Skip to content

Commit

Permalink
Merge pull request #60 from stanmart/no-zero-members
Browse files Browse the repository at this point in the history
Coalition members must receive positive payoffs
  • Loading branch information
miawlu authored Apr 27, 2024
2 parents 495f236 + 5677011 commit 99d3db0
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 9 deletions.
2 changes: 1 addition & 1 deletion _static/coalitions_demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ exampleOffers = [
{
'offer_id': 3,
'player': 1,
'members': [true, true, true],
'members': [true, true, false],
'allocations': [80, 20, 0],
},
{
Expand Down
16 changes: 13 additions & 3 deletions _static/live_bargaining.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,11 @@ openPopup = function (content, type) {
for (let i = 0; i < numPlayers; i++) {
isMemberCheckboxes[i].addEventListener('change', function () {
allocationTextBoxes[i].disabled = !isMemberCheckboxes[i].checked;
allocationTextBoxes[i].value = 0;
if (!isMemberCheckboxes[i].checked) {
allocationTextBoxes[i].value = 0;
} else {
allocationTextBoxes[i].value = 1;
}
updateTotalShareable();
updateTotalShared();
if (!allocationTextBoxes[i].disabled) {
Expand All @@ -56,12 +60,12 @@ for (let i = 0; i < numPlayers; i++) {
});

allocationTextBoxes[i].addEventListener('change', function () {
allocationTextBoxes[i].value = Math.floor(Math.max(0, allocationTextBoxes[i].value));
allocationTextBoxes[i].value = Math.floor(Math.max(1, allocationTextBoxes[i].value));
updateTotalShared();
});
allocationTextBoxes[i].addEventListener("keyup", function (event) {
if (event.key === "Enter") {
allocationTextBoxes[i].value = Math.floor(Math.max(0, allocationTextBoxes[i].value));
allocationTextBoxes[i].value = Math.floor(Math.max(1, allocationTextBoxes[i].value));
updateTotalShared();
}
});
Expand All @@ -80,6 +84,12 @@ function sendOffer() {
openPopup('Invalid proposal: total amount exceeds the budget available to this group', 'error');
return;
}
for (let i = 0; i < numPlayers; i++) {
if (isMemberCheckboxes[i].checked && allocationTextBoxes[i].value === '0') {
openPopup('Invalid proposal: all group members must receive a positive amount', 'error');
return;
}
}
members = isMemberCheckboxes.map(member => member.checked);
allocations = allocationTextBoxes.map(alloc => alloc.value);
liveSend({ 'type': 'propose', 'members': members, 'allocations': allocations })
Expand Down
16 changes: 13 additions & 3 deletions _static/proposal_demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ openPopup = function (content, type) {
for (let i = 0; i < numPlayers; i++) {
isMemberCheckboxes[i].addEventListener('change', function () {
allocationTextBoxes[i].disabled = !isMemberCheckboxes[i].checked;
allocationTextBoxes[i].value = 0;
if (!isMemberCheckboxes[i].checked) {
allocationTextBoxes[i].value = 0;
} else {
allocationTextBoxes[i].value = 1;
}
updateTotalShareable();
updateTotalShared();
if (!allocationTextBoxes[i].disabled) {
Expand All @@ -68,12 +72,12 @@ for (let i = 0; i < numPlayers; i++) {
});

allocationTextBoxes[i].addEventListener('change', function () {
allocationTextBoxes[i].value = Math.floor(Math.max(0, allocationTextBoxes[i].value));
allocationTextBoxes[i].value = Math.floor(Math.max(1, allocationTextBoxes[i].value));
updateTotalShared();
});
allocationTextBoxes[i].addEventListener("keyup", function (event) {
if (event.key === "Enter") {
allocationTextBoxes[i].value = Math.floor(Math.max(0, allocationTextBoxes[i].value));
allocationTextBoxes[i].value = Math.floor(Math.max(1, allocationTextBoxes[i].value));
updateTotalShared();
}
});
Expand Down Expand Up @@ -103,6 +107,12 @@ function sendOffer() {
openPopup('Invalid proposal: total amount exceeds the budget available to this group', 'error');
return;
}
for (let i = 0; i < numPlayers; i++) {
if (isMemberCheckboxes[i].checked && allocationTextBoxes[i].value === '0') {
openPopup('Invalid proposal: all group members must receive a positive amount', 'error');
return;
}
}

newPastOffers.push(newOffer);
updatePastOffers(newPastOffers);
Expand Down
2 changes: 1 addition & 1 deletion introduction/Coalitions.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ <h4> Group formation </h4>
Once the round ends, the final outcome and the payoffs of this round are determined as follows:
<span style="color: #b70505; font-weight: bold;">
Only if <u> all players in a proposed group </u> agree on the same proposal is that proposal successful.
Note, that <u>players who are not included in a proposal do not have to agree to it</u>.
Note, that <u>players who are not included in a proposal (marked as "—") do not have to agree to it</u>.
</span>
The group is then successfully formed and its members' payoffs are then determined by the agreed-upon proposal.
All other players get 0.
Expand Down
10 changes: 10 additions & 0 deletions live_bargaining/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ def check_proposal_validity(player: Player, members, allocations):
}
}

if any(
member and allocation == 0 for member, allocation in zip(members, allocations)
):
return {
player.id_in_group: {
"type": "error",
"content": "Invalid allocation: all members must receive a positive amount", # noqa: E501
}
}


def check_acceptance_validity(player: Player, offer_id):
if not isinstance(offer_id, int):
Expand Down
20 changes: 19 additions & 1 deletion live_bargaining/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def create_offers(method, Y):
{
"type": "propose",
"members": [True, True, True],
"allocations": [100, 0, 0],
"allocations": [90, 5, 5],
},
)

Expand Down Expand Up @@ -182,6 +182,24 @@ def test_invalid_input(method, Y, dummy_player, player_names):
{3: {"type": "error", "content": "Data is incomplete"}},
)

member_receives_zero = method(
1,
{
"type": "propose",
"members": [True, True, True],
"allocations": [100, 0, 0],
},
)
expect(
member_receives_zero,
{
1: {
"type": "error",
"content": "Invalid allocation: all members must receive a positive amount",
}
},
)


def call_live_method(method, **kwargs):
print(
Expand Down

0 comments on commit 99d3db0

Please sign in to comment.