Skip to content

Conversation

@bkj
Copy link

@bkj bkj commented Feb 14, 2023

This PR implemented the thread_idx "lock" I described on the call.

An example of the client-side code to support this functionality is

def filter_thread(msg):
    return (
        (msg.sender == own_power and msg.recipient == dst_power) or 
        (msg.sender == dst_power and msg.recipient == own_power)
    )

response = 0
while response == 0:
    # get thread (comms between me and dst_power)
    thread     = list(filter(filter_thread, game.messages.values()))

    # compute expected position in the thread
    thread_idx = len(thread)
    
    # generate a message based on the thread
    message    = create_message(thread)

    # try to send a message
    # - if the message is accepted, `response` is the timestamp it was it accepted
    # - if the message was bounced because `thread_idx` is incorrect, `response == 0`
    response = await game.send_game_message(dst_power, message, thread_idx=thread_idx) 
    
    if response == 0:
        await asyncio.sleep(1)   # wait a bit
        await game.synchronize() # update messages

E.g., if your thread_idx is wrong, it's because another message that you haven't seen yet was received by the server before your message. Thus, you may want to re-compute the message.

To ignore this functionality - and never have a message bounced - you can just do the normal:

await game.send_game_message(dst_power, message) 

To motivate the utility of this function - imagine PRP(A) and PRP(B) are mutually exclusive:

  • AUS sends PRP(A) and FRA sends PRP(B) at ~ the same time, without knowing about the other PRP.
  • Then, AUS sends YES(B) and FRA sends YES(A) at ~ the same time, without knowing about the other YES.
    What happens then? The negotiation is in a weird state. If this happened to two people, they might realize the conflict and pause to clarify ... but the bots might not be sophisticated to handle this situation at this point.

A small test shows these kinds of race conditions are actually pretty common -- in a single round of communication, this code catches three race conditions:

accepted server_type [1676054924290639/S1901M/TURKEY->ENGLAND/tid=0](PEACE(TURKEY ENGLAND))
accepted server_type [1676054924314901/S1901M/FRANCE->ENGLAND/tid=0](PEACE(FRANCE ENGLAND))
accepted server_type [1676054924322082/S1901M/TURKEY->RUSSIA/tid=0](PEACE(TURKEY RUSSIA))
accepted server_type [1676054924333371/S1901M/AUSTRIA->ITALY/tid=0](PEACE(AUSTRIA ITALY))
accepted server_type [1676054924335268/S1901M/ENGLAND->RUSSIA/tid=0](PEACE(ENGLAND RUSSIA))
* rejected server_type [1676054924337120/S1901M/RUSSIA->ENGLAND/tid=0](PEACE(RUSSIA ENGLAND))
accepted server_type [1676054924340226/S1901M/ITALY->ENGLAND/tid=0](PEACE(ITALY ENGLAND))
accepted server_type [1676054924342084/S1901M/GERMANY->FRANCE/tid=0](PEACE(GERMANY FRANCE))
accepted server_type [1676054924344416/S1901M/FRANCE->RUSSIA/tid=0](PEACE(FRANCE RUSSIA))
accepted server_type [1676054924362564/S1901M/TURKEY->ITALY/tid=0](PEACE(TURKEY ITALY))
* rejected server_type [1676054924368421/S1901M/ENGLAND->ITALY/tid=0](PEACE(ENGLAND ITALY))
accepted server_type [1676054924372534/S1901M/AUSTRIA->GERMANY/tid=0](PEACE(AUSTRIA GERMANY))
accepted server_type [1676054924382096/S1901M/ITALY->RUSSIA/tid=0](PEACE(ITALY RUSSIA))
* rejected server_type [1676054924384112/S1901M/GERMANY->AUSTRIA/tid=0](PEACE(GERMANY AUSTRIA))
accepted server_type [1676054924387729/S1901M/FRANCE->AUSTRIA/tid=0](PEACE(FRANCE AUSTRIA))
accepted server_type [1676054924392022/S1901M/FRANCE->TURKEY/tid=0](PEACE(FRANCE TURKEY))
accepted server_type [1676054924406874/S1901M/TURKEY->AUSTRIA/tid=0](PEACE(TURKEY AUSTRIA))
accepted server_type [1676054924420093/S1901M/AUSTRIA->ENGLAND/tid=0](PEACE(AUSTRIA ENGLAND))

if not self.has_power(recipient):
raise exceptions.MapPowerException(recipient)
return Message(phase=self.current_short_phase, sender=self.role, recipient=recipient, message=body)
return Message(phase=self.current_short_phase, sender=self.role, recipient=recipient, message=body, thread_idx=thread_idx)
Copy link

@mjspeck mjspeck Feb 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bkj could you add the thread_idx param to the docstring? Otherwise, the only explanation for it would be in this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants