apply clippy suggestions

This commit is contained in:
Ilion Beyst 2022-03-13 15:20:03 +01:00
parent f7655005ff
commit fd52e266c6
19 changed files with 157 additions and 62 deletions

View file

@ -0,0 +1 @@
SYNTAX IS OVER PARTY

View file

@ -0,0 +1,33 @@
import sys, json
def move(command):
""" print a command record to stdout """
moves = []
if command is not None:
moves.append(command)
print(json.dumps({ 'moves': moves }))
# flush the buffer, so that the gameserver can receive the json-encoded line.
sys.stdout.flush()
for line in sys.stdin:
state = json.loads(line)
# you are always player 1.
my_planets = [p for p in state['planets'] if p['owner'] == 1]
other_planets = [p for p in state['planets'] if p['owner'] != 1]
if not my_planets or not other_planets:
# we don't own any planets, so we can't make any moves.
move(None)
else:
# find my planet that has the most ships
planet = max(my_planets, key=lambda p: p['ship_count'])
# find enemy planet that has the least ships
destination = min(other_planets, key=lambda p: p['ship_count'])
# attack!
move({
'origin': planet['name'],
'destination': destination['name'],
'ship_count': planet['ship_count'] - 1
})

View file

@ -0,0 +1,56 @@
{"type":"stderr","player_id":2,"message":" File \"/workdir/bot.py\", line 1"}
{"type":"stderr","player_id":2,"message":" SYNTAX IS OVER PARTY"}
{"type":"stderr","player_id":2,"message":" ^^"}
{"type":"stderr","player_id":2,"message":"SyntaxError: invalid syntax"}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":7,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":0,"ship_count":5,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":8,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":0,"ship_count":5,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":1,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":9,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":0,"ship_count":5,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":1,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":2,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":10,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":0,"ship_count":5,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":1,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":2,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":3,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":11,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":0,"ship_count":5,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":1,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":2,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":3,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":4,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":1,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":12,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":5,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5},{"id":1,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":2,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":3,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":4,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":0,"x":-3.0,"y":5.0,"owner":null,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":13,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":5,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":6,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5},{"id":2,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":3,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":4,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":1,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":14,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":5,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":6,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":7,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":5},{"id":3,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":4,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":15,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":5,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":6,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":7,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":4},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":10},{"id":4,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":16,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":5,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":6,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":7,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":3},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":9},{"id":9,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":17,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":10},{"id":6,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":7,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":2},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":8},{"id":9,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":4}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":18,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":9},{"id":11,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":5},{"id":7,"ship_count":1,"origin":"protos","destination":"duteros","owner":1,"turns_remaining":1},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":7},{"id":9,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":3}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":19,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":8},{"id":11,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":4},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":10},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":6},{"id":9,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":2}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":20,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":7},{"id":11,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":3},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":9},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":5},{"id":9,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":1},{"id":13,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":4,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":21,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":6},{"id":11,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":2},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":8},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":4},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":10},{"id":13,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":4}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":4,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":22,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":5},{"id":11,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":1},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":7},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":3},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":9},{"id":13,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":3},{"id":15,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":0,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":23,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":4},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":10},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":6},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":2},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":8},{"id":13,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":2},{"id":15,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":4}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":0,"x":3.0,"y":5.0,"owner":null,"name":"tritos"},{"ship_count":24,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":3},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":9},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":5},{"id":8,"ship_count":1,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":1},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":7},{"id":13,"ship_count":4,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":1},{"id":15,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":3},{"id":17,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":25,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":2},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":8},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":4},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":10},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":6},{"id":17,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":4},{"id":15,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":2}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":26,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":10,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":1},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":7},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":3},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":9},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":5},{"id":17,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":3},{"id":15,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":1},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":7,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":27,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":11},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":6},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":2},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":8},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":4},{"id":17,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":2},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":5,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":28,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":10},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":5},{"id":12,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":1},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":7},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":3},{"id":17,"ship_count":2,"origin":"duteros","destination":"tritos","owner":1,"turns_remaining":1},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":7,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":29,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":9},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":4},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":10},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":6},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":2},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":8},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":6}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":30,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":8},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":3},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":9},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":5},{"id":14,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":1},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":31,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":7},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":2},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":8},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":4},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":11},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":5,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":32,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":6},{"id":16,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":1},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":3},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":10},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":33,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":5},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":10},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":2},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":9},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":34,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":4},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":9},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":18,"ship_count":2,"origin":"protos","destination":"tritos","owner":1,"turns_remaining":1},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":8},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":19,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":35,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":2,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":3},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":8},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":11},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":7},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":8},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":6}]}
{"type":"gamestate","planets":[{"ship_count":5,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":36,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":2,"x":3.0,"y":-5.0,"owner":null,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":2},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":10},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":6},{"id":21,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":3,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":37,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":4,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":20,"ship_count":3,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":1},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":9},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":5},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":10},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":4,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":38,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":8,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":9},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":22,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":8},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":4},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":9},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":23,"ship_count":6,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":7}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":39,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":12,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":8},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":32,"ship_count":7,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":5},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":7},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":3},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":8},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":2}]}
{"type":"gamestate","planets":[{"ship_count":5,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":40,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":2,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":7},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":32,"ship_count":7,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":4},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":6},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":2},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":7},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":25,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":33,"ship_count":11,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":5}]}
{"type":"gamestate","planets":[{"ship_count":6,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":41,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":7,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":6},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":32,"ship_count":7,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":3},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":5},{"id":24,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":1},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":6},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":11},{"id":33,"ship_count":11,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":4}]}
{"type":"gamestate","planets":[{"ship_count":7,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":3,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":42,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":5},{"id":26,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":32,"ship_count":7,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":2},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":4},{"id":35,"ship_count":6,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":5},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":5},{"id":27,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":10},{"id":33,"ship_count":11,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":3}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":7,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":4,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":43,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":15,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":null,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":4},{"id":36,"ship_count":6,"origin":"protos","destination":"extos","owner":1,"turns_remaining":5},{"id":32,"ship_count":7,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":1},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":3},{"id":35,"ship_count":6,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":4},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":4},{"id":33,"ship_count":11,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":2},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":8,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":44,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":2,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":1,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":3},{"id":36,"ship_count":6,"origin":"protos","destination":"extos","owner":1,"turns_remaining":4},{"id":37,"ship_count":14,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":5},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":2},{"id":35,"ship_count":6,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":3},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":3},{"id":33,"ship_count":11,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":1},{"id":29,"ship_count":4,"origin":"tritos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":45,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":7,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":13,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":2},{"id":36,"ship_count":6,"origin":"protos","destination":"extos","owner":1,"turns_remaining":3},{"id":37,"ship_count":14,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":4},{"id":28,"ship_count":4,"origin":"duteros","destination":"pemptos","owner":1,"turns_remaining":1},{"id":35,"ship_count":6,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":2},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":2},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":10},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":7}]}
{"type":"gamestate","planets":[{"ship_count":5,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":7,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":46,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":12,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":2,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":31,"ship_count":3,"origin":"duteros","destination":"extos","owner":1,"turns_remaining":1},{"id":36,"ship_count":6,"origin":"protos","destination":"extos","owner":1,"turns_remaining":2},{"id":37,"ship_count":14,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":3},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":10},{"id":35,"ship_count":6,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":1},{"id":30,"ship_count":4,"origin":"protos","destination":"pemptos","owner":1,"turns_remaining":1},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":9},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":6}]}
{"type":"gamestate","planets":[{"ship_count":6,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":8,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":47,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":12,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":40,"ship_count":11,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":36,"ship_count":6,"origin":"protos","destination":"extos","owner":1,"turns_remaining":1},{"id":37,"ship_count":14,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":2},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":9},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":5},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":7,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":9,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":48,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":7,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":8,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":40,"ship_count":11,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":10},{"id":37,"ship_count":14,"origin":"pemptos","destination":"extos","owner":1,"turns_remaining":1},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":8},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":4},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":7}]}
{"type":"gamestate","planets":[{"ship_count":8,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":49,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":8,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":23,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":40,"ship_count":11,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":9},{"id":42,"ship_count":8,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":7},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":3},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":6}]}
{"type":"gamestate","planets":[{"ship_count":9,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":7,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":3,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":50,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":9,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":2,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":40,"ship_count":11,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":8},{"id":42,"ship_count":8,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":6},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":2},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":5},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":10}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":8,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":4,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":51,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":10,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":3,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":40,"ship_count":11,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":1},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":7},{"id":42,"ship_count":8,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":34,"ship_count":5,"origin":"tritos","destination":"extos","owner":1,"turns_remaining":1},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":4},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":9},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":11}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":9,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":41,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":2,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":9,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":45,"ship_count":9,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":6},{"id":42,"ship_count":8,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":10},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":3},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":6,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":42,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":3,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":10,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":45,"ship_count":9,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":42,"ship_count":8,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":1},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":9},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":2},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":7},{"id":46,"ship_count":8,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":10}]}
{"type":"gamestate","planets":[{"ship_count":5,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":3,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":7,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":35,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":4,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":2,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":45,"ship_count":9,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":47,"ship_count":9,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":10},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":8},{"id":38,"ship_count":7,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":1},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":6},{"id":46,"ship_count":8,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":9}]}
{"type":"gamestate","planets":[{"ship_count":6,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":4,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":2,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":29,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":5,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":3,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":45,"ship_count":9,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":47,"ship_count":9,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":9},{"id":39,"ship_count":12,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":1},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":7},{"id":48,"ship_count":6,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":46,"ship_count":8,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":8}]}
{"type":"gamestate","planets":[{"ship_count":2,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":5,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":3,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":18,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":6,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":4,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":45,"ship_count":9,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":1},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":47,"ship_count":9,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":8},{"id":49,"ship_count":5,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":11},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":6},{"id":48,"ship_count":6,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":46,"ship_count":8,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":7}]}
{"type":"gamestate","planets":[{"ship_count":3,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":6,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":4,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":10,"x":6.0,"y":0.0,"owner":2,"name":"tetartos"},{"ship_count":2,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":5,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":50,"ship_count":5,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":41,"ship_count":11,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":1},{"id":47,"ship_count":9,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":7},{"id":49,"ship_count":5,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":10},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":5},{"id":48,"ship_count":6,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":3},{"id":46,"ship_count":8,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":6}]}
{"type":"gamestate","planets":[{"ship_count":4,"x":-6.0,"y":0.0,"owner":1,"name":"protos"},{"ship_count":2,"x":-3.0,"y":5.0,"owner":1,"name":"duteros"},{"ship_count":5,"x":3.0,"y":5.0,"owner":1,"name":"tritos"},{"ship_count":0,"x":6.0,"y":0.0,"owner":null,"name":"tetartos"},{"ship_count":3,"x":3.0,"y":-5.0,"owner":1,"name":"pemptos"},{"ship_count":6,"x":-3.0,"y":-5.0,"owner":1,"name":"extos"}],"expeditions":[{"id":50,"ship_count":5,"origin":"pemptos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":51,"ship_count":5,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":10},{"id":47,"ship_count":9,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":6},{"id":49,"ship_count":5,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":9},{"id":44,"ship_count":8,"origin":"protos","destination":"tetartos","owner":1,"turns_remaining":4},{"id":48,"ship_count":6,"origin":"tritos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":43,"ship_count":22,"origin":"extos","destination":"tetartos","owner":1,"turns_remaining":2},{"id":46,"ship_count":8,"origin":"duteros","destination":"tetartos","owner":1,"turns_remaining":5}]}

View file

@ -10,16 +10,9 @@ async fn main() {
_run_match(map_path).await; _run_match(map_path).await;
} }
const IMAGE: &'static str = "python:3.10-slim-buster"; const IMAGE: &str = "python:3.10-slim-buster";
async fn _run_match(map_path: String) { async fn _run_match(map_path: String) {
let code_dir_path = PathBuf::from("../simplebot");
let bot_spec = DockerBotSpec {
image: IMAGE.to_string(),
code_path: code_dir_path,
argv: vec!["python".to_string(), "simplebot.py".to_string()],
};
run_match(MatchConfig { run_match(MatchConfig {
map_path: PathBuf::from(map_path), map_path: PathBuf::from(map_path),
map_name: "hex".to_string(), map_name: "hex".to_string(),
@ -27,13 +20,25 @@ async fn _run_match(map_path: String) {
players: vec![ players: vec![
MatchPlayer { MatchPlayer {
name: "a".to_string(), name: "a".to_string(),
bot_spec: Box::new(bot_spec.clone()), bot_spec: Box::new(DockerBotSpec {
image: IMAGE.to_string(),
// code_path: PathBuf::from("../simplebot"),
code_path: PathBuf::from("./bots/simplebot"),
argv: vec!["python".to_string(), "simplebot.py".to_string()],
}),
}, },
MatchPlayer { MatchPlayer {
name: "b".to_string(), name: "b".to_string(),
bot_spec: Box::new(bot_spec.clone()), bot_spec: Box::new(DockerBotSpec {
image: IMAGE.to_string(),
code_path: PathBuf::from("./bots/broken_bot"),
argv: vec!["python".to_string(), "bot.py".to_string()],
}),
}, },
], ],
}) })
.await; .await;
// TODO: use a joinhandle to wait for the logger to finish
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
} }

View file

@ -35,7 +35,7 @@ pub fn run_local_bot(player_id: u32, event_bus: Arc<Mutex<EventBus>>, bot: Bot)
}; };
tokio::spawn(runner.run()); tokio::spawn(runner.run());
return LocalBotHandle { tx }; LocalBotHandle { tx }
} }
pub struct LocalBotRunner { pub struct LocalBotRunner {
@ -90,11 +90,11 @@ impl Bot {
let stdout = child.stdout.take().unwrap(); let stdout = child.stdout.take().unwrap();
let reader = BufReader::new(stdout).lines(); let reader = BufReader::new(stdout).lines();
return BotProcess { BotProcess {
stdin: child.stdin.take().unwrap(), stdin: child.stdin.take().unwrap(),
stdout: reader, stdout: reader,
child, child,
}; }
} }
} }

View file

@ -72,7 +72,7 @@ pub async fn run_match(config: MatchConfig) {
start_bot( start_bot(
player_id, player_id,
event_bus.clone(), event_bus.clone(),
&player.bot_spec, player.bot_spec.as_ref(),
match_logger.clone(), match_logger.clone(),
) )
}) })
@ -111,7 +111,7 @@ pub async fn run_match(config: MatchConfig) {
async fn start_bot( async fn start_bot(
player_id: u32, player_id: u32,
event_bus: Arc<Mutex<EventBus>>, event_bus: Arc<Mutex<EventBus>>,
bot_spec: &Box<dyn BotSpec>, bot_spec: &dyn BotSpec,
match_logger: MatchLogger, match_logger: MatchLogger,
) -> (u32, Box<dyn PlayerHandle>) { ) -> (u32, Box<dyn PlayerHandle>) {
let player_handle = bot_spec.run_bot(player_id, event_bus, match_logger).await; let player_handle = bot_spec.run_bot(player_id, event_bus, match_logger).await;

View file

@ -57,11 +57,11 @@ impl MatchCtx {
timeout, timeout,
}); });
return Request { Request {
player_id, player_id,
request_id, request_id,
event_bus: self.event_bus.clone(), event_bus: self.event_bus.clone(),
}; }
} }
pub fn players(&self) -> Vec<u32> { pub fn players(&self) -> Vec<u32> {
@ -97,6 +97,12 @@ impl EventBus {
} }
} }
impl Default for EventBus {
fn default() -> Self {
EventBus::new()
}
}
impl EventBus { impl EventBus {
pub fn resolve_request(&mut self, id: RequestId, result: RequestResult<Vec<u8>>) { pub fn resolve_request(&mut self, id: RequestId, result: RequestResult<Vec<u8>>) {
if self.request_responses.contains_key(&id) { if self.request_responses.contains_key(&id) {
@ -138,9 +144,9 @@ impl Future for Request {
event_bus event_bus
.wakers .wakers
.entry(request_id) .entry(request_id)
.or_insert_with(|| AtomicWaker::new()) .or_insert_with(AtomicWaker::new)
.register(cx.waker()); .register(cx.waker());
return Poll::Pending; Poll::Pending
} }
} }

View file

@ -29,7 +29,7 @@ pub async fn create_log_sink(log_file_path: &Path) -> MatchLogger {
.await .await
.expect("Could not create log file"); .expect("Could not create log file");
tokio::spawn(run_log_sink(rx, log_file)); tokio::spawn(run_log_sink(rx, log_file));
return tx; tx
} }
async fn run_log_sink(mut rx: mpsc::UnboundedReceiver<MatchLogMessage>, mut file: File) { async fn run_log_sink(mut rx: mpsc::UnboundedReceiver<MatchLogMessage>, mut file: File) {

View file

@ -74,7 +74,7 @@ impl PwMatch {
.iter() .iter()
.filter(|p| p.alive) .filter(|p| p.alive)
.map(move |player| { .map(move |player| {
let state_for_player = pw_serializer::serialize_rotated(&state, player.id - 1); let state_for_player = pw_serializer::serialize_rotated(state, player.id - 1);
match_ctx match_ctx
.request( .request(
player.id.try_into().unwrap(), player.id.try_into().unwrap(),
@ -115,7 +115,7 @@ impl PwMatch {
}) })
.collect(); .collect();
return proto::PlayerAction::Commands(commands); proto::PlayerAction::Commands(commands)
} }
} }

View file

@ -25,8 +25,8 @@ impl Config {
.collect(); .collect();
PwState { PwState {
players: players, players,
planets: planets, planets,
expeditions: Vec::new(), expeditions: Vec::new(),
expedition_num: 0, expedition_num: 0,
turn_num: 0, turn_num: 0,
@ -37,8 +37,7 @@ impl Config {
fn load_map(&self, num_players: usize) -> Vec<Planet> { fn load_map(&self, num_players: usize) -> Vec<Planet> {
let map = self.read_map().expect("[PLANET_WARS] reading map failed"); let map = self.read_map().expect("[PLANET_WARS] reading map failed");
return map map.planets
.planets
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(num, planet)| { .map(|(num, planet)| {
@ -55,27 +54,26 @@ impl Config {
}); });
if planet.ship_count > 0 { if planet.ship_count > 0 {
fleets.push(Fleet { fleets.push(Fleet {
owner: owner, owner,
ship_count: planet.ship_count, ship_count: planet.ship_count,
}); });
} }
return Planet { Planet {
id: num, id: num,
name: planet.name, name: planet.name,
x: planet.x, x: planet.x,
y: planet.y, y: planet.y,
fleets: fleets, fleets,
}; }
}) })
.collect(); .collect()
} }
fn read_map(&self) -> io::Result<Map> { fn read_map(&self) -> io::Result<Map> {
let mut file = File::open(&self.map_file)?; let mut file = File::open(&self.map_file)?;
let mut buf = String::new(); let mut buf = String::new();
file.read_to_string(&mut buf)?; file.read_to_string(&mut buf)?;
let map = serde_json::from_str(&buf)?; Ok(serde_json::from_str(&buf)?)
return Ok(map);
} }
} }

View file

@ -50,7 +50,7 @@ impl PlanetWars {
serializer::serialize_rotated(&self.state, player_id - 1) serializer::serialize_rotated(&self.state, player_id - 1)
} }
pub fn state<'a>(&'a self) -> &'a PwState { pub fn state(&self) -> &PwState {
&self.state &self.state
} }
@ -62,7 +62,7 @@ impl PlanetWars {
) -> Result<(), CommandError> { ) -> Result<(), CommandError> {
let dispatch = self.parse_command(player_num, cmd)?; let dispatch = self.parse_command(player_num, cmd)?;
self.state.dispatch(&dispatch); self.state.dispatch(&dispatch);
return Ok(()); Ok(())
} }
/// Check the given command for validity. /// Check the given command for validity.

View file

@ -128,7 +128,7 @@ impl PwState {
pub fn is_finished(&self) -> bool { pub fn is_finished(&self) -> bool {
let remaining = self.players.iter().filter(|p| p.alive).count(); let remaining = self.players.iter().filter(|p| p.alive).count();
return remaining < 2 || self.turn_num >= self.max_turns; remaining < 2 || self.turn_num >= self.max_turns
} }
pub fn living_players(&self) -> Vec<usize> { pub fn living_players(&self) -> Vec<usize> {
@ -187,6 +187,6 @@ impl Planet {
fn distance(&self, other: &Planet) -> u64 { fn distance(&self, other: &Planet) -> u64 {
let dx = self.x - other.x; let dx = self.x - other.x;
let dy = self.y - other.y; let dy = self.y - other.y;
return (dx.powi(2) + dy.powi(2)).sqrt().ceil() as u64; (dx.powi(2) + dy.powi(2)).sqrt().ceil() as u64
} }
} }

View file

@ -20,7 +20,7 @@ struct Serializer<'a> {
impl<'a> Serializer<'a> { impl<'a> Serializer<'a> {
fn new(state: &'a PwState, offset: usize) -> Self { fn new(state: &'a PwState, offset: usize) -> Self {
Serializer { Serializer {
state: state, state,
player_num_offset: offset, player_num_offset: offset,
} }
} }
@ -49,7 +49,7 @@ impl<'a> Serializer<'a> {
let num_players = self.state.players.len(); let num_players = self.state.players.len();
let rotated_id = (player_id + num_players - self.player_num_offset) % num_players; let rotated_id = (player_id + num_players - self.player_num_offset) % num_players;
// protocol player ids start at 1 // protocol player ids start at 1
return rotated_id + 1; rotated_id + 1
} }
fn serialize_planet(&self, planet: &Planet) -> proto::Planet { fn serialize_planet(&self, planet: &Planet) -> proto::Planet {

View file

@ -24,12 +24,11 @@ pub fn create_session(user: &User, conn: &PgConnection) -> Session {
token: gen_session_token(), token: gen_session_token(),
user_id: user.id, user_id: user.id,
}; };
let session = insert_into(sessions::table)
insert_into(sessions::table)
.values(&new_session) .values(&new_session)
.get_result::<Session>(conn) .get_result::<Session>(conn)
.unwrap(); .unwrap()
return session;
} }
pub fn find_user_by_session(token: &str, conn: &PgConnection) -> QueryResult<(Session, User)> { pub fn find_user_by_session(token: &str, conn: &PgConnection) -> QueryResult<(Session, User)> {
@ -42,5 +41,5 @@ pub fn find_user_by_session(token: &str, conn: &PgConnection) -> QueryResult<(Se
pub fn gen_session_token() -> String { pub fn gen_session_token() -> String {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let token: [u8; 32] = rng.gen(); let token: [u8; 32] = rng.gen();
return base64::encode(&token); base64::encode(&token)
} }

View file

@ -48,7 +48,7 @@ pub fn create_user(credentials: &Credentials, conn: &PgConnection) -> QueryResul
let salt: [u8; 32] = rand::thread_rng().gen(); let salt: [u8; 32] = rand::thread_rng().gen();
let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap(); let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap();
let new_user = NewUser { let new_user = NewUser {
username: &credentials.username, username: credentials.username,
password_salt: &salt, password_salt: &salt,
password_hash: &hash, password_hash: &hash,
}; };
@ -73,9 +73,9 @@ pub fn authenticate_user(credentials: &Credentials, db_conn: &PgConnection) -> O
.unwrap(); .unwrap();
if password_matches { if password_matches {
return Some(user); Some(user)
} else { } else {
return None; None
} }
}) })
} }
@ -91,15 +91,15 @@ fn test_argon() {
let salt: [u8; 32] = rand::thread_rng().gen(); let salt: [u8; 32] = rand::thread_rng().gen();
let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap(); let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap();
let new_user = NewUser { let new_user = NewUser {
username: &credentials.username, username: credentials.username,
password_hash: &hash, password_hash: &hash,
password_salt: &salt, password_salt: &salt,
}; };
let password_matches = argon2::verify_raw( let password_matches = argon2::verify_raw(
credentials.password.as_bytes(), credentials.password.as_bytes(),
&new_user.password_salt, new_user.password_salt,
&new_user.password_hash, new_user.password_hash,
&argon2_config(), &argon2_config(),
) )
.unwrap(); .unwrap();

View file

@ -10,7 +10,6 @@ pub mod util;
use std::ops::Deref; use std::ops::Deref;
use axum;
use bb8::{Pool, PooledConnection}; use bb8::{Pool, PooledConnection};
use bb8_diesel::{self, DieselConnectionManager}; use bb8_diesel::{self, DieselConnectionManager};
use diesel::{Connection, PgConnection}; use diesel::{Connection, PgConnection};
@ -60,13 +59,13 @@ pub async fn prepare_db(database_url: &str) -> Pool<DieselConnectionManager<PgCo
let manager = DieselConnectionManager::<PgConnection>::new(database_url); let manager = DieselConnectionManager::<PgConnection>::new(database_url);
let pool = bb8::Pool::builder().build(manager).await.unwrap(); let pool = bb8::Pool::builder().build(manager).await.unwrap();
seed_simplebot(&pool).await; seed_simplebot(&pool).await;
return pool; pool
} }
pub async fn api(configuration: Configuration) -> Router { pub async fn api(configuration: Configuration) -> Router {
let db_pool = prepare_db(&configuration.database_url).await; let db_pool = prepare_db(&configuration.database_url).await;
let api = Router::new() Router::new()
.route("/register", post(routes::users::register)) .route("/register", post(routes::users::register))
.route("/login", post(routes::users::login)) .route("/login", post(routes::users::login))
.route("/users/me", get(routes::users::current_user)) .route("/users/me", get(routes::users::current_user))
@ -91,8 +90,7 @@ pub async fn api(configuration: Configuration) -> Router {
) )
.route("/submit_bot", post(routes::demo::submit_bot)) .route("/submit_bot", post(routes::demo::submit_bot))
.route("/save_bot", post(routes::bots::save_bot)) .route("/save_bot", post(routes::bots::save_bot))
.layer(AddExtensionLayer::new(db_pool)); .layer(AddExtensionLayer::new(db_pool))
api
} }
pub async fn app() -> Router { pub async fn app() -> Router {

View file

@ -59,8 +59,8 @@ pub async fn save_bot(
owner_id: None, owner_id: None,
name: &params.bot_name, name: &params.bot_name,
}; };
let bot = bots::create_bot(&new_bot, &conn).expect("could not create bot");
bot bots::create_bot(&new_bot, &conn).expect("could not create bot")
} }
}; };
let _code_bundle = let _code_bundle =

View file

@ -13,8 +13,8 @@ use std::path::PathBuf;
use super::matches::ApiMatch; use super::matches::ApiMatch;
const PYTHON_IMAGE: &'static str = "python:3.10-slim-buster"; const PYTHON_IMAGE: &str = "python:3.10-slim-buster";
const OPPONENT_NAME: &'static str = "simplebot"; const OPPONENT_NAME: &str = "simplebot";
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SubmitBotParams { pub struct SubmitBotParams {

View file

@ -57,8 +57,7 @@ pub async fn play_match(
code_path: PathBuf::from(BOTS_DIR).join(code_bundle.path), code_path: PathBuf::from(BOTS_DIR).join(code_bundle.path),
image: "python:3.10-slim-buster".to_string(), image: "python:3.10-slim-buster".to_string(),
argv: shlex::split(&bot_config.run_command) argv: shlex::split(&bot_config.run_command)
// TODO: this is an user error, should ideally be handled before we get here .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?,
.ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR)?,
}), }),
}); });
@ -152,7 +151,7 @@ pub async fn get_match_data(
) -> Result<Json<ApiMatch>, StatusCode> { ) -> Result<Json<ApiMatch>, StatusCode> {
let match_data = matches::find_match(match_id, &conn) let match_data = matches::find_match(match_id, &conn)
.map_err(|_| StatusCode::NOT_FOUND) .map_err(|_| StatusCode::NOT_FOUND)
.map(|data| match_data_to_api(data))?; .map(match_data_to_api)?;
Ok(Json(match_data)) Ok(Json(match_data))
} }