graph-games-proto 0.3.2125__py3-none-any.whl → 0.3.2225__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,3 @@
1
1
  # __init__.py
2
2
  from .main import hello
3
- from .fns import isterminal, getfinalscores, get_deadlines, get_longest_path_length, get_max_allotted_times, get_legal_actions_for_path, find_player_with_longest_path, calc_player_graph, get_edges, FrozenDek, QValueLearningPolicy, Action2, getnextstate2, isactionlegal2, LegalAction, Fig, RandoPolicy, StaticBoardConfig, autoplay, getpublicstate, generate_cards, PublicState, State, Fig, getprivatescore, get_qvalue_trajectories, PlayerState, initfig, initboardconfig, gettoplay, printstate, getinitialstate, Card, PrivateState, getprivatestate, printaction, json_serializer, getrng, FrozenBoardConfig, initgameconfig, GameConfig
3
+ from .fns import getpublicgameconfig, alpha0, isterminal, getfinalscores, get_deadlines, get_longest_path_length, get_max_allotted_times, get_legal_actions_for_path, find_player_with_longest_path, calc_player_graph, get_edges, FrozenDek, QValueLearningPolicy, Action2, getnextstate2, isactionlegal2, LegalAction, Fig, RandoPolicy, StaticBoardConfig, autoplay, getpublicstate, generate_cards, PublicState, State, Fig, getprivatescore, get_qvalue_trajectories, PlayerState, initfig, initboardconfig, gettoplay, printstate, getinitialstate, Card, PrivateState, getprivatestate, printaction, json_serializer, getrng, FrozenBoardConfig, initgameconfig, GameConfig
graph_games_proto/fns.py CHANGED
@@ -932,78 +932,80 @@ class Fig(PClass):
932
932
  # TODO: the two fields below should just be a "StaticBoardConfig" object
933
933
  static_board_config_uuid = field(type=str)
934
934
  board_config = field(type=FrozenBoardConfig)
935
- path_scores = field(type=list) # List[int]
936
- # graph = field(type=int)
937
- # path_scores = field(type=int)
938
- # graph: BoardGraph
939
- # path_scores: List[int]
935
+ carduuid2card = field(type=dict) # Dict[str, Card]
940
936
  def __todict__(self):
941
937
  return {
942
938
  "static_board_config_uuid": self.static_board_config_uuid,
943
939
  "board_config": self.board_config.__todict__(),
944
- "path_scores": self.path_scores,
940
+ "carduuid2card": {k: v.__todict__() for k, v in self.carduuid2card.items()},
945
941
  }
946
942
  @staticmethod
947
943
  def __fromdict__(d):
948
944
  return initfig(
949
945
  d["static_board_config_uuid"],
950
946
  FrozenBoardConfig.__fromdict__(d["board_config"]),
947
+ carduuid2card={k: Card.__fromdict__(v) for k, v in d["carduuid2card"].items()},
951
948
  )
952
949
 
953
950
 
954
951
  @dispatch(str, FrozenBoardConfig)
955
952
  def initfig(static_board_config_uuid, board_config):
953
+ carduuid2card = {}
954
+ for dek in board_config.deks:
955
+ cards = generate_cards(dek)
956
+ for card in cards:
957
+ carduuid2card[card.uuid] = card
956
958
  return Fig(
957
959
  static_board_config_uuid=static_board_config_uuid,
958
960
  board_config=board_config,
959
- path_scores=getfrozenpathscores(board_config),
961
+ carduuid2card=carduuid2card,
960
962
  )
961
963
 
962
964
 
963
- class GameConfig(PClass):
965
+ class PublicGameConfig(PClass):
964
966
  uuid = field(type=str)
965
967
  started_at = field(type=str)
966
968
  num_players = field(type=int)
967
969
  fig = field(type=Fig)
968
- seed = field(type=int)
969
970
  def __todict__(self):
970
971
  return {
971
972
  "uuid": self.uuid,
972
973
  "started_at": self.started_at,
973
974
  "num_players": self.num_players,
974
975
  "fig": self.fig.__todict__(),
975
- "seed": self.seed,
976
976
  }
977
977
  @staticmethod
978
978
  def __fromdict__(d):
979
- return GameConfig(
979
+ return PublicGameConfig(
980
980
  uuid=d["uuid"],
981
981
  started_at=d["started_at"],
982
982
  num_players=d["num_players"],
983
983
  fig=Fig.__fromdict__(d["fig"]),
984
- seed=d["seed"]
985
984
  )
986
-
987
985
 
988
- class PublicGameConfig(PClass):
986
+
987
+ class GameConfig(PClass):
989
988
  uuid = field(type=str)
990
989
  started_at = field(type=str)
991
990
  num_players = field(type=int)
992
991
  fig = field(type=Fig)
992
+ seed = field(type=int)
993
993
  def __todict__(self):
994
994
  return {
995
995
  "uuid": self.uuid,
996
996
  "started_at": self.started_at,
997
997
  "num_players": self.num_players,
998
998
  "fig": self.fig.__todict__(),
999
+ "seed": self.seed,
999
1000
  }
1000
1001
  @staticmethod
1001
1002
  def __fromdict__(d):
1002
- return PublicGameConfig(
1003
+ return GameConfig(
1003
1004
  uuid=d["uuid"],
1004
1005
  started_at=d["started_at"],
1005
1006
  num_players=d["num_players"],
1006
1007
  fig=Fig.__fromdict__(d["fig"]),
1008
+ seed=d["seed"]
1007
1009
  )
1008
1010
 
1009
1011
 
@@ -1161,30 +1163,136 @@ class PrivateState(PClass):
1161
1163
  )
1162
1164
 
1163
1165
 
1166
+ class FaceupCardStack(PClass):
1167
+ cards = field(type=list) # List[Card]
1168
+ def __todict__(self):
1169
+ return {
1170
+ "cards": self.cards,
1171
+ }
1172
+ @staticmethod
1173
+ def __fromdict__(d):
1174
+ return FaceupCardStack(
1175
+ cards=d["cards"],
1176
+ )
1177
+
1178
+
1179
+ class FacedownCardStack(PClass):
1180
+ cards = field(type=list) # List[Card]
1181
+ def __todict__(self):
1182
+ return {
1183
+ "cards": self.cards,
1184
+ }
1185
+ @staticmethod
1186
+ def __fromdict__(d):
1187
+ return FaceupCardStack(
1188
+ cards=d["cards"],
1189
+ )
1190
+
1191
+
1192
+ class PublicFacedownCardStack(PClass):
1193
+ num_cards = field(type=int)
1194
+ def __todict__(self):
1195
+ return {
1196
+ "num_cards": self.num_cards,
1197
+ }
1198
+ @staticmethod
1199
+ def __fromdict__(d):
1200
+ return PublicFacedownCardStack(
1201
+ num_cards=d["num_cards"],
1202
+ )
1203
+
1204
+
1205
+ class FaceupCardSpread(PClass):
1206
+ spots = field(type=list) # List[Card|None]
1207
+ def __todict__(self):
1208
+ return {
1209
+ "spots": self.spots,
1210
+ }
1211
+ @staticmethod
1212
+ def __fromdict__(d):
1213
+ return FaceupCardSpread(
1214
+ spots=d["spots"],
1215
+ )
1216
+
1217
+
1218
+ class FacedownCardSpread(PClass):
1219
+ spots = field(type=list) # List[Card|None]
1220
+ def __todict__(self):
1221
+ return {
1222
+ "spots": self.spots,
1223
+ }
1224
+ @staticmethod
1225
+ def __fromdict__(d):
1226
+ return FacedownCardSpread(
1227
+ spots=d["spots"],
1228
+ )
1229
+
1230
+
1231
+ class PublicFacedownCardSpread(PClass):
1232
+ spots = field(type=list) # List[bool] # True if card is present, False if empty
1233
+ def __todict__(self):
1234
+ return {
1235
+ "spots": self.spots,
1236
+ }
1237
+ @staticmethod
1238
+ def __fromdict__(d):
1239
+ return PublicFacedownCardSpread(
1240
+ spots=d["spots"],
1241
+ )
1242
+
1243
+
1164
1244
  class PublicDeck(PClass):
1165
1245
  idx = field(type=int)
1166
1246
  uuid = field(type=str)
1167
- facedown_stack_len = field(type=int)
1168
- discard_len = field(type=int)
1169
- faceup_spots = field(type=list) # List[Card]
1247
+ all_cards = field(type=list) # List[str]
1248
+ faceup_stack = field(type=(FaceupCardStack, type(None)), initial=None)
1249
+ faceup_spread = field(type=(FaceupCardSpread, type(None)), initial=None)
1250
+ facedown_stack = field(type=(PublicFacedownCardStack, type(None)), initial=None)
1251
+ facedown_spread = field(type=(PublicFacedownCardSpread, type(None)), initial=None)
1252
+ discard_faceup_stack = field(type=(FaceupCardStack, type(None)), initial=None)
1253
+ discard_facedown_stack = field(type=(PublicFacedownCardStack, type(None)), initial=None)
1170
1254
  def __todict__(self):
1171
1255
  return {
1172
1256
  "idx": self.idx,
1173
1257
  "uuid": self.uuid,
1174
- "facedown_stack_len": self.facedown_stack_len,
1175
- "discard_len": self.discard_len,
1176
- "faceup_spots": self.faceup_spots,
1258
+ 'all_cards': self.all_cards,
1259
+ "faceup_stack": self.faceup_stack.__todict__() if self.faceup_stack else None,
1260
+ "faceup_spread": self.faceup_spread.__todict__() if self.faceup_spread else None,
1261
+ "facedown_stack": self.facedown_stack.__todict__() if self.facedown_stack else None,
1262
+ "facedown_spread": self.facedown_spread.__todict__() if self.facedown_spread else None,
1263
+ "discard_faceup_stack": self.discard_faceup_stack.__todict__() if self.discard_faceup_stack else None,
1264
+ "discard_facedown_stack": self.discard_facedown_stack.__todict__() if self.discard_facedown_stack else None,
1177
1265
  }
1178
1266
  @staticmethod
1179
1267
  def __fromdict__(d):
1180
1268
  return PublicDeck(
1181
1269
  idx=d["idx"],
1182
1270
  uuid=d["uuid"],
1183
- facedown_stack_len=d["facedown_stack_len"],
1184
- discard_len=d["discard_len"],
1185
- faceup_spots=d["faceup_spots"],
1271
+ all_cards=d["all_cards"],
1272
+ faceup_stack=FaceupCardStack.__fromdict__(d["faceup_stack"]) if d.get("faceup_stack") else None,
1273
+ faceup_spread=FaceupCardSpread.__fromdict__(d["faceup_spread"]) if d.get("faceup_spread") else None,
1274
+ facedown_stack=PublicFacedownCardStack.__fromdict__(d["facedown_stack"]) if d.get("facedown_stack") else None,
1275
+ facedown_spread=PublicFacedownCardSpread.__fromdict__(d["facedown_spread"]) if d.get("facedown_spread") else None,
1276
+ discard_faceup_stack=FaceupCardStack.__fromdict__(d["discard_faceup_stack"]) if d.get("discard_faceup_stack") else None,
1277
+ discard_facedown_stack=PublicFacedownCardStack.__fromdict__(d["discard_facedown_stack"]) if d.get("discard_facedown_stack") else None,
1186
1278
  )
1187
1279
 
1280
+ def print_public_deck_stats(deck):
1281
+ print("Deck idx:", deck.idx)
1282
+ print("Total cards in deck:", len(deck.all_cards))
1283
+ if deck.faceup_stack:
1284
+ print("Faceup stack cards:", len(deck.faceup_stack.cards))
1285
+ if deck.faceup_spread:
1286
+ print("Faceup spread cards:", sum(1 for card in deck.faceup_spread.spots if card is not None))
1287
+ if deck.facedown_stack:
1288
+ print("Facedown stack cards:", deck.facedown_stack.num_cards)
1289
+ if deck.facedown_spread:
1290
+ print("Facedown spread cards:", sum(1 for present in deck.facedown_spread.spots if present))
1291
+ if deck.discard_faceup_stack:
1292
+ print("Discard faceup stack cards:", len(deck.discard_faceup_stack.cards))
1293
+ if deck.discard_facedown_stack:
1294
+ print("Discard facedown stack cards:", deck.discard_facedown_stack.num_cards)
1295
+
1188
1296
 
1189
1297
  class LegalActionKeep(PClass):
1190
1298
  deck_idx = field(type=int)
@@ -1207,15 +1315,7 @@ class LegalActionKeep(PClass):
1207
1315
  )
1208
1316
  @staticmethod
1209
1317
  def get_default_action(legal_action, state, submitted_at):
1210
- discard_tray = state.players[legal_action.player_idx].discard_tray
1211
- deck_idx = legal_action.keep.deck_idx
1212
- card_uuids_matching_deck = [
1213
- card_uuid for card_uuid in discard_tray
1214
- if state.kernel.carduuid2deckidx[card_uuid] == deck_idx
1215
- ]
1216
- num_cards = len(card_uuids_matching_deck)
1217
1318
  actual_min = 0 if legal_action.keep.min is None else legal_action.keep.min
1218
- # actual_max = num_cards if legal_action.keep.max is None else min(legal_action.keep.max, num_cards)
1219
1319
  return Action2(
1220
1320
  submitted_at=submitted_at,
1221
1321
  legal_action=legal_action,
@@ -1246,22 +1346,12 @@ class LegalActionDiscard(PClass):
1246
1346
  )
1247
1347
  @staticmethod
1248
1348
  def get_default_action(legal_action, state, submitted_at):
1249
- discard_tray = state.players[legal_action.player_idx].discard_tray
1250
- deck_idx = legal_action.discard.deck_idx
1251
- card_uuids_matching_deck = [
1252
- card_uuid for card_uuid in discard_tray
1253
- if state.kernel.carduuid2deckidx[card_uuid] == deck_idx
1254
- ]
1255
- num_cards = len(card_uuids_matching_deck)
1256
1349
  actual_min = 0 if legal_action.discard.min is None else legal_action.discard.min
1257
- actual_max = num_cards if legal_action.discard.max is None else min(legal_action.discard.max, num_cards)
1258
- rand_num_chosen = state.kernel.rng.randint(actual_min, actual_max)
1259
- card_uuids = card_uuids_matching_deck[0:rand_num_chosen]
1260
1350
  return Action2(
1261
1351
  submitted_at=submitted_at,
1262
1352
  legal_action=legal_action,
1263
1353
  discard=ActionDiscard(
1264
- card_uuids=card_uuids
1354
+ discard_tray_idxs=list(range(actual_min)),
1265
1355
  )
1266
1356
  )
1267
1357
 
@@ -1663,52 +1753,21 @@ class Action2(PClass):
1663
1753
  )
1664
1754
 
1665
1755
 
1666
- class CardStack(PClass):
1667
- hidden = field(type=bool)
1668
- cards = field(type=list) # List[Card]
1669
- def __todict__(self):
1670
- return {
1671
- "hidden": self.hidden,
1672
- "cards": self.cards,
1673
- }
1674
- @staticmethod
1675
- def __fromdict__(d):
1676
- return CardStack(
1677
- hidden=d["hidden"],
1678
- cards=d["cards"],
1679
- )
1680
-
1681
-
1682
- class CardSpread(PClass):
1683
- hidden = field(type=bool)
1684
- spots = field(type=list) # List[Card|None]
1685
- def __todict__(self):
1686
- return {
1687
- "hidden": self.hidden,
1688
- "spots": self.spots,
1689
- }
1690
- @staticmethod
1691
- def __fromdict__(d):
1692
- return CardSpread(
1693
- hidden=d["hidden"],
1694
- spots=d["spots"],
1695
- )
1696
-
1697
-
1698
-
1699
1756
  class Deck(PClass):
1700
1757
  idx = field(type=int)
1701
1758
  uuid = field(type=str)
1702
- faceup_stack = field(type=(CardStack, type(None)), initial=None)
1703
- faceup_spread = field(type=(CardSpread, type(None)), initial=None)
1704
- facedown_stack = field(type=(CardStack, type(None)), initial=None)
1705
- facedown_spread = field(type=(CardSpread, type(None)), initial=None)
1706
- discard_faceup_stack = field(type=(CardStack, type(None)), initial=None)
1707
- discard_facedown_stack = field(type=(CardStack, type(None)), initial=None)
1759
+ all_cards = field(type=list) # List[str]
1760
+ faceup_stack = field(type=(FaceupCardStack, type(None)), initial=None)
1761
+ faceup_spread = field(type=(FaceupCardSpread, type(None)), initial=None)
1762
+ facedown_stack = field(type=(FacedownCardStack, type(None)), initial=None)
1763
+ facedown_spread = field(type=(FacedownCardSpread, type(None)), initial=None)
1764
+ discard_faceup_stack = field(type=(FaceupCardStack, type(None)), initial=None)
1765
+ discard_facedown_stack = field(type=(FacedownCardStack, type(None)), initial=None)
1708
1766
  def __todict__(self):
1709
1767
  return {
1710
1768
  "idx": self.idx,
1711
1769
  "uuid": self.uuid,
1770
+ 'all_cards': self.all_cards,
1712
1771
  "faceup_stack": self.faceup_stack.__todict__() if self.faceup_stack else None,
1713
1772
  "faceup_spread": self.faceup_spread.__todict__() if self.faceup_spread else None,
1714
1773
  "facedown_stack": self.facedown_stack.__todict__() if self.facedown_stack else None,
@@ -1721,28 +1780,32 @@ class Deck(PClass):
1721
1780
  return Deck(
1722
1781
  idx=d["idx"],
1723
1782
  uuid=d["uuid"],
1724
- faceup_stack=CardStack.__fromdict__(d["faceup_stack"]) if d.get("faceup_stack") else None,
1725
- faceup_spread=CardSpread.__fromdict__(d["faceup_spread"]) if d.get("faceup_spread") else None,
1726
- facedown_stack=CardStack.__fromdict__(d["facedown_stack"]) if d.get("facedown_stack") else None,
1727
- facedown_spread=CardSpread.__fromdict__(d["facedown_spread"]) if d.get("facedown_spread") else None,
1728
- discard_faceup_stack=CardStack.__fromdict__(d["discard_faceup_stack"]) if d.get("discard_faceup_stack") else None,
1729
- discard_facedown_stack=CardStack.__fromdict__(d["discard_facedown_stack"]) if d.get("discard_facedown_stack") else None,
1783
+ all_cards=d["all_cards"],
1784
+ faceup_stack=FaceupCardStack.__fromdict__(d["faceup_stack"]) if d.get("faceup_stack") else None,
1785
+ faceup_spread=FaceupCardSpread.__fromdict__(d["faceup_spread"]) if d.get("faceup_spread") else None,
1786
+ facedown_stack=FaceupCardStack.__fromdict__(d["facedown_stack"]) if d.get("facedown_stack") else None,
1787
+ facedown_spread=FaceupCardSpread.__fromdict__(d["facedown_spread"]) if d.get("facedown_spread") else None,
1788
+ discard_faceup_stack=FaceupCardStack.__fromdict__(d["discard_faceup_stack"]) if d.get("discard_faceup_stack") else None,
1789
+ discard_facedown_stack=FaceupCardStack.__fromdict__(d["discard_facedown_stack"]) if d.get("discard_facedown_stack") else None,
1730
1790
  )
1731
1791
 
1732
1792
 
1733
1793
  class CandidateDeck(PClass):
1734
1794
  deck_idx = field(type=int)
1735
- candidates = field(type=list) # List[Card]
1795
+ candidates = field(type=list) # List[str]
1796
+ notes = field(type=list) # List[str]
1736
1797
  def __todict__(self):
1737
1798
  return {
1738
1799
  'deck_idx': self.deck_idx,
1739
- 'candidates': [card.__todict__() for card in self.candidates],
1800
+ 'candidates': self.candidates,
1801
+ 'notes': self.notes,
1740
1802
  }
1741
1803
  @staticmethod
1742
1804
  def __fromdict__(d):
1743
1805
  return CandidateDeck(
1744
1806
  deck_idx=d["deck_idx"],
1745
- candidates=[Card.__fromdict__(card) for card in d["candidates"]],
1807
+ candidates=d["candidates"],
1808
+ notes=d["notes"],
1746
1809
  )
1747
1810
 
1748
1811
 
@@ -2134,12 +2197,9 @@ class StateKernel(PClass):
2134
2197
  history = field(type=list) # List[Action2]
2135
2198
  pieceuuid2piece = field(type=dict) # Dict[str, Piece]
2136
2199
  edgeuuid2idx = field(type=dict) # Dict[str, int]
2137
- carduuid2card = field(type=dict) # Dict[str, Card]
2138
2200
  edgetuple2uuid = field(type=dict) # Dict[Tuple[int, int], str]
2139
2201
  nodeuuid2idx = field(type=dict) # Dict[str, int]
2140
- carduuid2deckidx = field(type=dict) # Dict[str, int]
2141
2202
  bonusuuid2bonusidx = field(type=dict) # Dict[str, int]
2142
- starting_decks = field(type=list) # List[Deck]
2143
2203
  starting_piles = field(type=list) # List[Pile]
2144
2204
  goals = field(type=list) # List[FrozenGoal]
2145
2205
  last_to_play = field(type=(int, type(None)), initial=None)
@@ -2161,12 +2221,9 @@ class StateKernel(PClass):
2161
2221
  "idx2pathrecord": [v.__todict__() for v in self.idx2pathrecord],
2162
2222
  "pieceuuid2piece": {k: v.__todict__() for k, v in self.pieceuuid2piece.items()},
2163
2223
  "edgeuuid2idx": self.edgeuuid2idx,
2164
- "carduuid2card": {k: v.__todict__() for k, v in self.carduuid2card.items()},
2165
2224
  "edgetuple2uuid": [{"k": list(k), "v": v} for k, v in self.edgetuple2uuid.items()],
2166
2225
  "nodeuuid2idx": self.nodeuuid2idx,
2167
- "carduuid2deckidx": self.carduuid2deckidx,
2168
2226
  "bonusuuid2bonusidx": self.bonusuuid2bonusidx,
2169
- "starting_decks": [deck.__todict__() for deck in self.starting_decks],
2170
2227
  "starting_piles": [pile.__todict__() for pile in self.starting_piles],
2171
2228
  "goals": [goal.__todict__() for goal in self.goals],
2172
2229
  "last_to_play": self.last_to_play,
@@ -2190,12 +2247,9 @@ class StateKernel(PClass):
2190
2247
  idx2pathrecord=[Path2.__fromdict(v) for v in d["idx2pathrecord"]],
2191
2248
  pieceuuid2piece={k: Piece.__fromdict(v) for k, v in d["pieceuuid2piece"].items()},
2192
2249
  edgeuuid2idx=d["edgeuuid2idx"],
2193
- carduuid2card={k: Card.__fromdict(v) for k, v in d["carduuid2card"].items()},
2194
2250
  edgetuple2uuid={tuple(item["k"]): item["v"] for item in d["edgetuple2uuid"]},
2195
2251
  nodeuuid2idx=d["nodeuuid2idx"],
2196
- carduuid2deckidx=d["carduuid2deckidx"],
2197
2252
  bonusuuid2bonusidx=d["bonusuuid2bonusidx"],
2198
- starting_decks=[Deck.__fromdict__(x) for x in d["starting_decks"]],
2199
2253
  starting_piles=[Pile.__fromdict__(x) for x in d["starting_piles"]],
2200
2254
  goals=[FrozenGoal.__fromdict__(goal) for goal in d["goals"]],
2201
2255
  last_to_play=d.get("last_to_play"),
@@ -2225,14 +2279,6 @@ def init_state_kernel(game_config, **kwargs):
2225
2279
  for piece in pieces:
2226
2280
  pieceuuid2piece[piece.uuid] = piece
2227
2281
 
2228
- carduuid2deckidx = {}
2229
- carduuid2card = {}
2230
- for dek in board_config.deks:
2231
- cards = generate_cards(dek)
2232
- for card in cards:
2233
- carduuid2card[card.uuid] = card
2234
- carduuid2deckidx[card.uuid] = dek.idx
2235
-
2236
2282
  starting_piles = []
2237
2283
  for piece_template in board_config.piece_templates:
2238
2284
  if piece_template.has_player:
@@ -2263,12 +2309,15 @@ def init_state_kernel(game_config, **kwargs):
2263
2309
  starting_decks = []
2264
2310
  for dek in board_config.deks:
2265
2311
  cards = generate_cards(dek)
2312
+ all_card_uuids = [c.uuid for c in cards]
2266
2313
  deck_obj = Deck(
2267
2314
  uuid=dek.uuid,
2268
2315
  idx=dek.idx,
2269
- facedown_stack=CardStack(hidden=True, cards=[c.uuid for c in cards]),
2270
- faceup_spread=CardSpread(hidden=False, spots=[]),
2271
- discard_faceup_stack=CardStack(hidden=False, cards=[]),
2316
+ all_cards=all_card_uuids,
2317
+ facedown_stack=FacedownCardStack(cards=all_card_uuids),
2318
+ faceup_spread=FaceupCardSpread(spots=[]),
2319
+ discard_faceup_stack=FaceupCardStack(cards=[]),
2320
+ discard_facedown_stack=FacedownCardStack(cards=[]),
2272
2321
  )
2273
2322
  starting_decks.append(deck_obj)
2274
2323
 
@@ -2291,13 +2340,10 @@ def init_state_kernel(game_config, **kwargs):
2291
2340
  uuid2segmentrecord=uuid2segmentrecord,
2292
2341
  idx2pathrecord=idx2pathrecord,
2293
2342
  edgeuuid2idx=edgeuuid2idx,
2294
- carduuid2card=carduuid2card,
2295
2343
  pieceuuid2piece=pieceuuid2piece,
2296
2344
  edgetuple2uuid=edgetuple2uuid,
2297
2345
  nodeuuid2idx=nodeuuid2idx,
2298
- carduuid2deckidx=carduuid2deckidx,
2299
2346
  bonusuuid2bonusidx=bonusuuid2bonusidx,
2300
- starting_decks=starting_decks,
2301
2347
  starting_piles=starting_piles,
2302
2348
  goals=goals,
2303
2349
  player_graphs_3=player_graphs_3,
@@ -2565,14 +2611,12 @@ class RemainingAllottedTime(PClass):
2565
2611
 
2566
2612
 
2567
2613
  class PublicState(PClass):
2568
- game_config = field(type=PublicGameConfig)
2569
2614
  deadlines = field(type=list) # List[RemainingAllottedTime|None]
2570
2615
  game_started_at = field(type=str)
2571
2616
  allotted_times = field(type=list)
2572
2617
  all_pieces = field(type=list) # List[Piece]
2573
2618
  to_play_2 = field(type=list) # List[int]
2574
2619
  bonus_statuses = field(type=list) # List[BonusStatus]
2575
- starting_decks = field(type=list) # List[Deck]
2576
2620
  starting_piles = field(type=list) # List[Pile]
2577
2621
  history = field(type=list) # List[PublicAction]
2578
2622
  player_scores = field(type=list) # List[PublicPlayerScore]
@@ -2590,14 +2634,12 @@ class PublicState(PClass):
2590
2634
  terminal = field(type=bool)
2591
2635
  def __todict__(self):
2592
2636
  return {
2593
- "game_config": self.game_config.__todict__(),
2594
2637
  "deadlines": [deadline.__todict__() if deadline else None for deadline in self.deadlines],
2595
2638
  "game_started_at": self.game_started_at,
2596
2639
  "allotted_times": [allotted_time.__todict__() if allotted_time else None for allotted_time in self.allotted_times], # List[AllottedTime|None]
2597
2640
  "all_pieces": [piece.__todict__() for piece in self.all_pieces],
2598
2641
  "to_play_2": self.to_play_2,
2599
2642
  "bonus_statuses": [bs.__todict__() for bs in self.bonus_statuses],
2600
- "starting_decks": [deck.__todict__() for deck in self.starting_decks],
2601
2643
  "starting_piles": [pile.__todict__() for pile in self.starting_piles],
2602
2644
  "history": [x.__todict__() for x in self.history],
2603
2645
  "player_scores": [x.__todict__() for x in self.player_scores],
@@ -2617,14 +2659,12 @@ class PublicState(PClass):
2617
2659
  @staticmethod
2618
2660
  def __fromdict__(d):
2619
2661
  return PublicState(
2620
- game_config=PublicGameConfig.__fromdict__(d["game_config"]),
2621
2662
  deadlines=[RemainingAllottedTime.__fromdict__(x) for x in d["deadlines"]],
2622
2663
  game_started_at=d["game_started_at"],
2623
2664
  allotted_times=[AllottedTime.__fromdict__(x) if x else None for x in d["allotted_times"]], # List[AllottedTime|None]
2624
2665
  all_pieces=[Piece.__fromdict__(x) for x in d["all_pieces"]],
2625
2666
  to_play_2=d["to_play_2"],
2626
2667
  bonus_statuses=[BonusStatus.__fromdict__(x) for x in d["bonus_statuses"]],
2627
- starting_decks=[Deck.__fromdict__(x) for x in d["starting_decks"]],
2628
2668
  starting_piles=[Pile.__fromdict__(x) for x in d["starting_piles"]],
2629
2669
  history=[PublicAction.__fromdict__(x) for x in d["history"]],
2630
2670
  player_scores=[PublicPlayerScore.__fromdict__(x) for x in d["player_scores"]],
@@ -2644,16 +2684,19 @@ class PublicState(PClass):
2644
2684
 
2645
2685
 
2646
2686
  class PlayerState(PClass):
2687
+ game_config = field(type=PublicGameConfig)
2647
2688
  public = field(type=PublicState)
2648
2689
  private = field(type=PrivateState)
2649
2690
  def __todict__(self):
2650
2691
  return {
2692
+ "game_config": self.game_config.__todict__(),
2651
2693
  "public": self.public.__todict__(),
2652
2694
  "private": self.private.__todict__()
2653
2695
  }
2654
2696
  @staticmethod
2655
2697
  def __fromdict__(d):
2656
2698
  return PlayerState(
2699
+ game_config=PublicGameConfig.__fromdict__(d["game_config"]),
2657
2700
  public=PublicState.__fromdict__(d["public"]),
2658
2701
  private=PrivateState.__fromdict__(d["private"])
2659
2702
  )
@@ -3264,11 +3307,12 @@ def replenish_faceup_if_needed(kernel, deck_idx):
3264
3307
  def recycle_if_needed(kernel, deck_idx):
3265
3308
  deck = kernel.decks[deck_idx]
3266
3309
  if len(deck.facedown_stack.cards) == 0:
3267
- shuffled_discards = list(deck.discard_faceup_stack.cards)
3310
+ shuffled_discards = list(deck.discard_faceup_stack.cards) + list(deck.discard_facedown_stack.cards)
3268
3311
  kernel.rng.shuffle(shuffled_discards)
3269
3312
  deck = deck.set(
3270
- facedown_stack=CardStack(hidden=True, cards=shuffled_discards),
3271
- discard_faceup_stack=CardStack(hidden=False, cards=[])
3313
+ facedown_stack=FacedownCardStack(cards=shuffled_discards),
3314
+ discard_faceup_stack=FaceupCardStack(cards=[]),
3315
+ discard_facedown_stack=FacedownCardStack(cards=[]),
3272
3316
  )
3273
3317
  kernel = set_deck(kernel, deck.idx, deck)
3274
3318
  return kernel
@@ -3350,7 +3394,7 @@ def get_follow_up_draw_legal_actions(kernel, action):
3350
3394
 
3351
3395
  for card_uuid in kernel.decks[0].faceup_spread.spots:
3352
3396
  if card_uuid:
3353
- if not kernel.carduuid2card[card_uuid].is_wild:
3397
+ if not kernel.game_config.fig.carduuid2card[card_uuid].is_wild:
3354
3398
  to_return.append(
3355
3399
  LegalAction(
3356
3400
  player_idx=legal_action.player_idx,
@@ -3374,7 +3418,7 @@ def get_num_faceup_wilds(kernel, deck_idx):
3374
3418
  non_empty_spots = [spot for spot in deck.faceup_spread.spots if spot]
3375
3419
  if not non_empty_spots:
3376
3420
  return 0
3377
- return sum(1 for card_uuid in non_empty_spots if kernel.carduuid2card[card_uuid].is_wild)
3421
+ return sum(1 for card_uuid in non_empty_spots if kernel.game_config.fig.carduuid2card[card_uuid].is_wild)
3378
3422
 
3379
3423
 
3380
3424
  @dispatch(StateKernel)
@@ -3395,10 +3439,15 @@ def discardfaceup_shuffle_flip(kernel, deck_idx):
3395
3439
  for faceup_spot in deck.faceup_spread.spots:
3396
3440
  if faceup_spot:
3397
3441
  deck.discard_faceup_stack.cards.append(faceup_spot)
3398
- deck = deck.set(faceup_spread=CardStack(hidden=False, cards=[]))
3442
+ deck = deck.set(faceup_spread=FaceupCardStack(cards=[]))
3399
3443
  while len(deck.discard_faceup_stack.cards) > 0:
3400
- card = deck.discard_faceup_stack.cards.pop()
3401
- deck.facedown_stack.cards.append(card)
3444
+ deck.facedown_stack.cards.append(
3445
+ deck.discard_faceup_stack.cards.pop()
3446
+ )
3447
+ while len(deck.discard_facedown_stack.cards) > 0:
3448
+ deck.facedown_stack.cards.append(
3449
+ deck.discard_facedown_stack.cards.pop()
3450
+ )
3402
3451
  deck = shuffle(kernel.rng, deck)
3403
3452
  kernel = set_deck(kernel, deck.idx, deck)
3404
3453
  kernel = flip_cards(kernel, deck.idx, num_faceup_spots)
@@ -3423,7 +3472,7 @@ def handle_faceup_draw_action(kernel, action):
3423
3472
  kernel = replenish_faceup_spot_if_needed(kernel, faceup_draw.deck_idx, spot_idx)
3424
3473
 
3425
3474
  # Prevent an extra draw if last draw was a face-wild-draw
3426
- # if not game.kernel.carduuid2card[drawn_card].is_wild:
3475
+ # if not game.kernel.game_config.fig.carduuid2card[drawn_card].is_wild:
3427
3476
  # # TODO: extract this out to user-defined function/hook
3428
3477
  # game = append_follow_up_draw_legal_actions(game, action)
3429
3478
 
@@ -3643,7 +3692,7 @@ def handle_move_longest_path_card(kernel, action):
3643
3692
  player_with_card = find_player_with_longest_path_card(kernel)
3644
3693
  if player_with_card:
3645
3694
  # Find the index of the card from the player's cards, then pop it
3646
- card_idx = next((i for i, card_uuid in enumerate(player_with_card.cards) if kernel.carduuid2card[card_uuid].deck_idx == 2), None)
3695
+ card_idx = next((i for i, card_uuid in enumerate(player_with_card.cards) if kernel.game_config.fig.carduuid2card[card_uuid].deck_idx == 2), None)
3647
3696
  if card_idx is not None:
3648
3697
  longest_path_card = player_with_card.cards.pop(card_idx)
3649
3698
 
@@ -3659,7 +3708,7 @@ def handle_move_longest_path_card(kernel, action):
3659
3708
 
3660
3709
  def find_player_with_longest_path_card(game):
3661
3710
  for player in game.players:
3662
- if any(game.kernel.carduuid2card[card_uuid].deck_idx == 2 for card_uuid in player.cards):
3711
+ if any(game.kernel.game_config.fig.carduuid2card[card_uuid].deck_idx == 2 for card_uuid in player.cards):
3663
3712
  return player
3664
3713
  return None
3665
3714
 
@@ -3703,7 +3752,7 @@ def handle_move_pieces_to_path_action(kernel, action):
3703
3752
  # Remove the card from player's cards
3704
3753
  card_uuid = player.cards.pop(card_idx)
3705
3754
  # add to discard
3706
- kernel.decks[kernel.carduuid2card[card_uuid].deck_idx].discard_faceup_stack.cards.append(card_uuid)
3755
+ kernel.decks[kernel.game_config.fig.carduuid2card[card_uuid].deck_idx].discard_faceup_stack.cards.append(card_uuid)
3707
3756
 
3708
3757
  kernel = recycle_decks_if_needed(kernel)
3709
3758
  kernel = replenish_decks_if_needed(kernel)
@@ -3799,7 +3848,7 @@ def handle_keep_action(kernel, action):
3799
3848
  non_kept_cards.append(card_uuid)
3800
3849
 
3801
3850
  # Discard the non-kept cards to the deck's discard pile
3802
- deck.discard_faceup_stack.cards.extend(non_kept_cards)
3851
+ deck.discard_facedown_stack.cards.extend(non_kept_cards)
3803
3852
 
3804
3853
  # Clear the discard tray and add the kept cards back
3805
3854
  player.cards.extend([c for c in kept_cards if c is not None])
@@ -3846,7 +3895,7 @@ def handle_discard_action(kernel, action):
3846
3895
  print("****************************** handle_discard_action 6", non_kept_cards)
3847
3896
 
3848
3897
  # Discard the non-kept cards to the deck's discard pile
3849
- deck.discard_faceup_stack.cards.extend(non_kept_cards)
3898
+ deck.discard_facedown_stack.cards.extend(non_kept_cards)
3850
3899
 
3851
3900
  # Clear the discard tray and add the kept cards back
3852
3901
  player.cards.extend([c for c in kept_cards if c is not None])
@@ -3877,7 +3926,7 @@ def set_deck(kernel, deck_idx, deck):
3877
3926
  def shuffle(rng, deck):
3878
3927
  shuffled_cards = list(deck.facedown_stack.cards)
3879
3928
  rng.shuffle(shuffled_cards)
3880
- return deck.set(facedown_stack=CardStack(hidden=True, cards=shuffled_cards))
3929
+ return deck.set(facedown_stack=FacedownCardStack(cards=shuffled_cards))
3881
3930
 
3882
3931
 
3883
3932
  @dispatch(StateKernel, int)
@@ -4172,7 +4221,7 @@ HOOK_NAMESPACE = {
4172
4221
  @dispatch(StateKernel)
4173
4222
  def get_wild_unit_uuids(state_kernel):
4174
4223
  wild_unit_uuids = []
4175
- for card in state_kernel.carduuid2card.values():
4224
+ for card in state_kernel.game_config.fig.carduuid2card.values():
4176
4225
  if card.is_wild:
4177
4226
  wild_unit_uuids.append(card.resource_uuid)
4178
4227
  return wild_unit_uuids
@@ -4187,7 +4236,7 @@ def match_strict_wild(state_kernel, fulfillment, cards, segment_records):
4187
4236
 
4188
4237
  for segment_record in segment_records:
4189
4238
  if segment_record.unit_uuid and segment_record.unit_uuid in wild_unit_uuids:
4190
- first_matching_idx = next((i for i, card_uuid in enumerate(new_cards) if state_kernel.carduuid2card[card_uuid].resource_uuid == segment_record.unit_uuid), None)
4239
+ first_matching_idx = next((i for i, card_uuid in enumerate(new_cards) if state_kernel.game_config.fig.carduuid2card[card_uuid].resource_uuid == segment_record.unit_uuid), None)
4191
4240
  if first_matching_idx is not None:
4192
4241
  new_fulfillment.append(new_cards.pop(first_matching_idx))
4193
4242
  else:
@@ -4205,8 +4254,8 @@ def match_non_wild_non_empty(state_kernel, fulfillment, cards, segment_records):
4205
4254
  new_segment_records = []
4206
4255
 
4207
4256
  for segment_record in segment_records:
4208
- first_strict_matching_idx = next((i for i, card_uuid in enumerate(new_cards) if state_kernel.carduuid2card[card_uuid].resource_uuid == segment_record.unit_uuid), None)
4209
- first_wild_matching_idx = next((i for i, card_uuid in enumerate(new_cards) if state_kernel.carduuid2card[card_uuid].resource_uuid in wild_unit_uuids), None)
4257
+ first_strict_matching_idx = next((i for i, card_uuid in enumerate(new_cards) if state_kernel.game_config.fig.carduuid2card[card_uuid].resource_uuid == segment_record.unit_uuid), None)
4258
+ first_wild_matching_idx = next((i for i, card_uuid in enumerate(new_cards) if state_kernel.game_config.fig.carduuid2card[card_uuid].resource_uuid in wild_unit_uuids), None)
4210
4259
  first_matching_idx = first_strict_matching_idx if first_strict_matching_idx is not None else first_wild_matching_idx
4211
4260
  if first_matching_idx is not None:
4212
4261
  new_fulfillment.append(new_cards.pop(first_matching_idx))
@@ -4245,14 +4294,14 @@ def match_empty(state_kernel, fulfillment, cards, segment_records):
4245
4294
 
4246
4295
  @dispatch(StateKernel, list, int)
4247
4296
  def get_uniform_sets(state_kernel, cards, min_length):
4248
- wilds = [card_uuid for card_uuid in cards if state_kernel.carduuid2card[card_uuid].is_wild]
4249
- non_wilds = [card_uuid for card_uuid in cards if not state_kernel.carduuid2card[card_uuid].is_wild]
4297
+ wilds = [card_uuid for card_uuid in cards if state_kernel.game_config.fig.carduuid2card[card_uuid].is_wild]
4298
+ non_wilds = [card_uuid for card_uuid in cards if not state_kernel.game_config.fig.carduuid2card[card_uuid].is_wild]
4250
4299
  # print("********************* cards: ", cards)
4251
4300
  # print("********************* wilds: ", wilds)
4252
4301
  # print("********************* non_wilds: ", non_wilds)
4253
4302
  unit_uuid_2_cards = {}
4254
4303
  for card_uuid in non_wilds:
4255
- card = state_kernel.carduuid2card[card_uuid]
4304
+ card = state_kernel.game_config.fig.carduuid2card[card_uuid]
4256
4305
  if card.resource_uuid not in unit_uuid_2_cards:
4257
4306
  unit_uuid_2_cards[card.resource_uuid] = []
4258
4307
  unit_uuid_2_cards[card.resource_uuid].append(card_uuid)
@@ -4301,7 +4350,7 @@ def get_sample_actionclaimpath(game, player_idx, path_idx):
4301
4350
  @dispatch(StateKernel, int, int)
4302
4351
  def get_sample_path_fulfillment(kernel, player_idx, path_idx):
4303
4352
  path_record = kernel.idx2pathrecord[path_idx]
4304
- remaining_card_uuids = [card_uuid for card_uuid in kernel.players[player_idx].cards if kernel.carduuid2card[card_uuid].deck_idx == 0]
4353
+ remaining_card_uuids = [card_uuid for card_uuid in kernel.players[player_idx].cards if kernel.game_config.fig.carduuid2card[card_uuid].deck_idx == 0]
4305
4354
  remaining_pieces = [
4306
4355
  piece_uuid
4307
4356
  for piece_uuid in kernel.players[player_idx].pieces
@@ -4503,7 +4552,7 @@ def calc_legal_actions3(state_kernel):
4503
4552
 
4504
4553
  elif last_action.legal_action.faceup_draw:
4505
4554
  faceup_draw = last_action.legal_action.faceup_draw
4506
- if not state_kernel.carduuid2card[faceup_draw.card_uuid].is_wild:
4555
+ if not state_kernel.game_config.fig.carduuid2card[faceup_draw.card_uuid].is_wild:
4507
4556
  legal_actions = get_follow_up_draw_legal_actions(state_kernel, last_action)
4508
4557
  if legal_actions:
4509
4558
  return legal_actions
@@ -4647,7 +4696,6 @@ def get_public_player_scores(s):
4647
4696
  # all_pieces = field(type=list) # List[Piece]
4648
4697
  # to_play_2 = field(type=list) # List[int]
4649
4698
  # bonus_statuses = field(type=list) # List[BonusStatus]
4650
- # starting_decks = field(type=list) # List[Deck]
4651
4699
  # starting_piles = field(type=list) # List[Pile]
4652
4700
  # history = field(type=list) # List[PublicAction]
4653
4701
  # player_scores = field(type=list) # List[PublicPlayerScore]
@@ -4670,24 +4718,69 @@ def get_public_player_scores(s):
4670
4718
  # goal_completions = field(type=list, initial=[]) # List[GoalCompletion]
4671
4719
 
4672
4720
 
4673
- def get_public_history(s: State):
4674
- return [action.get_public(s) for action in s.kernel.history]
4721
+ def get_candidate_decks(ps: PlayerState) -> List[CandidateDeck]:
4722
+ candidate_lists = [
4723
+ copy.deepcopy(public_deck.all_cards)
4724
+ for public_deck in ps.public.decks
4725
+ ]
4675
4726
 
4727
+ note_lists = [
4728
+ [f"Deck {deck_idx} started with {len(candidate_deck)} cards"]
4729
+ for deck_idx, candidate_deck in enumerate(candidate_lists)
4730
+ ]
4676
4731
 
4677
- def get_candidate_decks(ps: PlayerState) -> List[CandidateDeck]:
4678
- pass
4732
+ for deck_idx, (public_deck, candidates) in enumerate(zip(ps.public.decks, candidate_lists)):
4733
+ # filter out cards that are faceup
4734
+ spots_to_remove = [card_uuid for card_uuid in public_deck.faceup_spread.spots if card_uuid]
4735
+ for card_uuid in spots_to_remove:
4736
+ if card_uuid:
4737
+ print("************************************ spots_to_remove: ", spots_to_remove)
4738
+ candidates.remove(card_uuid)
4739
+
4740
+ note_lists[deck_idx].append(f"Removed {len(spots_to_remove)} candidates from deck {public_deck.idx} for faceup spots")
4741
+
4742
+ # filter out cards in faceup discard
4743
+ for card_uuid in public_deck.discard_faceup_stack.cards:
4744
+ candidates.remove(card_uuid)
4745
+
4746
+ note_lists[deck_idx].append(f"Removed {len(public_deck.discard_faceup_stack.cards)} candidates from deck {public_deck.idx} for faceup discard")
4747
+
4748
+
4749
+ for card_uuid in ps.private.player.cards:
4750
+ card = ps.game_config.fig.carduuid2card[card_uuid]
4751
+ candidate_lists[card.deck_idx].remove(card_uuid)
4752
+ note_lists[card.deck_idx].append(f"Removed 1 candidate from deck {card.deck_idx} for player hand (for player {ps.private.player.idx})")
4753
+
4754
+ return [
4755
+ CandidateDeck(
4756
+ deck_idx=deck_idx,
4757
+ candidates=candidate_list,
4758
+ notes=note_list + [f"Deck {deck_idx} ends with {len(candidate_list)} cards"]
4759
+ )
4760
+ for deck_idx, (candidate_list, note_list) in enumerate(zip(candidate_lists, note_lists))
4761
+ ]
4679
4762
 
4680
4763
 
4681
4764
  def imagine_player(p_idx: int, ps: PlayerState, candidate_decks: List[CandidateDeck]) -> Player:
4765
+ print(f"imagine_player {p_idx}")
4682
4766
  if ps.private.player.idx == p_idx:
4767
+ print(f"No need to imagine player {p_idx}, returning private player")
4683
4768
  return ps.private.player
4769
+ print(f"len(candidate_decks[0].candidates): ", len(candidate_decks[0].candidates))
4770
+ print(f"public_player.deck_counts: ", ps.public.players[p_idx].deck_counts)
4684
4771
  public_player = ps.public.players[p_idx]
4772
+ print(f"z1")
4685
4773
  cards = []
4774
+ print(f"z2")
4686
4775
  for deck_idx, count in enumerate(public_player.deck_counts):
4776
+ print(f"deck_idx: {deck_idx}, count: {count}")
4687
4777
  candidate_deck = candidate_decks[deck_idx]
4778
+ print(f"len(candidate_deck.candidates) before: {len(candidate_deck.candidates)}")
4688
4779
  for _ in range(count):
4689
4780
  cards.append(candidate_deck.candidates.pop())
4781
+ print(f"len(candidate_deck.candidates) after: {len(candidate_deck.candidates)}")
4690
4782
  discard_tray = []
4783
+ print(f"z4")
4691
4784
  for deck_idx, count in enumerate(public_player.discard_deck_counts):
4692
4785
  candidate_deck = candidate_decks[deck_idx]
4693
4786
  for _ in range(count):
@@ -4709,18 +4802,25 @@ def imagine_players(ps: PlayerState, candidate_decks: List[CandidateDeck]) -> Li
4709
4802
 
4710
4803
 
4711
4804
  def imagine_decks(ps: PlayerState, candidate_decks: List[CandidateDeck]) -> List[Deck]:
4712
- public = ps.public
4805
+ # print("************************************ candidate_decks[1]: ", candidate_decks[1])
4713
4806
  imagined = [
4714
- imagine_deck(public_deck, candidate_deck)
4715
- for public_deck in public.decks
4807
+ imagine_deck(public_deck, candidate_decks[deck_idx])
4808
+ for deck_idx, public_deck in enumerate(ps.public.decks)
4716
4809
  ]
4810
+ # print("************************************ imagined[1]: ", imagined[1])
4717
4811
  return imagined
4718
4812
 
4719
4813
 
4720
4814
  def imagine_deck(public_deck: PublicDeck, candidate_deck: CandidateDeck) -> Deck:
4721
- return Deck(
4815
+ facedown_stack_cards = [
4816
+ candidate_deck.candidates.pop() for _ in range(public_deck.facedown_stack.num_cards)
4817
+ ]
4818
+ print(f"len(facedown_stack_cards) pops for deck_idx [{public_deck.idx}]: ", len(facedown_stack_cards))
4819
+
4820
+ imagined = Deck(
4722
4821
  idx=public_deck.idx,
4723
4822
  uuid=public_deck.uuid,
4823
+ all_cards=copy.deepcopy(public_deck.all_cards),
4724
4824
  faceup_stack=(
4725
4825
  copy.deepcopy(public_deck.faceup_stack)
4726
4826
  if public_deck.faceup_stack else None
@@ -4730,47 +4830,66 @@ def imagine_deck(public_deck: PublicDeck, candidate_deck: CandidateDeck) -> Deck
4730
4830
  if public_deck.faceup_spread else None
4731
4831
  ),
4732
4832
  facedown_stack=(
4733
- CardStack(
4734
- hidden=True,
4735
- cards=[
4736
- candidate_deck.candidates.pop() for _ in range(public_deck.facedown_stack_len)
4737
- ]
4833
+ FacedownCardStack(
4834
+ cards=facedown_stack_cards
4738
4835
  )
4739
- if public_deck.facedown_stack_len > 0 else None
4836
+ if public_deck.facedown_stack else None
4740
4837
  ),
4741
4838
  facedown_spread=(
4742
- CardSpread(
4743
- hidden=True,
4839
+ FacedownCardSpread(
4744
4840
  spots=[
4745
- candidate_deck.candidates.pop() for _ in range(len(public_deck.facedown_spread_len))
4841
+ candidate_deck.candidates.pop() if spot else None
4842
+ for spot in public_deck.facedown_spread.spots
4746
4843
  ]
4747
4844
  )
4748
- if public_deck.facedown_spread_len > 0 else None
4845
+ if public_deck.facedown_spread else None
4749
4846
  ),
4750
4847
  discard_faceup_stack=(
4751
4848
  copy.deepcopy(public_deck.discard_faceup_stack)
4752
4849
  if public_deck.discard_faceup_stack else None
4753
4850
  ),
4754
4851
  discard_facedown_stack=(
4755
- CardStack(
4756
- hidden=True,
4852
+ FacedownCardStack(
4757
4853
  cards=[
4758
- candidate_deck.candidates.pop() for _ in range(public_deck.discard_facedown_stack_len)
4854
+ candidate_deck.candidates.pop() for _ in range(public_deck.discard_facedown_stack.num_cards)
4759
4855
  ]
4760
4856
  )
4761
- if public_deck.discard_facedown_stack_len > 0 else None
4857
+ if public_deck.discard_facedown_stack else None
4762
4858
  ),
4763
4859
  )
4764
4860
 
4861
+ # print("************************************ public_deck.facedown_stack 10: ", public_deck.facedown_stack)
4862
+ # print("************************************ imagined.facedown_stack: ", imagined.facedown_stack)
4863
+
4864
+ return imagined
4865
+
4765
4866
 
4766
4867
  @dispatch(PlayerState)
4767
- def imagine_state(ps):
4868
+ def imagine_state(ps: PlayerState) -> State:
4768
4869
  public = ps.public
4769
- game_config = public.game_config
4870
+ game_config = ps.game_config
4770
4871
 
4771
4872
  candidate_decks = get_candidate_decks(ps)
4873
+
4874
+ print_public_deck_stats(ps.public.decks[0])
4875
+
4876
+ print("\n")
4877
+ print("************************************ candidate_decks[1].notes a: ", candidate_decks[1].notes)
4878
+ print("************************************ len(candidate_decks[1].candidates) a: ", len(candidate_decks[1].candidates))
4879
+ print("\n")
4880
+
4772
4881
  imagined_decks = imagine_decks(ps, candidate_decks)
4882
+
4883
+ print("\n")
4884
+ print("************************************ len(candidate_decks[1].candidates) b: ", len(candidate_decks[1].candidates))
4885
+ print("player deck[1] counts: ", [public_player.deck_counts[1] for public_player in ps.public.players])
4886
+ print("\n")
4887
+
4773
4888
  imagined_players = imagine_players(ps, candidate_decks)
4889
+
4890
+ print("\n")
4891
+ print("************************************ len(candidate_decks[1].candidates) c: ", len(candidate_decks[1].candidates))
4892
+ print("\n")
4774
4893
 
4775
4894
  imagined_kernel = init_state_kernel(
4776
4895
  GameConfig(
@@ -4843,16 +4962,14 @@ def getpublicstate(s):
4843
4962
 
4844
4963
 
4845
4964
  return PublicState(
4846
- game_config=getpublicgameconfig(s.kernel.game_config),
4847
4965
  deadlines=get_deadlines(s),
4848
4966
  game_started_at=s.kernel.game_config.started_at,
4849
4967
  allotted_times=get_max_allotted_times(s),
4850
4968
  all_pieces=list(s.kernel.pieceuuid2piece.values()),
4851
4969
  to_play_2=getpublictoplay(s),
4852
4970
  bonus_statuses=s.bonus_statuses_3,
4853
- starting_decks=s.kernel.starting_decks,
4854
4971
  starting_piles=s.kernel.starting_piles,
4855
- history=get_public_history(s),
4972
+ history=s.kernel.history,
4856
4973
  player_scores=get_public_player_scores(s),
4857
4974
  player_graphs=s.kernel.player_graphs_3,
4858
4975
  goals=s.kernel.goals,
@@ -4874,20 +4991,25 @@ def getpublicdeck(s, d):
4874
4991
  return PublicDeck(
4875
4992
  idx=d.idx,
4876
4993
  uuid=d.uuid,
4877
- facedown_stack_len=len(d.facedown_stack.cards),
4878
- discard_len=len(d.discard_faceup_stack.cards),
4879
- faceup_spots=d.faceup_spread.spots,
4994
+ all_cards=d.all_cards,
4995
+ faceup_stack = copy.deepcopy(d.faceup_stack) if d.faceup_stack else None,
4996
+ faceup_spread = copy.deepcopy(d.faceup_spread) if d.faceup_spread else None,
4997
+ facedown_stack = PublicFacedownCardStack(num_cards=len(d.facedown_stack.cards)) if d.facedown_stack else None,
4998
+ facedown_spread = PublicFacedownCardSpread(spots=[spot is not None for spot in d.facedown_spread.spots]) if d.facedown_spread else None,
4999
+ discard_faceup_stack = copy.deepcopy(d.discard_faceup_stack) if d.discard_faceup_stack else None,
5000
+ discard_facedown_stack = PublicFacedownCardStack(num_cards=len(d.discard_facedown_stack.cards)) if d.discard_facedown_stack else None,
4880
5001
  )
5002
+ # print("************************************ public_state.decks[0].facedown_stack 7: ", public_state.decks[0].facedown_stack)
4881
5003
 
4882
5004
 
4883
5005
  @dispatch(State, Player)
4884
5006
  def getpublicplayer(s, p):
4885
5007
  deck_counts = [0 for _ in s.kernel.game_config.fig.board_config.deks]
4886
5008
  for card in p.cards:
4887
- deck_counts[s.kernel.carduuid2card[card].deck_idx] += 1
5009
+ deck_counts[s.kernel.game_config.fig.carduuid2card[card].deck_idx] += 1
4888
5010
  discard_deck_counts = [0 for _ in s.kernel.game_config.fig.board_config.deks]
4889
5011
  for card in p.discard_tray:
4890
- discard_deck_counts[s.kernel.carduuid2card[card].deck_idx] += 1
5012
+ discard_deck_counts[s.kernel.game_config.fig.carduuid2card[card].deck_idx] += 1
4891
5013
  piece_template_counts = [0 for _ in s.kernel.game_config.fig.board_config.piece_templates]
4892
5014
  for piece_uuid in p.pieces:
4893
5015
  piece_template_counts[s.kernel.pieceuuid2piece[piece_uuid].piece_template_idx] += 1
@@ -4900,52 +5022,6 @@ def getpublicplayer(s, p):
4900
5022
  )
4901
5023
 
4902
5024
 
4903
- # Implementing the following Julia function:
4904
- # function getpublicscore(s::State, player_idx::Int)
4905
- # addends = Int[]
4906
-
4907
- # if getsettingvalue(s, :path_scoring)
4908
- # (; path_scores) = s.fig
4909
- # path_lens = getplayerpathlens(s, player_idx)
4910
- # if isempty(path_lens)
4911
- # return 0
4912
- # end
4913
- # push!(addends, sum(map(len -> path_scores[len], path_lens)))
4914
- # end
4915
-
4916
- # if getsettingvalue(s, :cluster_scoring)
4917
- # (; clusters) = s.fig.board_config
4918
- # uuid2cluster = Dict((x.uuid, x) for x in clusters)
4919
- # (; completed_clusters) = s.player_hands[player_idx]
4920
- # cluster_scores = map(completed_clusters) do cluster_uuid
4921
- # uuid2cluster[cluster_uuid].score
4922
- # end
4923
- # if !isempty(cluster_scores)
4924
- # push!(addends, sum(cluster_scores))
4925
- # end
4926
- # end
4927
-
4928
- # sum(addends)
4929
- # end
4930
- def getpublicscore(s, player_idx):
4931
- addends = []
4932
- if getsettingvalue(s, 'path_scoring'):
4933
- path_lens = getplayerpathlens(s, player_idx)
4934
- if not path_lens:
4935
- return 0
4936
- addends.append(sum(s.kernel.game_config.fig.path_scores[len] for len in path_lens))
4937
-
4938
- if getsettingvalue(s, 'cluster_scoring'):
4939
- clusters = s.kernel.game_config.fig.board_config.clusters
4940
- uuid2cluster = {x.uuid: x for x in clusters}
4941
- completed_clusters = s.player_hands[player_idx].completed_clusters
4942
- cluster_scores = [uuid2cluster[cluster_uuid].score for cluster_uuid in completed_clusters]
4943
- if cluster_scores:
4944
- addends.append(sum(cluster_scores))
4945
-
4946
- return sum(addends)
4947
-
4948
-
4949
5025
  # Implementing the following Julia function:
4950
5026
  # function getplayerpathlens(s::State, player_idx::Int)
4951
5027
  # getpathlens(s)[getplayerpathidxs(s, player_idx)]
@@ -5107,7 +5183,7 @@ def get_player_graph(s, player_idx):
5107
5183
  def get_goals(kernel, player_idx):
5108
5184
  player = kernel.players[player_idx]
5109
5185
  goaluuid2goal = {goal.uuid: goal for goal in kernel.goals}
5110
- goal_uuids = [kernel.carduuid2card[card_uuid].goal_uuid for card_uuid in player.cards if kernel.carduuid2card[card_uuid].goal_uuid]
5186
+ goal_uuids = [kernel.game_config.fig.carduuid2card[card_uuid].goal_uuid for card_uuid in player.cards if kernel.game_config.fig.carduuid2card[card_uuid].goal_uuid]
5111
5187
  return [
5112
5188
  goaluuid2goal[goal_uuid] for goal_uuid in goal_uuids if goal_uuid in goaluuid2goal
5113
5189
  ]
@@ -5117,7 +5193,7 @@ def get_goals(kernel, player_idx):
5117
5193
  def get_goals3(kernel, player_idx):
5118
5194
  player = kernel.players[player_idx]
5119
5195
  goaluuid2goal = {goal.uuid: goal for goal in kernel.goals}
5120
- goal_uuids = [kernel.carduuid2card[card_uuid].goal_uuid for card_uuid in player.cards if kernel.carduuid2card[card_uuid].goal_uuid]
5196
+ goal_uuids = [kernel.game_config.fig.carduuid2card[card_uuid].goal_uuid for card_uuid in player.cards if kernel.game_config.fig.carduuid2card[card_uuid].goal_uuid]
5121
5197
  return [
5122
5198
  goaluuid2goal[goal_uuid] for goal_uuid in goal_uuids if goal_uuid in goaluuid2goal
5123
5199
  ]
@@ -5698,10 +5774,15 @@ def get_default_toplay(s):
5698
5774
 
5699
5775
 
5700
5776
  @dispatch(PlayerState)
5701
- def get_intuited_best_actions(ps):
5702
- if not ps.private.legal_actions_3:
5777
+ def get_intuited_best_actions(ps: PlayerState):
5778
+ imagined_state = imagine_state(ps)
5779
+ possible_actions = [
5780
+ legal_action.get_default_action(imagined_state)
5781
+ for legal_action in ps.private.legal_actions_3
5782
+ ]
5783
+ if not possible_actions:
5703
5784
  return None
5704
- return ps.private.legal_actions_3[:8]
5785
+ return possible_actions[:8]
5705
5786
 
5706
5787
 
5707
5788
  def get_spread(q_values, p_idx):
@@ -5716,7 +5797,7 @@ def getvproxy0(ps):
5716
5797
 
5717
5798
 
5718
5799
  @dispatch(PlayerState, Action2)
5719
- def imagine_dynamics(ps, a):
5800
+ def imagine_dynamics(ps: PlayerState, a: Action2):
5720
5801
  return dynamics(imagine_state(ps), a)
5721
5802
 
5722
5803
 
@@ -5725,14 +5806,14 @@ def dynamics(s, a):
5725
5806
  scores = get_public_player_scores(s)
5726
5807
  next_s = getnextstate2(s, a)
5727
5808
  next_scores = get_public_player_scores(next_s)
5728
- rewards = [next_scores[i] - scores[i] for i in range(len(scores))]
5809
+ rewards = [next_scores[i].total - scores[i].total for i in range(len(scores))]
5729
5810
  return next_s, rewards
5730
5811
 
5731
5812
 
5732
- @dispatch(PlayerState)
5733
- def alpha0(ps):
5813
+ def alpha0(ps: PlayerState):
5814
+ # print("************************************ ps.public.decks[0].facedown_stack 8: ", ps.public.decks[0].facedown_stack)
5734
5815
  td = 3
5735
- legal_actions = ps.legal_actions_3
5816
+ legal_actions = ps.private.legal_actions_3
5736
5817
  if not legal_actions:
5737
5818
  return None
5738
5819
  intuited = get_intuited_best_actions(ps)
@@ -5748,7 +5829,8 @@ def get_max_spread_idx(q_proxies, p_idx):
5748
5829
 
5749
5830
 
5750
5831
  @dispatch(PlayerState, Action2, int)
5751
- def getqproxy0(ps, a, td):
5832
+ def getqproxy0(ps: PlayerState, a: LegalAction, td: int):
5833
+ print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ getqproxy0 td: ", td)
5752
5834
 
5753
5835
  def qproxybase():
5754
5836
  next_s, rewards = imagine_dynamics(ps, a)
@@ -5770,9 +5852,13 @@ def getqproxy0(ps, a, td):
5770
5852
  return rewards
5771
5853
  next_p_idx = get_default_toplay(next_s)
5772
5854
  next_ps = getprivatestate(next_s, next_p_idx)
5773
- next_p_idx = next_ps.player.player_idx
5774
- next_intuited = get_intuited_best_actions(next_ps)
5775
- competing_next_q_values = [getqproxy0(next_ps, a, td-1) for a in next_intuited]
5855
+ player_state = PlayerState(
5856
+ game_config=getpublicgameconfig(next_s.kernel.game_config),
5857
+ public=getpublicstate(next_s),
5858
+ private=next_ps,
5859
+ )
5860
+ next_intuited = get_intuited_best_actions(player_state)
5861
+ competing_next_q_values = [getqproxy0(player_state, a, td-1) for a in next_intuited]
5776
5862
  max_next_spread_idx = get_max_spread_idx(competing_next_q_values, next_p_idx)
5777
5863
  next_q_values = competing_next_q_values[max_next_spread_idx]
5778
5864
  q_values = [r + next_q_values[i] for i, r in enumerate(rewards)]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graph_games_proto
3
- Version: 0.3.2125
3
+ Version: 0.3.2225
4
4
  Requires-Dist: multipledispatch==1.0.0
5
5
  Requires-Dist: pyrsistent==0.20.0
6
6
  Requires-Dist: numpy==2.2.4
@@ -0,0 +1,9 @@
1
+ graph_games_proto/__init__.py,sha256=BcRdYe0yElSo3vQ5eqhecM1QP-NXaV-mQtcBH6KUnN0,696
2
+ graph_games_proto/all_types.py,sha256=IpbwftEcHS5Ewz-saFNk0lO9FvcbuHG36odRTayCXUk,54911
3
+ graph_games_proto/fns.py,sha256=UgSKX2RtHOY0LwQwV3RE_h0AUE-vGKCiw5nSz25oZF8,211032
4
+ graph_games_proto/main.py,sha256=fj2U7KcwrpZtuUhjOX5yVxY18LZvvsxDFYZ_S5mxe04,145
5
+ graph_games_proto/state.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ graph_games_proto-0.3.2225.dist-info/METADATA,sha256=yq0W9HamGVrJZy9eeEyIe9FwF1qdnKW2HrsuuL2DTm0,188
7
+ graph_games_proto-0.3.2225.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
8
+ graph_games_proto-0.3.2225.dist-info/top_level.txt,sha256=-4QSrBMf_MM4BGsr2QXBpqDx8c8k_OPnzGyFjqjakes,18
9
+ graph_games_proto-0.3.2225.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- graph_games_proto/__init__.py,sha256=_EVQR-51XehfH45XZlba1WPdx3omS3Gm1nTwrgGyn2Q,667
2
- graph_games_proto/all_types.py,sha256=IpbwftEcHS5Ewz-saFNk0lO9FvcbuHG36odRTayCXUk,54911
3
- graph_games_proto/fns.py,sha256=4AJuya9rToZ6X9R1s3VaIgPVfgSzWgFGtcpq1fcb08E,205649
4
- graph_games_proto/main.py,sha256=fj2U7KcwrpZtuUhjOX5yVxY18LZvvsxDFYZ_S5mxe04,145
5
- graph_games_proto/state.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- graph_games_proto-0.3.2125.dist-info/METADATA,sha256=QXSXIlQrExUjx_OAlmIh0lqTA_OvtbGwxj9OLyIw288,188
7
- graph_games_proto-0.3.2125.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
8
- graph_games_proto-0.3.2125.dist-info/top_level.txt,sha256=-4QSrBMf_MM4BGsr2QXBpqDx8c8k_OPnzGyFjqjakes,18
9
- graph_games_proto-0.3.2125.dist-info/RECORD,,