From baa34aa23e2e12b9882db40220a48cf407602967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Fri, 25 Mar 2022 20:57:18 -0300 Subject: [PATCH 1/7] improved serialization of the galazy, including context data --- pythonium/output_handler.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/pythonium/output_handler.py b/pythonium/output_handler.py index 81680e7..8f3e0f2 100644 --- a/pythonium/output_handler.py +++ b/pythonium/output_handler.py @@ -42,11 +42,27 @@ def finish(self, galaxy, winner): @attr.s class StreamOutputHanlder(OutputHandler): def start(self, galaxy): - self.output.write(f"pythonium|{__version__}|{galaxy.name}\n") + data = { + "version": __version__, + "galaxy": galaxy.name, + "players": [player for player in galaxy.known_races], + "size": list(galaxy.size) + } + self.output.write(json.dumps(data)) + self.output.write("\n") + def step(self, galaxy, context): - self.output.write(json.dumps(galaxy.serialize())) + data = { + "galaxy": galaxy.serialize(), + "score": context["score"] + } + self.output.write(json.dumps(data)) self.output.write("\n") def finish(self, galaxy, winner): - self.output.write(f"pythonium|{galaxy.name}|{galaxy.turn}|{winner}\n") + data = { + "turns": galaxy.turn, + "winner": winner + } + self.output.write(json.dumps(data)) From e970c53e13047a36da313e1c5d45e7b70c2dc9d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Fri, 25 Mar 2022 20:57:55 -0300 Subject: [PATCH 2/7] simplify viz from better serialziation --- pythonium/main.py | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/pythonium/main.py b/pythonium/main.py index 5c29f5f..86e3d4b 100644 --- a/pythonium/main.py +++ b/pythonium/main.py @@ -1,3 +1,4 @@ +import click import http.server import importlib import os @@ -7,11 +8,11 @@ import time import uuid import webbrowser + +from datetime import date from datetime import datetime as dt from pathlib import Path -import click - from . import __version__ from .game import Game from .game_modes import ClassicMode @@ -90,8 +91,9 @@ def run( @cli.command() @click.argument("state") +@click.option("--port", default=PORT) @click.option("--html", default=None) -def visualize(state, html): +def visualize(state, port, html): with open(state, "r") as state_file: state_data = parseToPOJO(state_file.read()) @@ -110,10 +112,10 @@ def visualize(state, html): handler = http.server.SimpleHTTPRequestHandler - with socketserver.TCPServer(("", PORT), handler) as httpd: - click.echo("Server started at localhost:" + str(PORT)) + with socketserver.TCPServer(("", port), handler) as httpd: + click.echo("Server started at localhost:" + str(port)) url = "http://localhost:{port}/{path}".format( - port=PORT, path=output_fname + port=port, path=output_fname ) click.echo("Visualization in: " + url) webbrowser.open(url) @@ -121,31 +123,13 @@ def visualize(state, html): def parseToPOJO(data_json): - prefix, *states, suffix = data_json.splitlines() + meta, *states, end = data_json.splitlines() pojo = f"""{{ + meta: {meta}, turns: {get_data_turns(states)}, - galaxyName: "{get_data_galaxy_name(prefix)}", - players: {get_data_players(data_json)}, + end: {end}, }}""" - return pojo - -def get_data_galaxy_name(prefix): - return prefix.split("|")[2] - - def get_data_turns(states): return "[{}]".format(",\n".join(states)) - - -def get_data_players(data_json): - def oc_to_name(oc): - return oc[len('"player": ') :] - - names_occurrencies = re.findall('"player": "[^(?!")]*"', data_json) - names = list(set([oc_to_name(name_oc) for name_oc in names_occurrencies])) - - if len(names) == 1: - return f"[{names[0]}]" - return f"[{names[0]}, {names[1]}]" From d924c09909b56b36497d1c897496e005f42e2b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Fri, 25 Mar 2022 20:58:17 -0300 Subject: [PATCH 3/7] update after serializartion changes --- pythonium/webrenderer/web_renderer.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pythonium/webrenderer/web_renderer.js b/pythonium/webrenderer/web_renderer.js index b3b90a4..8023f23 100644 --- a/pythonium/webrenderer/web_renderer.js +++ b/pythonium/webrenderer/web_renderer.js @@ -6,7 +6,7 @@ document.getElementById("visualization").appendChild(app.view); app.stage.scale.set(resizeFactor); function renderTheGalaxy(simulationStep) { - data.turns[simulationStep].things.forEach( + data.turns[simulationStep].galaxy.things.forEach( (thing, index) => { let texture = thing.thing_type == "planet" ? textures.planets[index % 3] @@ -14,10 +14,10 @@ function renderTheGalaxy(simulationStep) { let sprite = new PIXI.TilingSprite(texture); sprite.anchor.set(0.5); sprite.scale.set(0.1); - if (thing.player == data.players[0]) { + if (thing.player == data.meta.players[0]) { sprite.tint = playerColors[0]; } - if (thing.player == data.players[1]) { + if (thing.player == data.meta.players[1]) { sprite.tint = playerColors[1]; } if (thing.thing_type == "planet" && data.turns[simulationStep].explosions.length > 0) { @@ -136,10 +136,10 @@ loader.load((loader, resources) => { }); window.onload = function() { - document.getElementById("galaxy-name-placeholder").innerText = data.galaxyName; + document.getElementById("galaxy-name-placeholder").innerText = data.meta.galaxy; let botsListElem = document.getElementById("bots-list"); - data.players.forEach((bot, i) => { + data.meta.players.forEach((bot, i) => { var li = document.createElement("li"); li.innerHTML = "■" + bot; li.style = "color:" + playerColorsStr[i]; From 20236f89c8ca0dd69864b7b59841864283c9177a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Sat, 26 Mar 2022 12:34:03 -0300 Subject: [PATCH 4/7] Use different colors for diferent players --- pythonium/webrenderer/web_renderer.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pythonium/webrenderer/web_renderer.js b/pythonium/webrenderer/web_renderer.js index 8023f23..c2a02ee 100644 --- a/pythonium/webrenderer/web_renderer.js +++ b/pythonium/webrenderer/web_renderer.js @@ -1,6 +1,7 @@ // Globals let SIZE = 700; let resizeFactor = SIZE / 500; // 500 is the galaxy size +let playerColors = {}; let app = new PIXI.Application({ width: SIZE, height: SIZE}); document.getElementById("visualization").appendChild(app.view); app.stage.scale.set(resizeFactor); @@ -14,11 +15,8 @@ function renderTheGalaxy(simulationStep) { let sprite = new PIXI.TilingSprite(texture); sprite.anchor.set(0.5); sprite.scale.set(0.1); - if (thing.player == data.meta.players[0]) { - sprite.tint = playerColors[0]; - } - if (thing.player == data.meta.players[1]) { - sprite.tint = playerColors[1]; + if (thing.player) { + sprite.tint = playerColors[thing.player]; } if (thing.thing_type == "planet" && data.turns[simulationStep].explosions.length > 0) { let explosion = data.turns[simulationStep].explosions.find( @@ -116,8 +114,6 @@ stepInputElem.onchange = function(e) { // Create the application helper and add its render target to the page const textures = {}; -const playerColors = [0x00AAFF, 0xFFAA00]; -const playerColorsStr = ["#00AAFF", "#FFAA00"]; const loader = PIXI.Loader.shared; loader.add('planet01', 'assets/planet01.png'); loader.add('planet02', 'assets/planet02.png'); @@ -138,11 +134,16 @@ loader.load((loader, resources) => { window.onload = function() { document.getElementById("galaxy-name-placeholder").innerText = data.meta.galaxy; + const colors = [0x00AAFF, 0xFFAA00, 0x03fc0f, 0xbf061b, 0xdb12db, 0x308c0e, 0x1cbed4]; + const colorsStr = ["#00AAFF", "#FFAA00", "#03fc0f", "#bf061b", "#db12db", "#308c0e", "#1cbed4"]; + let botsListElem = document.getElementById("bots-list"); - data.meta.players.forEach((bot, i) => { + data.meta.players.forEach((bot, idx) => { + let i = idx % colors.length; // As we only have a limited number of colors, they may be reused... + playerColors[bot] = colors[i]; var li = document.createElement("li"); li.innerHTML = "■" + bot; - li.style = "color:" + playerColorsStr[i]; + li.style = "color:" + colorsStr[i]; botsListElem.appendChild(li); }); From aac345ae1c35c37e6af652d1a347dc98502a412f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Sat, 26 Mar 2022 12:42:25 -0300 Subject: [PATCH 5/7] remove unused import --- pythonium/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pythonium/main.py b/pythonium/main.py index 86e3d4b..39947a8 100644 --- a/pythonium/main.py +++ b/pythonium/main.py @@ -9,7 +9,6 @@ import uuid import webbrowser -from datetime import date from datetime import datetime as dt from pathlib import Path From 3d1cd884cf9df7bb775e3c58f0474e46aea0ec77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Sat, 26 Mar 2022 12:42:48 -0300 Subject: [PATCH 6/7] fix after merge --- pythonium/webrenderer/web_renderer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pythonium/webrenderer/web_renderer.js b/pythonium/webrenderer/web_renderer.js index c2a02ee..0c51d66 100644 --- a/pythonium/webrenderer/web_renderer.js +++ b/pythonium/webrenderer/web_renderer.js @@ -18,8 +18,8 @@ function renderTheGalaxy(simulationStep) { if (thing.player) { sprite.tint = playerColors[thing.player]; } - if (thing.thing_type == "planet" && data.turns[simulationStep].explosions.length > 0) { - let explosion = data.turns[simulationStep].explosions.find( + if (thing.thing_type == "planet" && data.turns[simulationStep].galaxy.explosions.length > 0) { + let explosion = data.turns[simulationStep].galaxy.explosions.find( explosion => explosion.ship.position[0] == thing.position[0] && explosion.ship.position[1] == thing.position[1] ) From da4fe8fe888972a63deef18f3e58dc4b2277e422 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mat=C3=ADas=20de=20la=20Torre?= Date: Sat, 26 Mar 2022 12:48:28 -0300 Subject: [PATCH 7/7] black + isort fixes --- pythonium/explosion.py | 1 + pythonium/main.py | 5 +++-- pythonium/output_handler.py | 13 +++---------- pythonium/rules/executor.py | 4 +++- pythonium/rules/extractor.py | 11 ++++++----- tests/rules/test_extractor.py | 1 - tests/rules/test_planet.py | 4 +--- 7 files changed, 17 insertions(+), 22 deletions(-) diff --git a/pythonium/explosion.py b/pythonium/explosion.py index 8be8b32..12bac25 100644 --- a/pythonium/explosion.py +++ b/pythonium/explosion.py @@ -1,4 +1,5 @@ import attr + from .ship import Ship diff --git a/pythonium/main.py b/pythonium/main.py index 39947a8..e7df97f 100644 --- a/pythonium/main.py +++ b/pythonium/main.py @@ -1,4 +1,3 @@ -import click import http.server import importlib import os @@ -8,10 +7,11 @@ import time import uuid import webbrowser - from datetime import datetime as dt from pathlib import Path +import click + from . import __version__ from .game import Game from .game_modes import ClassicMode @@ -130,5 +130,6 @@ def parseToPOJO(data_json): }}""" return pojo + def get_data_turns(states): return "[{}]".format(",\n".join(states)) diff --git a/pythonium/output_handler.py b/pythonium/output_handler.py index 8f3e0f2..7f61694 100644 --- a/pythonium/output_handler.py +++ b/pythonium/output_handler.py @@ -46,23 +46,16 @@ def start(self, galaxy): "version": __version__, "galaxy": galaxy.name, "players": [player for player in galaxy.known_races], - "size": list(galaxy.size) + "size": list(galaxy.size), } self.output.write(json.dumps(data)) self.output.write("\n") - def step(self, galaxy, context): - data = { - "galaxy": galaxy.serialize(), - "score": context["score"] - } + data = {"galaxy": galaxy.serialize(), "score": context["score"]} self.output.write(json.dumps(data)) self.output.write("\n") def finish(self, galaxy, winner): - data = { - "turns": galaxy.turn, - "winner": winner - } + data = {"turns": galaxy.turn, "winner": winner} self.output.write(json.dumps(data)) diff --git a/pythonium/rules/executor.py b/pythonium/rules/executor.py index 98b4f60..1e12fb7 100644 --- a/pythonium/rules/executor.py +++ b/pythonium/rules/executor.py @@ -25,7 +25,9 @@ def __call__(self, orders): self.execute_rule(rule_class, rule_orders) def execute_rule(self, rule_class, orders): - logger.info("Executing rule", extra={'rule': rule_class, 'orders': len(orders)}) + logger.info( + "Executing rule", extra={"rule": rule_class, "orders": len(orders)} + ) for order in orders: kwargs = order.kwargs if isinstance(order, ShipOrder): diff --git a/pythonium/rules/extractor.py b/pythonium/rules/extractor.py index 369f9e9..e8aa00a 100644 --- a/pythonium/rules/extractor.py +++ b/pythonium/rules/extractor.py @@ -12,12 +12,13 @@ @attr.s(auto_attribs=True) class OrdersExtractor: """ - :param game_mode: Class that define some game rules - :type game_mode: :class:GameMode - :param _raise_exceptions: If ``True`` stop the game if an exception is raised when - computing player actions. Useful for debuging players. - :type _raise_exceptions: bool + :param game_mode: Class that define some game rules + :type game_mode: :class:GameMode + :param _raise_exceptions: If ``True`` stop the game if an exception is raised when + computing player actions. Useful for debuging players. + :type _raise_exceptions: bool """ + game_mode: GameMode = attr.ib() _raise_exceptions: bool = attr.ib(default=False) diff --git a/tests/rules/test_extractor.py b/tests/rules/test_extractor.py index c4e7598..f7cd001 100644 --- a/tests/rules/test_extractor.py +++ b/tests/rules/test_extractor.py @@ -2,7 +2,6 @@ class TestOrdersExtractor: - def setup(self, game_mode): self.extract = OrdersExtractor(game_mode) diff --git a/tests/rules/test_planet.py b/tests/rules/test_planet.py index 3a58a7f..7277538 100644 --- a/tests/rules/test_planet.py +++ b/tests/rules/test_planet.py @@ -157,9 +157,7 @@ def test_taxes_dont_change(self, galaxy): """ If set taxes are equal to current taxes, does nothing """ - rule = PlanetSetTaxesRule( - planet=self.planet, taxes=self.current_taxes - ) + rule = PlanetSetTaxesRule(planet=self.planet, taxes=self.current_taxes) rule.execute(galaxy) assert self.planet.taxes == self.current_taxes