aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--planetwars-matchrunner/bots/broken_bot/bot.py1
-rw-r--r--planetwars-matchrunner/bots/simplebot/simplebot.py33
-rw-r--r--planetwars-matchrunner/match.log56
-rw-r--r--planetwars-matchrunner/src/bin/testmatch.rs25
-rw-r--r--planetwars-matchrunner/src/bot_runner.rs6
-rw-r--r--planetwars-matchrunner/src/lib.rs4
-rw-r--r--planetwars-matchrunner/src/match_context.rs14
-rw-r--r--planetwars-matchrunner/src/match_log.rs2
-rw-r--r--planetwars-matchrunner/src/pw_match.rs4
-rw-r--r--planetwars-rules/src/config.rs20
-rw-r--r--planetwars-rules/src/lib.rs4
-rw-r--r--planetwars-rules/src/rules.rs4
-rw-r--r--planetwars-rules/src/serializer.rs4
-rw-r--r--planetwars-server/src/db/sessions.rs9
-rw-r--r--planetwars-server/src/db/users.rs12
-rw-r--r--planetwars-server/src/lib.rs8
-rw-r--r--planetwars-server/src/routes/bots.rs4
-rw-r--r--planetwars-server/src/routes/demo.rs4
-rw-r--r--planetwars-server/src/routes/matches.rs5
19 files changed, 157 insertions, 62 deletions
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<Mutex<EventBus>>, 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<Mutex<EventBus>>,
- bot_spec: &Box<dyn BotSpec>,
+ bot_spec: &dyn BotSpec,
match_logger: MatchLogger,
) -> (u32, Box<dyn PlayerHandle>) {
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<u32> {
@@ -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<Vec<u8>>) {
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<MatchLogMessage>, 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<Planet> {
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<Map> {
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<usize> {
@@ -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::<Session>(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<DieselConnectionManager<PgCo
let manager = DieselConnectionManager::<PgConnection>::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: &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 =
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<Json<ApiMatch>, 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))
}