Skip to content

Commit 5ee8d6f

Browse files
committed
Successfully completing the game
1 parent b655359 commit 5ee8d6f

6 files changed

Lines changed: 80 additions & 51 deletions

File tree

Config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010

1111
class Config:
12+
min_n_points_to_finish = 15
1213
n_simulations = 100
13-
n_games = 100
14+
n_games = 1
1415
n_players = 2

agent/train_agent.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections import defaultdict
2+
from dataclasses import astuple
23
from math import sqrt
34

45
import numpy as np
@@ -21,6 +22,7 @@ def train_agent():
2122
pi, action = policy(game, agent, 1, Config.n_simulations)
2223
examples_per_game.append((game, pi, 0))
2324
game = game.perform(action)
25+
print(len(game.players[1].cards), game.players[1].points)
2426
if game.is_terminal():
2527
for example in examples_per_game:
2628
example[2] = game.get_state()

src/Game.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from itertools import combinations, starmap, product
33
from typing import Self, Type
44

5+
from Config import Config
56
from .StateExtractor import StateExtractor
67
from .entities.AllResources import AllResources
78
from .entities.BasicResources import BasicResources
@@ -60,7 +61,7 @@ def next_turn(self) -> None:
6061
self.current_player.aristocrats.append(
6162
self.board.aristocrats.pop(index)
6263
)
63-
if self.current_player.points >= 15 or self._last_turn:
64+
if self.current_player.points >= Config.min_n_points_to_finish or self._last_turn:
6465
self._last_turn = True
6566
self._performed_the_last_move[self.current_player] = self._last_turn
6667
self.current_player = self.players[0]
@@ -73,15 +74,12 @@ def is_terminal(self) -> bool:
7374
def get_results(self) -> dict[Player, int]:
7475
results = {}
7576
for player in self.players:
76-
if not all(self._performed_the_last_move.values()):
77-
results[player] = (
78-
1
79-
if player
80-
== max(self.players, key=lambda p: (p.points, -len(p.cards)))
81-
else -1
82-
)
83-
else:
84-
print("Finished game")
77+
results[player] = (
78+
1
79+
if player
80+
== max(self.players, key=lambda p: (p.points, -len(p.cards)))
81+
else -1
82+
)
8583
return results
8684

8785
def get_state(self) -> tuple:
@@ -99,15 +97,15 @@ def copy(self) -> Self:
9997
resources.white,
10098
resources.gold,
10199
),
102-
cards=PlayerCards(tuple(player.cards)),
103-
reserve=PlayerReserve(tuple(player.reserve)),
104-
aristocrats=PlayerAristocrats(tuple(player.aristocrats)),
100+
cards=PlayerCards(player.cards),
101+
reserve=PlayerReserve(player.reserve),
102+
aristocrats=PlayerAristocrats(player.aristocrats),
105103
)
106104
for player in self.players
107105
),
108106
board=Board(
109107
n_players=(board := self.board).n_players,
110-
tiers=list(Tier(tier.hidden, tier.visible) for tier in board.tiers),
108+
tiers=list(Tier(list(tier.hidden), list(tier.visible)) for tier in board.tiers),
111109
aristocrats=Aristocrats(board.aristocrats),
112110
resources=AllResources(
113111
board.resources.red,
@@ -125,6 +123,9 @@ def copy(self) -> Self:
125123
game.is_blocked[player] = next(
126124
value for key, value in self.is_blocked.items() if key == player
127125
)
126+
game._performed_the_last_move[player] = next(
127+
value for key, value in self._performed_the_last_move.items() if key == player
128+
)
128129
return game
129130

130131
def get_possible_actions(self) -> list[Move]:

src/moves/Build.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
from abc import ABC
2+
from dataclasses import dataclass
3+
from typing import TYPE_CHECKING
4+
5+
from src.entities.Card import Card
6+
from ..entities.AllResources import AllResources
7+
8+
if TYPE_CHECKING:
9+
from src.Game import Game
10+
from .Move import Move
11+
12+
13+
@dataclass(slots=True, frozen=True)
14+
class Build(Move, ABC):
15+
@staticmethod
16+
def _build(game: "Game", card: Card) -> "Game":
17+
current_player = game.current_player
18+
gold_paid_for_red = max(0, card.cost.red - current_player.production.red - current_player.resources.red)
19+
gold_paid_for_green = max(0, card.cost.green - current_player.production.green - current_player.resources.green)
20+
gold_paid_for_blue = max(0, card.cost.blue - current_player.production.blue - current_player.resources.blue)
21+
gold_paid_for_black = max(0, card.cost.black - current_player.production.black - current_player.resources.black)
22+
gold_paid_for_white = max(0, card.cost.white - current_player.production.white - current_player.resources.white)
23+
cost = AllResources(
24+
max(0, card.cost.red - current_player.production.red - gold_paid_for_red),
25+
max(0, card.cost.green - current_player.production.green - gold_paid_for_green),
26+
max(0, card.cost.blue - current_player.production.blue - gold_paid_for_blue),
27+
max(0, card.cost.black - current_player.production.black - gold_paid_for_black),
28+
max(0, card.cost.white - current_player.production.white - gold_paid_for_white),
29+
sum((gold_paid_for_red, gold_paid_for_green, gold_paid_for_blue, gold_paid_for_black, gold_paid_for_white)),
30+
)
31+
current_player.resources = AllResources(
32+
max(0, current_player.resources.red - cost.red),
33+
max(0, current_player.resources.green - cost.green),
34+
max(0, current_player.resources.blue - cost.blue),
35+
max(0, current_player.resources.black - cost.black),
36+
max(0, current_player.resources.white - cost.white),
37+
current_player.resources.gold - cost.gold,
38+
)
39+
game.board.resources = AllResources(
40+
game.board.resources.red + cost.red,
41+
game.board.resources.green + cost.green,
42+
game.board.resources.blue + cost.blue,
43+
game.board.resources.black + cost.black,
44+
game.board.resources.white + cost.white,
45+
game.board.resources.gold + cost.gold,
46+
)
47+
current_player.cards.append(card)
48+
return game

src/moves/BuildBoard.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,23 @@
1-
from collections import Counter
2-
from dataclasses import asdict, dataclass
1+
from dataclasses import dataclass
2+
from typing import TYPE_CHECKING
33

4-
from src.entities.BasicResources import BasicResources
54
from src.entities.Card import empty_card
6-
from typing import TYPE_CHECKING
5+
from .Build import Build
76

87
if TYPE_CHECKING:
98
from src.Game import Game
10-
from .Move import Move
119

1210

1311
@dataclass(slots=True, frozen=True)
14-
class BuildBoard(Move):
12+
class BuildBoard(Build):
1513
tier_index: int
1614
index: int
1715

1816
def perform(self, game: "Game") -> "Game":
19-
game = Move.perform(self, game)
20-
current_player = game.current_player
21-
if current_player.resources.lacks():
22-
raise ValueError()
17+
game = Build.perform(self, game)
2318
tier = game.board.tiers[self.tier_index]
2419
card = tier.pop(self.index)
25-
not_produced = BasicResources(
26-
**(Counter(asdict(card.cost)) - Counter(asdict(current_player.production)))
27-
)
28-
if (current_player.resources - not_produced).lacks():
29-
raise ValueError()
30-
current_player.resources -= not_produced
31-
current_player.cards.append(card)
32-
return game
20+
return Build._build(game, card)
3321

3422
def is_valid(self, game: "Game") -> bool:
3523
tier = game.board.tiers[self.tier_index]
@@ -38,5 +26,5 @@ def is_valid(self, game: "Game") -> bool:
3826
card = tier.visible[self.index]
3927
current_player = game.current_player
4028
return not (
41-
current_player.resources + current_player.production - card.cost
29+
(current_player.resources + current_player.production) - card.cost
4230
).lacks()

src/moves/BuildReserve.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
1-
from collections import Counter
2-
from dataclasses import asdict, dataclass
1+
from dataclasses import dataclass
2+
from typing import TYPE_CHECKING
33

4-
from src.entities.BasicResources import BasicResources
54
from src.entities.Card import empty_card
6-
from typing import TYPE_CHECKING
5+
from .Build import Build
76

87
if TYPE_CHECKING:
98
from src.Game import Game
10-
from .Move import Move
119

1210

1311
@dataclass(slots=True, frozen=True)
14-
class BuildReserve(Move):
12+
class BuildReserve(Build):
1513
index: int
1614

1715
def perform(self, game: "Game") -> "Game":
18-
game = Move.perform(self, game)
16+
game = Build.perform(self, game)
1917
current_player = game.current_player
20-
if current_player.resources.lacks():
21-
raise ValueError()
2218
card = current_player.reserve.pop(self.index)
23-
not_produced = BasicResources(
24-
**(Counter(asdict(card.cost)) - Counter(asdict(current_player.production)))
25-
)
26-
if (current_player.resources - not_produced).lacks():
27-
raise ValueError()
28-
current_player.resources -= not_produced
29-
current_player.cards.append(card)
30-
return game
19+
return Build._build(game, card)
3120

3221
def is_valid(self, game: "Game") -> bool:
3322
current_player = game.current_player

0 commit comments

Comments
 (0)