From be540c717a1e3ed78e06d4411ba4558d0da102b7 Mon Sep 17 00:00:00 2001 From: Robbie Armstrong <34013278+roarmstrong@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:28:17 +1000 Subject: [PATCH 1/5] Add tech tiles and rep tiles for expanded galaxy games. Use data/techs.json to setup tech bag. Update tech.json tech tile counts --- data/basic_game.json | 114 +------------------------------------ data/techs.json | 28 +++++++-- helpers/GamestateHelper.py | 17 +++++- 3 files changed, 40 insertions(+), 119 deletions(-) diff --git a/data/basic_game.json b/data/basic_game.json index 1b2da5c..b995e3e 100644 --- a/data/basic_game.json +++ b/data/basic_game.json @@ -51,119 +51,7 @@ ], "tile_deck_300": [], "tile_discard": [], - "tech_deck": [ - "ade", - "ade", - "ade", - "ade", - "anc", - "anc", - "anc", - "fus", - "fus", - "fus", - "gas", - "gas", - "gas", - "imh", - "imh", - "imh", - "imh", - "imh", - "poc", - "poc", - "poc", - "poc", - "qug", - "qug", - "qug", - "tad", - "tad", - "tad", - "adm", - "adm", - "adm", - "adm", - "glc", - "glc", - "glc", - "neb", - "neb", - "neb", - "neb", - "neb", - "phs", - "phs", - "phs", - "phs", - "phs", - "plc", - "plc", - "plc", - "plc", - "plc", - "plm", - "plm", - "plm", - "stb", - "stb", - "stb", - "stb", - "stb", - "tas", - "tas", - "tas", - "adl", - "adl", - "adl", - "adl", - "adl", - "adr", - "adr", - "adr", - "adr", - "adr", - "ark", - "ark", - "ark", - "fud", - "fud", - "fud", - "fud", - "fud", - "mon", - "mon", - "mon", - "nar", - "nar", - "nar", - "nar", - "nar", - "orb", - "orb", - "orb", - "orb", - "orb", - "wog", - "wog", - "wog", - "abs", - "anl", - "ans", - "cld", - "cof", - "flm", - "iml", - "met", - "rican", - "seh", - "socan", - "trd", - "zes", - "pim", - "nea", - "wap" - ], + "tech_deck": [], "available_techs": [], "reputation_tiles": [ 4, diff --git a/data/techs.json b/data/techs.json index 32202fb..652e229 100644 --- a/data/techs.json +++ b/data/techs.json @@ -8,7 +8,7 @@ "art_pt": 0, "infdisc": 0, "dtile": 0, - "num": 4, + "num": 5, "description": "You may upgrade your Ship Blueprints with Gauss Shield Ship Parts. This basic shield is a starting tech for the Orion species. Reduces die rolls against this ship by 1, with no effect on Direct Hits." }, "fus": { @@ -20,7 +20,8 @@ "art_pt": 0, "infdisc": 0, "dtile": 0, - "num": 4, + "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with Fusion Source Ship Parts. Fusion Source generates 6 Energy for the ship." }, "imh": { @@ -33,6 +34,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with Improved Hull Ship Parts. Improved Hull panels can each absorb up to 2 hits during the Combat phase." }, "imhmod": { @@ -45,6 +47,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with modded Improved Hull Ship Parts. Improved Hull panels can each absorb up to 2 hits during the Combat phase but subtract 1 from your initiative." }, "poc": { @@ -56,7 +59,8 @@ "art_pt": 0, "infdisc": 0, "dtile": 0, - "num": 4, + "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with Positron Computer Ship Parts. Positron Computers add +2 to all non-Direct Hit (1-5) dice values rolled by this ship during the Combat Phase. Each Positron Computer requires 1 Energy." }, "ade": { @@ -69,6 +73,7 @@ "infdisc": 0, "dtile": 0, "num": 4, + "num_expanded_galaxy": 5, "description": "You may place Population Cubes in Advanced Money (Yellow) or Neutral (White) Population Squares with your Colony Ships. Advanced Population Squares are indicated by a small starburst in the upper left corner." }, "tad": { @@ -93,6 +98,7 @@ "infdisc": 0, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You may upgrade your Ship Blueprints with Antimatter Cannon Ship Parts. During the Combat Phase, Antimatter Cannons deal 4 hits to a single target if 1) the red die rolls a Direct Hit, or 2) if the red die result + total Computers - total Shields of the target ship = 6 or greater. Also see Antimass Splitter. Each Antimass Cannon requires 4 Energy." }, "qug": { @@ -105,6 +111,7 @@ "infdisc": 2, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You receive two additional Influence Discs, placed immediately on your Influence Track." }, "neb": { @@ -141,6 +148,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with Plasma Cannon Ship Parts. During the Combat Phase, Plasma Cannons deal 2 hits to a single target if 1) the orange die rolls a Direct Hit, or 2) if the orange die result + total Computers - total Shields of the target ship = 6 or greater. Each Plasma Cannon requires 2 Energy." }, "phs": { @@ -153,6 +161,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with Phase Shield Ship Parts. Reduces die rolls against this ship by 2, with no effect on Direct Hits. Each Phase Shield requires 1 Energy." }, "phsmod": { @@ -165,6 +174,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with modded Phase Shield Ship Parts. Reduces die rolls against this ship by 2, with no effect on Direct Hits. Each Phase Shield requires 1 Energy but also increases initiative by 1." }, "adm": { @@ -177,6 +187,7 @@ "infdisc": 0, "dtile": 0, "num": 4, + "num_expanded_galaxy": 5, "description": "You may place Population Cubes in Advanced Materials (Brown) or Neutral (White) Population Squares with your Colony Ships. Advanced Population Squares are indicated by a small starburst in the upper left corner." }, "tas": { @@ -189,6 +200,7 @@ "infdisc": 0, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You may upgrade your Ship Blueprints with Tachyon Source Ship Parts. Tachyon Source generates 9 Energy for the ship." }, "glc": { @@ -201,6 +213,7 @@ "infdisc": 0, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You may upgrade your Ship Blueprints with Gluon Computer Ship Parts. Gluon Computers add +3 to all non-Direct Hit (1-5) dice values rolled by this ship during the Combat Phase. Each Gluon Computer requires 2 Energy." }, "plm": { @@ -213,6 +226,7 @@ "infdisc": 0, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You may upgrade your Ship Blueprints with Plasma Missile Ship Parts. A Plasma Missile box rolls two dice at the beginning of Combat Phase during the Fire Missiles step. Each Plasma Missile deals 2 hits if 1) the orange die rolls a Direct Hit, or 2) if the orange die result + total Computers - total Shields of the target ship = 6 or greater. Does not fire during the Repeated Engagement Rounds. Each Plasma Missile box requires 1 Energy." }, "nar": { @@ -237,6 +251,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may upgrade your Ship Blueprints with Fusion Drive Ship Parts. Each Fusion Drive allows ships to Move into up to 2 systems during a single Move Activation. Each Fusion Drive also adds +2 to the Ship's Initiative value during Combat; i.e., the ship also shoots faster. Each Fusion Drive requires 2 Energy." }, "orb": { @@ -249,6 +264,7 @@ "infdisc": 0, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You may Build Orbitals." }, "adr": { @@ -261,6 +277,7 @@ "infdisc": 1, "dtile": 0, "num": 5, + "num_expanded_galaxy": 6, "description": "You receive 1 additional Influence Disc, placed immediately on your Influence Track." }, "adl": { @@ -272,7 +289,8 @@ "art_pt": 0, "infdisc": 0, "dtile": 0, - "num": 5, + "num": 4, + "num_expanded_galaxy": 5, "description": "You may place Population Cubes in Advanced Science (Pink) or Neutral (White) Population Squares with your Colony Ships. Advanced Population Squares are indicated by a small starburst in the upper left corner." }, "mon": { @@ -285,6 +303,7 @@ "infdisc": 0, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You may Build Monoliths." }, "wog": { @@ -297,6 +316,7 @@ "infdisc": 0, "dtile": 0, "num": 3, + "num_expanded_galaxy": 4, "description": "You may Explore, Move to, and Influence adjacent Sectors if the edges connecting the Sectors contain 1 Wormhole." }, "ark": { diff --git a/helpers/GamestateHelper.py b/helpers/GamestateHelper.py index c34a3fe..e01d370 100644 --- a/helpers/GamestateHelper.py +++ b/helpers/GamestateHelper.py @@ -996,9 +996,9 @@ def setup_finished(self): self.gamestate["setup_finished"] = 1 self.update() - def setup_techs_and_outer_rim(self, count: int, galactic_events ,hyperlane): + def setup_techs_and_outer_rim(self, count: int, galactic_events, hyperlane): self.gamestate["player_count"] = count - draw_count = {2: [5, 12], 3: [8, 14], 4: [14, 16], 5: [16, 18], 6: [18, 20],7:[22,22],8:[24,24],9:[24,26]} + draw_count = {2: [5, 12], 3: [8, 14], 4: [14, 16], 5: [16, 18], 6: [18, 20], 7: [22, 22], 8: [24, 24], 9: [24, 26]} third_sector_tiles = ["301", "302", "303", "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "381", "382", "398", "397", "399", "396", "394", "393"] @@ -1017,6 +1017,15 @@ def setup_techs_and_outer_rim(self, count: int, galactic_events ,hyperlane): with open("data/techs.json", "r") as f: tech_data = json.load(f) + expanded_galaxy = count > 6 + for tech_id, tech_info in tech_data.items(): + if expanded_galaxy and "num_expanded_galaxy" in tech_info: + tile_count = tech_info["num_expanded_galaxy"] + else: + tile_count = tech_info["num"] + for _ in range(tile_count): + self.gamestate["tech_deck"].append(tech_id) + while sector_draws > 0: random.shuffle(third_sector_tiles) self.gamestate["tile_deck_300"].append(third_sector_tiles.pop(0)) @@ -1033,6 +1042,10 @@ def setup_techs_and_outer_rim(self, count: int, galactic_events ,hyperlane): pass else: tech_draws -= 1 + + if expanded_galaxy: + self.gamestate["reputation_tiles"].extend([4, 4, 3, 3, 3, 2, 2, 1, 1]) + minorDraws = 4 minor_species = ["Cruiser Discount", "Dreadnought Discount", "Monolith Discount", "Orbital Discount", "Tech Discount", "Population Cube", From 584f92861b2c86569601ccf3139e036bc0d771d5 Mon Sep 17 00:00:00 2001 From: Robbie Armstrong <34013278+roarmstrong@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:09:11 +1000 Subject: [PATCH 2/5] fixup log for rift cannon + community parts. Add minimal tests for this path --- helpers/GamestateHelper.py | 12 +++++ setup/GameInit.py | 10 +--- tests/test_game_init_tech_deck.py | 88 +++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 tests/test_game_init_tech_deck.py diff --git a/helpers/GamestateHelper.py b/helpers/GamestateHelper.py index e01d370..fbe517a 100644 --- a/helpers/GamestateHelper.py +++ b/helpers/GamestateHelper.py @@ -1018,7 +1018,19 @@ def setup_techs_and_outer_rim(self, count: int, galactic_events, hyperlane): tech_data = json.load(f) expanded_galaxy = count > 6 + rift_cannon = self.gamestate.get("rift_cannon", True) + community_parts = self.gamestate.get("community_parts", False) + excluded_techs = set() + if not rift_cannon: + excluded_techs.add("rican") + if community_parts: + excluded_techs.update({"imh", "phs"}) + else: + excluded_techs.update({"imhmod", "phsmod"}) + for tech_id, tech_info in tech_data.items(): + if tech_id in excluded_techs: + continue if expanded_galaxy and "num_expanded_galaxy" in tech_info: tile_count = tech_info["num_expanded_galaxy"] else: diff --git a/setup/GameInit.py b/setup/GameInit.py index 11d0fab..c16d095 100644 --- a/setup/GameInit.py +++ b/setup/GameInit.py @@ -54,15 +54,9 @@ def create_game(self): self.gamestate[ship+"_type"]="wa" self.gamestate["turnsInPassingOrder"] = self.turn_order_variant if not self.rift_cannon: - self.gamestate["tech_deck"].remove("rican") self.gamestate["discTiles"].remove("ricon") - if self.community_parts: - while "imh" in self.gamestate["tech_deck"]: - self.gamestate["tech_deck"].remove("imh") - self.gamestate["tech_deck"].append("imhmod") - while "phs" in self.gamestate["tech_deck"]: - self.gamestate["tech_deck"].remove("phs") - self.gamestate["tech_deck"].append("phsmod") + self.gamestate["rift_cannon"] = self.rift_cannon + self.gamestate["community_parts"] = self.community_parts with open(f"{config.gamestate_path}/{self.gamestate['game_id']}.json", "w") as f: json.dump(self.gamestate, f) diff --git a/tests/test_game_init_tech_deck.py b/tests/test_game_init_tech_deck.py new file mode 100644 index 0000000..2c7d567 --- /dev/null +++ b/tests/test_game_init_tech_deck.py @@ -0,0 +1,88 @@ +import json +import pytest +import config + + +def _minimal_gamestate(): + return { + "game_id": "test0", + "game_name": "Test", + "setup_finished": 1, + "game_phase": [], + "game_round": 1, + "roundNum": 1, + "advanced_ai": 0, + "wa_ai": 0, + "player_count": 2, + "player_order": [], + "active_player": [], + "activePlayerColor": [], + "lastPingTime": 0, + "lastButton": "", + "available_colors": [], + "used_colors": [], + "tile_deck_100": [], + "tile_deck_200": [], + "tile_deck_300": [], + "tile_discard": [], + "tech_deck": [], + "available_techs": [], + "reputation_tiles": [4, 3, 2, 1], + "discTiles": [], + "players": {}, + "board": {}, + } + + +def _run_setup_techs(tmp_path, community_parts: bool = False, rift_cannon: bool = True): + """Run setup_techs_and_outer_rim() against a temp game and return the resulting gamestate.""" + from helpers.GamestateHelper import GamestateHelper + + gs = _minimal_gamestate() + gs["community_parts"] = community_parts + gs["rift_cannon"] = rift_cannon + + game_path = tmp_path / f"{gs['game_id']}.json" + with open(game_path, "w") as f: + json.dump(gs, f) + + original_path = config.gamestate_path + config.gamestate_path = str(tmp_path) + try: + game = GamestateHelper(None, gs["game_id"]) + game.setup_techs_and_outer_rim(2, False, False) + return game.gamestate + finally: + config.gamestate_path = original_path + + +def _all_techs(gs): + return gs["tech_deck"] + gs["available_techs"] + + +class TestCommunityParts: + def test_community_parts_enabled(self, tmp_path): + gs = _run_setup_techs(tmp_path, community_parts=True) + all_techs = _all_techs(gs) + assert "phs" not in all_techs + assert "imh" not in all_techs + assert "phsmod" in all_techs + assert "imhmod" in all_techs + + def test_community_parts_disabled(self, tmp_path): + gs = _run_setup_techs(tmp_path, community_parts=False) + all_techs = _all_techs(gs) + assert "phsmod" not in all_techs + assert "imhmod" not in all_techs + assert "phs" in all_techs + assert "imh" in all_techs + + +class TestRiftCannon: + def test_rift_cannon_disabled(self, tmp_path): + gs = _run_setup_techs(tmp_path, rift_cannon=False) + assert "rican" not in _all_techs(gs) + + def test_rift_cannon_enabled(self, tmp_path): + gs = _run_setup_techs(tmp_path, rift_cannon=True) + assert "rican" in _all_techs(gs) From b9662c3b3dc7d3ad368c521a2ca92a68f070d7fc Mon Sep 17 00:00:00 2001 From: Robbie Armstrong <34013278+roarmstrong@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:18:06 +1000 Subject: [PATCH 3/5] Add a GHA workflow for pytest --- .github/workflows/pytest.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/pytest.yml diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 0000000..36ec950 --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,27 @@ +name: Pytest + +on: + pull_request: + branches: + - main + +jobs: + pytest: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v3 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + grep -v pywin32 requirements.txt | pip install -r /dev/stdin + pip install pytest + + - name: Run tests + run: pytest tests/ From 052936207044eb690e9890b199683d3e2def0242 Mon Sep 17 00:00:00 2001 From: TaylorBoyd Date: Wed, 22 Apr 2026 18:43:09 -0400 Subject: [PATCH 4/5] Bug Fix in final scoring Issue discovered by ggranger --- helpers/DrawHelper.py | 1 + 1 file changed, 1 insertion(+) diff --git a/helpers/DrawHelper.py b/helpers/DrawHelper.py index 5cb370a..b5b5388 100644 --- a/helpers/DrawHelper.py +++ b/helpers/DrawHelper.py @@ -1635,6 +1635,7 @@ def get_public_points(self, player, showPrivateRegardless:bool): points -= 1 if "per rep" in reputation: countRep = True + points -= 1 if countAmb: points += ambass if countRep: From 2fe7a6e844a5ffcbf86c85aa50fc6785dbe98913 Mon Sep 17 00:00:00 2001 From: Robbie Armstrong <34013278+roarmstrong@users.noreply.github.com> Date: Thu, 23 Apr 2026 11:04:37 +1000 Subject: [PATCH 5/5] update pytest invocation --- .github/workflows/pytest.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 36ec950..9ae66db 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -24,4 +24,7 @@ jobs: pip install pytest - name: Run tests - run: pytest tests/ + run: | + echo '{"token": "test-token", "game_number": 46, "gamestate_path": "/tmp/eclipse_test_games"}' > config.json + python3 -m pytest tests/ +