From fd52e266c6e25999a49c36f17342977b759a2612 Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Sun, 13 Mar 2022 15:20:03 +0100 Subject: [PATCH] apply clippy suggestions --- planetwars-matchrunner/bots/broken_bot/bot.py | 1 + .../bots/simplebot/simplebot.py | 33 +++++++++++ planetwars-matchrunner/match.log | 56 +++++++++++++++++++ planetwars-matchrunner/src/bin/testmatch.rs | 25 +++++---- planetwars-matchrunner/src/bot_runner.rs | 6 +- planetwars-matchrunner/src/lib.rs | 4 +- planetwars-matchrunner/src/match_context.rs | 14 +++-- planetwars-matchrunner/src/match_log.rs | 2 +- planetwars-matchrunner/src/pw_match.rs | 4 +- planetwars-rules/src/config.rs | 20 +++---- planetwars-rules/src/lib.rs | 4 +- planetwars-rules/src/rules.rs | 4 +- planetwars-rules/src/serializer.rs | 4 +- planetwars-server/src/db/sessions.rs | 9 ++- planetwars-server/src/db/users.rs | 12 ++-- planetwars-server/src/lib.rs | 8 +-- planetwars-server/src/routes/bots.rs | 4 +- planetwars-server/src/routes/demo.rs | 4 +- planetwars-server/src/routes/matches.rs | 5 +- 19 files changed, 157 insertions(+), 62 deletions(-) create mode 100644 planetwars-matchrunner/bots/broken_bot/bot.py create mode 100644 planetwars-matchrunner/bots/simplebot/simplebot.py create mode 100644 planetwars-matchrunner/match.log diff --git a/planetwars-matchrunner/bots/broken_bot/bot.py b/planetwars-matchrunner/bots/broken_bot/bot.py new file mode 100644 index 0000000..e4af2dd --- /dev/null +++ b/planetwars-matchrunner/bots/broken_bot/bot.py @@ -0,0 +1 @@ +SYNTAX IS OVER PARTY \ No newline at end of file diff --git a/planetwars-matchrunner/bots/simplebot/simplebot.py b/planetwars-matchrunner/bots/simplebot/simplebot.py new file mode 100644 index 0000000..b2a6b8f --- /dev/null +++ b/planetwars-matchrunner/bots/simplebot/simplebot.py @@ -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 + }) diff --git a/planetwars-matchrunner/match.log b/planetwars-matchrunner/match.log new file mode 100644 index 0000000..59d55dc --- /dev/null +++ b/planetwars-matchrunner/match.log @@ -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}]} diff --git a/planetwars-matchrunner/src/bin/testmatch.rs b/planetwars-matchrunner/src/bin/testmatch.rs index db160cf..4a9d10e 100644 --- a/planetwars-matchrunner/src/bin/testmatch.rs +++ b/planetwars-matchrunner/src/bin/testmatch.rs @@ -10,16 +10,9 @@ async fn main() { _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) { - 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 { map_path: PathBuf::from(map_path), map_name: "hex".to_string(), @@ -27,13 +20,25 @@ async fn _run_match(map_path: String) { players: vec![ MatchPlayer { 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 { 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; + + // TODO: use a joinhandle to wait for the logger to finish + tokio::time::sleep(std::time::Duration::from_secs(1)).await; } diff --git a/planetwars-matchrunner/src/bot_runner.rs b/planetwars-matchrunner/src/bot_runner.rs index adb5907..d40a133 100644 --- a/planetwars-matchrunner/src/bot_runner.rs +++ b/planetwars-matchrunner/src/bot_runner.rs @@ -35,7 +35,7 @@ pub fn run_local_bot(player_id: u32, event_bus: Arc>, bot: Bot) }; tokio::spawn(runner.run()); - return LocalBotHandle { tx }; + LocalBotHandle { tx } } pub struct LocalBotRunner { @@ -90,11 +90,11 @@ impl Bot { let stdout = child.stdout.take().unwrap(); let reader = BufReader::new(stdout).lines(); - return BotProcess { + BotProcess { stdin: child.stdin.take().unwrap(), stdout: reader, child, - }; + } } } diff --git a/planetwars-matchrunner/src/lib.rs b/planetwars-matchrunner/src/lib.rs index 0be0b3d..b7a9e53 100644 --- a/planetwars-matchrunner/src/lib.rs +++ b/planetwars-matchrunner/src/lib.rs @@ -72,7 +72,7 @@ pub async fn run_match(config: MatchConfig) { start_bot( player_id, event_bus.clone(), - &player.bot_spec, + player.bot_spec.as_ref(), match_logger.clone(), ) }) @@ -111,7 +111,7 @@ pub async fn run_match(config: MatchConfig) { async fn start_bot( player_id: u32, event_bus: Arc>, - bot_spec: &Box, + bot_spec: &dyn BotSpec, match_logger: MatchLogger, ) -> (u32, Box) { let player_handle = bot_spec.run_bot(player_id, event_bus, match_logger).await; diff --git a/planetwars-matchrunner/src/match_context.rs b/planetwars-matchrunner/src/match_context.rs index 6ea60c3..1dac09b 100644 --- a/planetwars-matchrunner/src/match_context.rs +++ b/planetwars-matchrunner/src/match_context.rs @@ -57,11 +57,11 @@ impl MatchCtx { timeout, }); - return Request { + Request { player_id, request_id, event_bus: self.event_bus.clone(), - }; + } } pub fn players(&self) -> Vec { @@ -97,6 +97,12 @@ impl EventBus { } } +impl Default for EventBus { + fn default() -> Self { + EventBus::new() + } +} + impl EventBus { pub fn resolve_request(&mut self, id: RequestId, result: RequestResult>) { if self.request_responses.contains_key(&id) { @@ -138,9 +144,9 @@ impl Future for Request { event_bus .wakers .entry(request_id) - .or_insert_with(|| AtomicWaker::new()) + .or_insert_with(AtomicWaker::new) .register(cx.waker()); - return Poll::Pending; + Poll::Pending } } diff --git a/planetwars-matchrunner/src/match_log.rs b/planetwars-matchrunner/src/match_log.rs index 9991f99..30751fd 100644 --- a/planetwars-matchrunner/src/match_log.rs +++ b/planetwars-matchrunner/src/match_log.rs @@ -29,7 +29,7 @@ pub async fn create_log_sink(log_file_path: &Path) -> MatchLogger { .await .expect("Could not create log file"); tokio::spawn(run_log_sink(rx, log_file)); - return tx; + tx } async fn run_log_sink(mut rx: mpsc::UnboundedReceiver, mut file: File) { diff --git a/planetwars-matchrunner/src/pw_match.rs b/planetwars-matchrunner/src/pw_match.rs index c114d78..c9a7f7b 100644 --- a/planetwars-matchrunner/src/pw_match.rs +++ b/planetwars-matchrunner/src/pw_match.rs @@ -74,7 +74,7 @@ impl PwMatch { .iter() .filter(|p| p.alive) .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 .request( player.id.try_into().unwrap(), @@ -115,7 +115,7 @@ impl PwMatch { }) .collect(); - return proto::PlayerAction::Commands(commands); + proto::PlayerAction::Commands(commands) } } diff --git a/planetwars-rules/src/config.rs b/planetwars-rules/src/config.rs index 57c77eb..14a4ac2 100644 --- a/planetwars-rules/src/config.rs +++ b/planetwars-rules/src/config.rs @@ -25,8 +25,8 @@ impl Config { .collect(); PwState { - players: players, - planets: planets, + players, + planets, expeditions: Vec::new(), expedition_num: 0, turn_num: 0, @@ -37,8 +37,7 @@ impl Config { fn load_map(&self, num_players: usize) -> Vec { let map = self.read_map().expect("[PLANET_WARS] reading map failed"); - return map - .planets + map.planets .into_iter() .enumerate() .map(|(num, planet)| { @@ -55,27 +54,26 @@ impl Config { }); if planet.ship_count > 0 { fleets.push(Fleet { - owner: owner, + owner, ship_count: planet.ship_count, }); } - return Planet { + Planet { id: num, name: planet.name, x: planet.x, y: planet.y, - fleets: fleets, - }; + fleets, + } }) - .collect(); + .collect() } fn read_map(&self) -> io::Result { let mut file = File::open(&self.map_file)?; let mut buf = String::new(); file.read_to_string(&mut buf)?; - let map = serde_json::from_str(&buf)?; - return Ok(map); + Ok(serde_json::from_str(&buf)?) } } diff --git a/planetwars-rules/src/lib.rs b/planetwars-rules/src/lib.rs index 48034ee..26382f1 100644 --- a/planetwars-rules/src/lib.rs +++ b/planetwars-rules/src/lib.rs @@ -50,7 +50,7 @@ impl PlanetWars { serializer::serialize_rotated(&self.state, player_id - 1) } - pub fn state<'a>(&'a self) -> &'a PwState { + pub fn state(&self) -> &PwState { &self.state } @@ -62,7 +62,7 @@ impl PlanetWars { ) -> Result<(), CommandError> { let dispatch = self.parse_command(player_num, cmd)?; self.state.dispatch(&dispatch); - return Ok(()); + Ok(()) } /// Check the given command for validity. diff --git a/planetwars-rules/src/rules.rs b/planetwars-rules/src/rules.rs index 587098f..e339b4e 100644 --- a/planetwars-rules/src/rules.rs +++ b/planetwars-rules/src/rules.rs @@ -128,7 +128,7 @@ impl PwState { pub fn is_finished(&self) -> bool { 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 { @@ -187,6 +187,6 @@ impl Planet { fn distance(&self, other: &Planet) -> u64 { let dx = self.x - other.x; 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 } } diff --git a/planetwars-rules/src/serializer.rs b/planetwars-rules/src/serializer.rs index 7eb2e01..22ba52e 100644 --- a/planetwars-rules/src/serializer.rs +++ b/planetwars-rules/src/serializer.rs @@ -20,7 +20,7 @@ struct Serializer<'a> { impl<'a> Serializer<'a> { fn new(state: &'a PwState, offset: usize) -> Self { Serializer { - state: state, + state, player_num_offset: offset, } } @@ -49,7 +49,7 @@ impl<'a> Serializer<'a> { let num_players = self.state.players.len(); let rotated_id = (player_id + num_players - self.player_num_offset) % num_players; // protocol player ids start at 1 - return rotated_id + 1; + rotated_id + 1 } fn serialize_planet(&self, planet: &Planet) -> proto::Planet { diff --git a/planetwars-server/src/db/sessions.rs b/planetwars-server/src/db/sessions.rs index 96f3926..a91d954 100644 --- a/planetwars-server/src/db/sessions.rs +++ b/planetwars-server/src/db/sessions.rs @@ -24,12 +24,11 @@ pub fn create_session(user: &User, conn: &PgConnection) -> Session { token: gen_session_token(), user_id: user.id, }; - let session = insert_into(sessions::table) + + insert_into(sessions::table) .values(&new_session) .get_result::(conn) - .unwrap(); - - return session; + .unwrap() } 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 { let mut rng = rand::thread_rng(); let token: [u8; 32] = rng.gen(); - return base64::encode(&token); + base64::encode(&token) } diff --git a/planetwars-server/src/db/users.rs b/planetwars-server/src/db/users.rs index a97ade5..3c071de 100644 --- a/planetwars-server/src/db/users.rs +++ b/planetwars-server/src/db/users.rs @@ -48,7 +48,7 @@ pub fn create_user(credentials: &Credentials, conn: &PgConnection) -> QueryResul let salt: [u8; 32] = rand::thread_rng().gen(); let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap(); let new_user = NewUser { - username: &credentials.username, + username: credentials.username, password_salt: &salt, password_hash: &hash, }; @@ -73,9 +73,9 @@ pub fn authenticate_user(credentials: &Credentials, db_conn: &PgConnection) -> O .unwrap(); if password_matches { - return Some(user); + Some(user) } else { - return None; + None } }) } @@ -91,15 +91,15 @@ fn test_argon() { let salt: [u8; 32] = rand::thread_rng().gen(); let hash = argon2::hash_raw(credentials.password.as_bytes(), &salt, &argon_config).unwrap(); let new_user = NewUser { - username: &credentials.username, + username: credentials.username, password_hash: &hash, password_salt: &salt, }; let password_matches = argon2::verify_raw( credentials.password.as_bytes(), - &new_user.password_salt, - &new_user.password_hash, + new_user.password_salt, + new_user.password_hash, &argon2_config(), ) .unwrap(); diff --git a/planetwars-server/src/lib.rs b/planetwars-server/src/lib.rs index 6cc2824..51d6613 100644 --- a/planetwars-server/src/lib.rs +++ b/planetwars-server/src/lib.rs @@ -10,7 +10,6 @@ pub mod util; use std::ops::Deref; -use axum; use bb8::{Pool, PooledConnection}; use bb8_diesel::{self, DieselConnectionManager}; use diesel::{Connection, PgConnection}; @@ -60,13 +59,13 @@ pub async fn prepare_db(database_url: &str) -> Pool::new(database_url); let pool = bb8::Pool::builder().build(manager).await.unwrap(); seed_simplebot(&pool).await; - return pool; + pool } pub async fn api(configuration: Configuration) -> Router { let db_pool = prepare_db(&configuration.database_url).await; - let api = Router::new() + Router::new() .route("/register", post(routes::users::register)) .route("/login", post(routes::users::login)) .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("/save_bot", post(routes::bots::save_bot)) - .layer(AddExtensionLayer::new(db_pool)); - api + .layer(AddExtensionLayer::new(db_pool)) } pub async fn app() -> Router { diff --git a/planetwars-server/src/routes/bots.rs b/planetwars-server/src/routes/bots.rs index c9bf8ce..f7f99cb 100644 --- a/planetwars-server/src/routes/bots.rs +++ b/planetwars-server/src/routes/bots.rs @@ -59,8 +59,8 @@ pub async fn save_bot( owner_id: None, name: ¶ms.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 = diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs index 749c0ca..eb7f61f 100644 --- a/planetwars-server/src/routes/demo.rs +++ b/planetwars-server/src/routes/demo.rs @@ -13,8 +13,8 @@ use std::path::PathBuf; use super::matches::ApiMatch; -const PYTHON_IMAGE: &'static str = "python:3.10-slim-buster"; -const OPPONENT_NAME: &'static str = "simplebot"; +const PYTHON_IMAGE: &str = "python:3.10-slim-buster"; +const OPPONENT_NAME: &str = "simplebot"; #[derive(Serialize, Deserialize, Debug)] pub struct SubmitBotParams { diff --git a/planetwars-server/src/routes/matches.rs b/planetwars-server/src/routes/matches.rs index 9fa532e..991a4b5 100644 --- a/planetwars-server/src/routes/matches.rs +++ b/planetwars-server/src/routes/matches.rs @@ -57,8 +57,7 @@ pub async fn play_match( code_path: PathBuf::from(BOTS_DIR).join(code_bundle.path), image: "python:3.10-slim-buster".to_string(), argv: shlex::split(&bot_config.run_command) - // TODO: this is an user error, should ideally be handled before we get here - .ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR)?, + .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?, }), }); @@ -152,7 +151,7 @@ pub async fn get_match_data( ) -> Result, StatusCode> { let match_data = matches::find_match(match_id, &conn) .map_err(|_| StatusCode::NOT_FOUND) - .map(|data| match_data_to_api(data))?; + .map(match_data_to_api)?; Ok(Json(match_data)) }