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 5c29f5f..e7df97f 100644 --- a/pythonium/main.py +++ b/pythonium/main.py @@ -90,8 +90,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 +111,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 +122,14 @@ 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]}]" diff --git a/pythonium/output_handler.py b/pythonium/output_handler.py index 81680e7..7f61694 100644 --- a/pythonium/output_handler.py +++ b/pythonium/output_handler.py @@ -42,11 +42,20 @@ 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)) 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/pythonium/webrenderer/web_renderer.js b/pythonium/webrenderer/web_renderer.js index b3b90a4..0c51d66 100644 --- a/pythonium/webrenderer/web_renderer.js +++ b/pythonium/webrenderer/web_renderer.js @@ -1,12 +1,13 @@ // 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); 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,14 +15,11 @@ 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]) { - sprite.tint = playerColors[0]; + if (thing.player) { + sprite.tint = playerColors[thing.player]; } - if (thing.player == data.players[1]) { - sprite.tint = playerColors[1]; - } - 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] ) @@ -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'); @@ -136,13 +132,18 @@ loader.load((loader, resources) => { }); window.onload = function() { - document.getElementById("galaxy-name-placeholder").innerText = data.galaxyName; + 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.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); }); 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