graph-games-proto 0.3.1866__py3-none-any.whl → 0.3.1877__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.
graph_games_proto/fns.py CHANGED
@@ -559,22 +559,6 @@ class FrozenBoardConfigDataclass:
559
559
  settings: List[FrozenSetting]
560
560
 
561
561
 
562
- @dataclass(frozen=True)
563
- class Action:
564
- player_idx: int
565
- action_name: str
566
- return_route_cards: Set[int]
567
- point_uuid: Optional[UUID]
568
- path_idx: Optional[int]
569
- unit_combo: Optional[str]
570
- draw_faceup_unit_card_num: Optional[int]
571
- draw_faceup_spot_num: Optional[int]
572
- def __str__(self):
573
- return f"Action({self.action_name})"
574
- def __repr__(self):
575
- return self.__str__()
576
-
577
-
578
562
  class FrozenRoute(PClass):
579
563
  num = field(type=int)
580
564
  uuid = field(type=str)
@@ -1005,198 +989,6 @@ class ActionDrawUnit:
1005
989
  pass
1006
990
 
1007
991
 
1008
- # struct PublicState
1009
- # fig::Fig
1010
- # logged_game_uuid::UUID
1011
- # to_play::Vector{Int}
1012
- # last_to_play::Union{Nothing,Int}
1013
- # terminal::Bool
1014
- # winners::Vector{Int}
1015
-
1016
-
1017
- class AltAction(PClass):
1018
- player_idx = field(type=int)
1019
- action_name = field(type=str)
1020
- path_idx = field(type=(int, type(None)), initial=None)
1021
- return_route_cards = field(type=list, initial=[]) # List[int]
1022
- draw_faceup_unit_card_num = field(type=(int, type(None)), initial=None)
1023
- draw_faceup_spot_num = field(type=(int, type(None)), initial=None)
1024
- point_uuid = field(type=(str, type(None)), initial=None)
1025
- unit_combo = field(type=(str, type(None)), initial=None) # TODO: should be list of int
1026
- def __todict__(self):
1027
- return {
1028
- "player_idx": self.player_idx,
1029
- "action_name": self.action_name,
1030
- "path_idx": self.path_idx,
1031
- "return_route_cards": self.return_route_cards,
1032
- "draw_faceup_unit_card_num": self.draw_faceup_unit_card_num,
1033
- "draw_faceup_spot_num": self.draw_faceup_spot_num,
1034
- "point_uuid": self.point_uuid,
1035
- "unit_combo": self.unit_combo
1036
- }
1037
- @staticmethod
1038
- def __fromdict__(json_dict):
1039
- return AltAction(
1040
- player_idx=json_dict["player_idx"],
1041
- action_name=json_dict["action_name"],
1042
- path_idx=json_dict.get("path_idx", None), # Handle missing key gracefully
1043
- return_route_cards=json_dict.get("return_route_cards", []), # Handle missing key gracefully
1044
- draw_faceup_unit_card_num=json_dict.get("draw_faceup_unit_card_num", None), # Handle missing key gracefully
1045
- draw_faceup_spot_num=json_dict.get("draw_faceup_spot_num", None), # Handle missing key gracefully
1046
- point_uuid=json_dict.get("point_uuid", None), # Handle missing key gracefully
1047
- unit_combo=json_dict.get("unit_combo", None) # Handle missing key gracefully
1048
- )
1049
-
1050
-
1051
- class ActionSpec(PClass):
1052
- # # TODO: should remove "player_idx" as it's always the same as "to_play"
1053
- player_idx = field(type=int)
1054
- action_name = field(type=str)
1055
- return_route_option_sets = field(type=list, initial=[]) # List[OptionSet]
1056
- draw_faceup_spots = field(type=dict, initial={}) # Dict{Int, int}
1057
- points = field(type=list, initial=[]) # List[PointCombos]
1058
- paths = field(type=list, initial=[]) # List[PathCombos]
1059
- def __todict__(self):
1060
- return {
1061
- "player_idx": self.player_idx,
1062
- "action_name": self.action_name,
1063
- "return_route_option_sets": [x.__todict__() for x in self.return_route_option_sets],
1064
- "draw_faceup_spots": self.draw_faceup_spots,
1065
- "points": [x.__todict__() for x in self.points],
1066
- "paths": [x.__todict__() for x in self.paths],
1067
- }
1068
- @staticmethod
1069
- def __fromdict__(d):
1070
- print("""d["return_route_option_sets"]""", d["return_route_option_sets"])
1071
- return ActionSpec(
1072
- player_idx=d["player_idx"],
1073
- action_name=d["action_name"],
1074
- return_route_option_sets=[OptionSet.__fromdict__(x) for x in d["return_route_option_sets"]],
1075
- draw_faceup_spots=d["draw_faceup_spots"],
1076
- points=[PointCombos.__fromdict__(x) for x in d["points"]],
1077
- paths=[PathCombos.__fromdict__(x) for x in d["paths"]],
1078
- )
1079
-
1080
-
1081
- # Implementing the following Julia function:
1082
- # struct PathCombos
1083
- # path_idx::Int
1084
- # default_combo::String
1085
- # sample_fulfillment::Vector{Int}
1086
- # end
1087
- class PathCombos(PClass):
1088
- path_idx = field(type=int)
1089
- default_combo = field(type=str)
1090
- sample_fulfillment = field(type=list) # List[int]
1091
- def __todict__(self):
1092
- return {
1093
- "path_idx": self.path_idx,
1094
- "default_combo": self.default_combo,
1095
- "sample_fulfillment": self.sample_fulfillment,
1096
- }
1097
- @staticmethod
1098
- def __fromdict__(d):
1099
- return PathCombos(
1100
- path_idx=d["path_idx"],
1101
- default_combo=d["default_combo"],
1102
- sample_fulfillment=d["sample_fulfillment"]
1103
- )
1104
-
1105
-
1106
- # Implementing the following Julia function:
1107
- # struct OptionSet
1108
- # option_idxs::Set{Int}
1109
- # end
1110
- class OptionSet(PClass):
1111
- option_idxs = field(type=set) # Set[int]
1112
- def __todict__(self):
1113
- return {
1114
- "option_idxs": list(self.option_idxs),
1115
- }
1116
- @staticmethod
1117
- def __fromdict__(d):
1118
- return OptionSet(
1119
- option_idxs=set(d["option_idxs"])
1120
- )
1121
-
1122
-
1123
- class PointCombos(PClass):
1124
- point_uuid = field(type=str)
1125
- default_combo = field(type=str)
1126
- sample_fulfillment = field(type=list) # List[int]
1127
- def __todict__(self):
1128
- return {
1129
- "point_uuid": self.point_uuid,
1130
- "default_combo": self.default_combo,
1131
- "sample_fulfillment": self.sample_fulfillment,
1132
- }
1133
- @staticmethod
1134
- def __fromdict__(d):
1135
- return PointCombos(
1136
- point_uuid=d["point_uuid"],
1137
- default_combo=d["default_combo"],
1138
- sample_fulfillment=d["sample_fulfillment"]
1139
- )
1140
-
1141
-
1142
- class PlayerInfo(PClass):
1143
- fig = field(type=Fig)
1144
- player_idx = field(type=int)
1145
- new_route_cards = field(type=PVector) # List[int]
1146
- route_cards = field(type=PVector) # List[int]
1147
- unit_cards = field(type=PVector) # List[int]
1148
- completed_routes = field(type=list) # List[int]
1149
- completed_clusters = field(type=list) # List[UUID]
1150
- paths = field(type=list) # List[int]
1151
- points = field(type=list) # List[UUID]
1152
- tokens = field(type=list) # List[UUID]
1153
- num_pieces = field(type=int)
1154
- num_point_pieces = field(type=int)
1155
- longest_trail = field(type=list) # List[int]
1156
- longest_trail_len = field(type=int)
1157
- final_score = field(type=object) # Union{Nothing, PlayerScore}
1158
- def __todict__(self):
1159
- return {
1160
- "fig": self.fig.__todict__(),
1161
- "player_idx": self.player_idx,
1162
- "new_route_cards": list(self.new_route_cards),
1163
- "route_cards": list(self.route_cards),
1164
- "unit_cards": list(self.unit_cards),
1165
- "completed_routes": self.completed_routes,
1166
- "completed_clusters": self.completed_clusters,
1167
- "paths": self.paths,
1168
- "points": self.points,
1169
- "tokens": self.tokens,
1170
- "num_pieces": self.num_pieces,
1171
- "num_point_pieces": self.num_point_pieces,
1172
- "longest_trail": self.longest_trail,
1173
- "longest_trail_len": self.longest_trail_len,
1174
- "final_score": self.final_score.__todict__() if self.final_score else None,
1175
- }
1176
- @staticmethod
1177
- def __fromdict__(d):
1178
- return PlayerInfo(
1179
- fig=Fig.__fromdict__(d["fig"]),
1180
- player_idx=d["player_idx"],
1181
- new_route_cards=pvector(d["new_route_cards"]),
1182
- route_cards=pvector(d["route_cards"]),
1183
- unit_cards=pvector(d["unit_cards"]),
1184
- completed_routes=d["completed_routes"],
1185
- completed_clusters=d["completed_clusters"],
1186
- paths=d["paths"],
1187
- points=d["points"],
1188
- tokens=d["tokens"],
1189
- num_pieces=d["num_pieces"],
1190
- num_point_pieces=d["num_point_pieces"],
1191
- longest_trail=d["longest_trail"],
1192
- longest_trail_len=d["longest_trail_len"],
1193
- final_score=PlayerScore.__fromdict__(d["final_score"]) if d.get("final_score") else None,
1194
- )
1195
- @staticmethod
1196
- def clone(hand):
1197
- return PlayerInfo.__fromdict__(hand.__todict__())
1198
-
1199
-
1200
992
  class PublicPlayer(PClass):
1201
993
  idx = field(type=int)
1202
994
  pieces = field(type=list) # List[Piece]
@@ -1307,36 +1099,27 @@ class PrivatePlayerScore(PClass):
1307
1099
  )
1308
1100
 
1309
1101
 
1310
- # Implementing the following Julia function:
1311
- # struct PrivateState
1312
- # legal_actions::Vector{ActionSpec}
1313
- # segment_statuses::Vector{SegmentStatus}
1314
- # hand::PlayerInfo
1315
- # end
1316
1102
  class PrivateState(PClass):
1103
+ my_history = field(type=list) # List[Action2]
1317
1104
  player_score = field(type=PrivatePlayerScore)
1318
1105
  player = field(type=Player)
1319
1106
  legal_actions_2 = field(type=list) # List[LegalAction]
1320
- legal_actions = field(type=list) # List[ActionSpec]
1321
- hand = field(type=PlayerInfo)
1322
1107
  goal_completions = field(type=list, initial=[]) # List[GoalCompletion]
1323
1108
  def __todict__(self):
1324
1109
  return {
1110
+ "my_history": [x.__todict__() for x in self.my_history],
1325
1111
  "player_score": self.player_score.__todict__(),
1326
1112
  "player": self.player.__todict__(),
1327
1113
  "legal_actions_2": [x.__todict__() for x in self.legal_actions_2],
1328
- "legal_actions": [x.__todict__() for x in self.legal_actions],
1329
- "hand": self.hand.__todict__(),
1330
1114
  "goal_completions": [x.__todict__() for x in self.goal_completions],
1331
1115
  }
1332
1116
  @staticmethod
1333
1117
  def __fromdict__(d):
1334
1118
  return PrivateState(
1119
+ my_history=[Action2.__fromdict__(x) for x in d["my_history"]],
1335
1120
  player_score=PrivatePlayerScore.__fromdict__(d["player_score"]),
1336
1121
  player=Player.__fromdict__(d["player"]),
1337
1122
  legal_actions_2=[LegalAction.__fromdict__(x) for x in d["legal_actions_2"]],
1338
- legal_actions=[ActionSpec.__fromdict__(x) for x in d["legal_actions"]],
1339
- hand=PlayerInfo.__fromdict__(d["hand"]),
1340
1123
  goal_completions=[GoalCompletion.__fromdict__(x) for x in d["goal_completions"]],
1341
1124
  )
1342
1125
 
@@ -2155,7 +1938,6 @@ class State(PClass):
2155
1938
  uuid2segment = field(type=dict) # Dict[str, Segment]
2156
1939
  pieceuuid2piece = field(type=dict) # Dict[str, Piece]
2157
1940
  carduuid2card = field(type=dict) # Dict[str, Card]
2158
- final_scores = field(type=(list, type(None)), initial=None) # Optional[List[int]]
2159
1941
  bonus_statuses = field(type=list) # List[BonusStatus]
2160
1942
  bonusuuid2bonusidx = field(type=dict) # Dict[str, int]
2161
1943
  carduuid2deckidx = field(type=dict) # Dict[str, int]
@@ -2179,10 +1961,6 @@ class State(PClass):
2179
1961
  game_config = field(type=GameConfig)
2180
1962
  rng = field(type=random.Random)
2181
1963
  terminal = field(type=bool)
2182
- initial_to_play = field(type=list) # List[int]
2183
- route_cards = field(type=PVector) # List[int]
2184
- route_discards = field(type=PVector) # List[int]
2185
- player_hands = field(type=PVector) # List[PlayerInfo]
2186
1964
  last_to_play = field(type=(int, type(None)), initial=None)
2187
1965
  winners = field(type=list) # List[int]
2188
1966
  def __todict__(self):
@@ -2192,7 +1970,6 @@ class State(PClass):
2192
1970
  "uuid2segment": {k: v.__todict__() for k, v in self.uuid2segment.items()},
2193
1971
  "pieceuuid2piece": {k: v.__todict__() for k, v in self.pieceuuid2piece.items()},
2194
1972
  "carduuid2card": {k: v.__todict__() for k, v in self.carduuid2card.items()},
2195
- "final_scores": self.final_scores,
2196
1973
  "bonus_statuses": [status.__todict__() for status in self.bonus_statuses],
2197
1974
  "bonusuuid2bonusidx": self.bonusuuid2bonusidx,
2198
1975
  "carduuid2deckidx": self.carduuid2deckidx,
@@ -2216,10 +1993,6 @@ class State(PClass):
2216
1993
  "game_config": self.game_config.__todict__(),
2217
1994
  "rng": rng2json(self.rng),
2218
1995
  "terminal": self.terminal,
2219
- "initial_to_play": self.initial_to_play,
2220
- "route_cards": list(self.route_cards),
2221
- "route_discards": list(self.route_discards),
2222
- "player_hands": [x.__todict__() for x in self.player_hands],
2223
1996
  "last_to_play": self.last_to_play,
2224
1997
  "winners": self.winners,
2225
1998
  }
@@ -2231,7 +2004,6 @@ class State(PClass):
2231
2004
  uuid2segment={k: Segment2.__fromdict__(v) for k, v in d["uuid2segment"].items()},
2232
2005
  pieceuuid2piece={k: Piece.__fromdict__(v) for k, v in d["pieceuuid2piece"].items()},
2233
2006
  carduuid2card={k: Card.__fromdict__(v) for k, v in d["carduuid2card"].items()},
2234
- final_scores=d["final_scores"],
2235
2007
  bonus_statuses=[BonusStatus.__fromdict__(x) for x in d["bonus_statuses"]],
2236
2008
  bonusuuid2bonusidx=d["bonusuuid2bonusidx"],
2237
2009
  carduuid2deckidx=d["carduuid2deckidx"],
@@ -2255,10 +2027,6 @@ class State(PClass):
2255
2027
  game_config=GameConfig.__fromdict__(d["game_config"]),
2256
2028
  rng=json2rng(d["rng"]),
2257
2029
  terminal=d["terminal"],
2258
- initial_to_play=d["initial_to_play"],
2259
- route_cards=pvector(d["route_cards"]),
2260
- route_discards=pvector(d["route_discards"]),
2261
- player_hands=pvector([PlayerInfo.__fromdict__(h) for h in d["player_hands"]]),
2262
2030
  last_to_play=d.get("last_to_play"),
2263
2031
  winners=d["winners"],
2264
2032
  )
@@ -2514,7 +2282,6 @@ class PublicState(PClass):
2514
2282
  decks = field(type=list) # List[PublicDeck]
2515
2283
  piles = field(type=list) # List[Pile]
2516
2284
  player_idxs = field(type=list) # List[int]
2517
- initial_to_play = field(type=list) # List[int]
2518
2285
  players = field(type=list) # List[PublicPlayer]
2519
2286
  last_to_play = field(type=(int, type(None)), initial=None)
2520
2287
  winners = field(type=list)
@@ -2539,7 +2306,6 @@ class PublicState(PClass):
2539
2306
  "decks": [deck.__todict__() for deck in self.decks],
2540
2307
  "piles": [pile.__todict__() for pile in self.piles],
2541
2308
  "player_idxs": self.player_idxs,
2542
- "initial_to_play": self.initial_to_play,
2543
2309
  "players": [x.__todict__() for x in self.players],
2544
2310
  "last_to_play": self.last_to_play,
2545
2311
  "winners": self.winners,
@@ -2566,7 +2332,6 @@ class PublicState(PClass):
2566
2332
  decks=[PublicDeck.__fromdict__(deck) for deck in d["decks"]],
2567
2333
  piles=[Pile.__fromdict__(x) for x in d["piles"]],
2568
2334
  player_idxs=d["player_idxs"],
2569
- initial_to_play=d["initial_to_play"],
2570
2335
  players=[PublicPlayer.__fromdict__(x) for x in d["players"]],
2571
2336
  last_to_play=d.get("last_to_play"),
2572
2337
  winners=d["winners"],
@@ -2720,50 +2485,9 @@ def getsettingvalue(s, setting_name):
2720
2485
  def getinitialstate(game_config):
2721
2486
  fig = game_config.fig
2722
2487
  rng = getrng(game_config.seed)
2723
- route_deck = shuffledeck(getnumroutecards(fig), rng)
2724
2488
  unit_deck = shuffledeck(gettotaldeckcards(fig), rng)
2725
2489
  route_deck_idx, unit_deck_idx = 0, 0
2726
- player_hands = []
2727
- initial_num_route_choices = getsettingvalue(fig, "initial_num_route_choices")
2728
- num_initial_unit_cards = getsettingvalue(fig, "num_initial_unit_cards")
2729
- num_segment_pieces_per_player = getsettingvalue(fig, "num_segment_pieces_per_player")
2730
- num_point_pieces_per_player = getsettingvalue(fig, "num_point_pieces_per_player")
2731
-
2732
-
2733
- for player_idx in range(game_config.num_players):
2734
- player_hand = PlayerInfo(
2735
- fig=fig,
2736
- player_idx=player_idx,
2737
- new_route_cards=pvector(route_deck[route_deck_idx:(route_deck_idx+(initial_num_route_choices))]),
2738
- route_cards=pvector([]),
2739
- unit_cards=pvector(unit_deck[unit_deck_idx:(unit_deck_idx + num_initial_unit_cards)]),
2740
- completed_routes=[],
2741
- completed_clusters=[],
2742
- paths=[],
2743
- points=[],
2744
- tokens=[],
2745
- num_pieces=num_segment_pieces_per_player,
2746
- num_point_pieces=num_point_pieces_per_player,
2747
- longest_trail=[],
2748
- longest_trail_len=0,
2749
- final_score=None,
2750
- )
2751
- player_hands.append(player_hand)
2752
- route_deck_idx += initial_num_route_choices
2753
- unit_deck_idx += num_initial_unit_cards
2754
-
2755
- faceup_spots = getfaceupspots(fig, unit_deck, unit_deck_idx)
2756
2490
  unit_deck_idx += 5
2757
- # Implementing the following Julia function:
2758
- # unit_cards = unit_deck[unit_deck_idx:end]
2759
- unit_cards = unit_deck[unit_deck_idx:] if unit_deck_idx < len(unit_deck) else []
2760
- route_cards = route_deck[route_deck_idx:]
2761
-
2762
- if getsettingvalue(fig, 'action_route_discard'):
2763
- initial_to_play = list(range(game_config.num_players))
2764
- else:
2765
- initial_to_play = [getfirstplayeridx(rng, game_config.num_players)]
2766
-
2767
2491
  board_config = fig.board_config
2768
2492
  deck_0_rng = getrng(1234321)
2769
2493
  deck_1_rng = getrng(8738758)
@@ -2848,7 +2572,6 @@ def getinitialstate(game_config):
2848
2572
  uuid2segment=uuid2segment,
2849
2573
  pieceuuid2piece=pieceuuid2piece,
2850
2574
  carduuid2card=carduuid2card,
2851
- final_scores=None,
2852
2575
  bonus_statuses=bonus_statuses,
2853
2576
  bonusuuid2bonusidx=bonusuuid2bonusidx,
2854
2577
  carduuid2deckidx=carduuid2deckidx,
@@ -2879,11 +2602,7 @@ def getinitialstate(game_config):
2879
2602
  player_idxs=list(range(game_config.num_players)),
2880
2603
  decks=decks,
2881
2604
  game_config=game_config,
2882
- initial_to_play=initial_to_play,
2883
2605
  rng=rng,
2884
- route_cards=pvector(route_cards),
2885
- route_discards=pvector([]),
2886
- player_hands=pvector(player_hands),
2887
2606
  last_to_play=None,
2888
2607
  winners=[],
2889
2608
  terminal=False,
@@ -2994,15 +2713,20 @@ def handle_last_to_play(game):
2994
2713
  return game
2995
2714
 
2996
2715
 
2716
+ def getfinalscores(game):
2717
+ return [
2718
+ getpublicplayerscore(game, game.player_scores[player_idx]).total
2719
+ for player_idx in range(len(game.players))
2720
+ ]
2721
+
2722
+
2997
2723
  def handle_calc_winners(game):
2998
2724
  if game.terminal:
2999
2725
  players_with_highest_score = []
3000
2726
  highest_score = -1000
3001
- final_scores = []
2727
+ final_scores = getfinalscores(game)
3002
2728
  for player_idx in range(len(game.players)):
3003
- player_score = game.player_scores[player_idx]
3004
- final_score = getpublicplayerscore(game, player_score).total
3005
- final_scores.append(final_score)
2729
+ final_score = final_scores[player_idx]
3006
2730
  if final_score > highest_score:
3007
2731
  highest_score = final_score
3008
2732
  players_with_highest_score = [player_idx]
@@ -3010,7 +2734,6 @@ def handle_calc_winners(game):
3010
2734
  players_with_highest_score.append(player_idx)
3011
2735
  return game.set(
3012
2736
  winners=players_with_highest_score,
3013
- final_scores=final_scores,
3014
2737
  )
3015
2738
 
3016
2739
  return game
@@ -4308,63 +4031,6 @@ def getnextstate2(s, a, log=False):
4308
4031
  return s
4309
4032
 
4310
4033
 
4311
-
4312
- @dispatch(State, QValueLearningPolicy)
4313
- def getnextaction(s, policy):
4314
- player_idx = gettoplay(s)[0]
4315
- legal_action_specs = getlegalactionspecsforplayer(s, player_idx, None, None)
4316
- legal_actions = get_all_legal_actions(s, player_idx, legal_action_specs)
4317
-
4318
- if s.rng.random() <= policy.epsilon:
4319
- random_action = legal_actions[s.rng.randint(0, len(legal_actions) - 1)]
4320
- return random_action
4321
-
4322
- q_values = policy.qvalue_fn(s, legal_actions)
4323
- argmax_idx = max(range(len(q_values)), key=lambda i: q_values[i])
4324
-
4325
- return legal_actions[argmax_idx]
4326
-
4327
-
4328
- @dispatch(State, RandoPolicy)
4329
- def getnextaction(s, policy):
4330
- player_idx = gettoplay(s)[0]
4331
- legal_actions = getlegalactionspecsforplayer(s, player_idx, None, None)
4332
- action_spec = legal_actions[s.rng.randint(0, len(legal_actions) - 1)]
4333
-
4334
- if action_spec.action_name == "ROUTE_DISCARD":
4335
- return AltAction(
4336
- action_name="ROUTE_DISCARD",
4337
- player_idx=player_idx,
4338
- return_route_cards=[0],
4339
- )
4340
-
4341
- if action_spec.action_name == "DRAW_UNIT_FACEUP":
4342
- draw_faceup_spot_num = 1
4343
- return AltAction(
4344
- action_name="DRAW_UNIT_FACEUP",
4345
- player_idx=player_idx,
4346
- draw_faceup_unit_card_num=s.faceup_spots[draw_faceup_spot_num-1],
4347
- draw_faceup_spot_num=draw_faceup_spot_num,
4348
- )
4349
-
4350
- if action_spec.action_name == "DRAW_UNIT_DECK":
4351
- return AltAction(
4352
- action_name="DRAW_UNIT_DECK",
4353
- player_idx=player_idx,
4354
- )
4355
-
4356
- if action_spec.action_name == "CLAIM_POINT":
4357
- point = action_spec.points[s.rng.randint(0, len(action_spec.points) - 1)]
4358
- return AltAction(
4359
- action_name="CLAIM_POINT",
4360
- player_idx=player_idx,
4361
- point_uuid=str(point.point_uuid),
4362
- unit_combo=point.default_combo,
4363
- )
4364
-
4365
- return None
4366
-
4367
-
4368
4034
  def getpublicplayerscore(s, player_score):
4369
4035
  if s.terminal:
4370
4036
  # Join the arrays of public and private items
@@ -4448,6 +4114,98 @@ def get_deadlines(s):
4448
4114
  ]
4449
4115
 
4450
4116
 
4117
+ def get_public_player_scores(s):
4118
+ return [getpublicplayerscore(s, player_score) for player_score in s.player_scores]
4119
+
4120
+
4121
+ # deadlines = field(type=list) # List[RemainingAllottedTime|None]
4122
+ # game_started_at = field(type=str)
4123
+ # allotted_times = field(type=list)
4124
+ # all_pieces = field(type=list) # List[Piece]
4125
+ # to_play_2 = field(type=list) # List[int]
4126
+ # bonus_statuses = field(type=list) # List[BonusStatus]
4127
+ # starting_decks = field(type=list) # List[Deck]
4128
+ # starting_piles = field(type=list) # List[Pile]
4129
+ # history = field(type=list) # List[PublicAction]
4130
+ # player_scores = field(type=list) # List[PublicPlayerScore]
4131
+ # player_graphs = field(type=list) # List[PlayerGraph]
4132
+ # goals = field(type=list) # List[Goal]
4133
+ # nodes = field(type=list) # List[Node]
4134
+ # edges = field(type=list) # List[BiEdge]
4135
+ # regions = field(type=list)
4136
+ # decks = field(type=list) # List[PublicDeck]
4137
+ # piles = field(type=list) # List[Pile]
4138
+ # player_idxs = field(type=list) # List[int]
4139
+ # players = field(type=list) # List[PublicPlayer]
4140
+ # last_to_play = field(type=(int, type(None)), initial=None)
4141
+ # winners = field(type=list)
4142
+ # = field(type=bool)
4143
+
4144
+
4145
+ # player_score = field(type=PrivatePlayerScore)
4146
+ # player = field(type=Player)
4147
+ # legal_actions_2 = field(type=list) # List[LegalAction]
4148
+ # goal_completions = field(type=list, initial=[]) # List[GoalCompletion]
4149
+
4150
+
4151
+
4152
+ def get_public_history(s):
4153
+ return [action.get_public(s) for action in s.history]
4154
+
4155
+ def imagine_history(public_state, private_state):
4156
+ pass
4157
+
4158
+ def imagine_player_scores(public_state, private_state):
4159
+ pass
4160
+
4161
+ def imagine_legal_actions(public_state, private_state):
4162
+ pass
4163
+
4164
+ def imagine_players(public_state, private_state):
4165
+ pass
4166
+
4167
+ def imagine_decks(public_state, private_state):
4168
+ pass
4169
+
4170
+ def imagine_rng(public_state, private_state):
4171
+ pass
4172
+
4173
+
4174
+ def imagine_state(public_state, private_state):
4175
+ return State(
4176
+ uuid2edge = public_state.uuid2edge,
4177
+ idx2path = public_state.idx2path,
4178
+ uuid2segment = public_state.uuid2segment,
4179
+ pieceuuid2piece = public_state.pieceuuid2piece,
4180
+ carduuid2card = public_state.carduuid2card,
4181
+ bonus_statuses = public_state.bonus_statuses,
4182
+ bonusuuid2bonusidx = public_state.bonusuuid2bonusidx,
4183
+ carduuid2deckidx = public_state.carduuid2deckidx,
4184
+ starting_decks = public_state.starting_decks,
4185
+ starting_piles = public_state.starting_piles,
4186
+ player_graphs = public_state.player_graphs,
4187
+ goals = public_state.goals,
4188
+ nodes = public_state.nodes,
4189
+ nodeuuid2idx = public_state.nodeuuid2idx,
4190
+ edges = public_state.edges,
4191
+ edgeuuid2idx = public_state.edgeuuid2idx,
4192
+ edgetuple2uuid = public_state.edgetuple2uuid,
4193
+ regions = public_state.regions,
4194
+ terminal = public_state.terminal,
4195
+ last_to_play = public_state.last_to_play,
4196
+ winners = public_state.winners,
4197
+ piles = public_state.piles,
4198
+ player_idxs = public_state.player_idxs,
4199
+ game_config = public_state.game_config,
4200
+ legal_actions_2 = imagine_legal_actions(public_state, private_state),
4201
+ players = imagine_players(public_state, private_state),
4202
+ decks = imagine_decks(public_state, private_state),
4203
+ rng = imagine_rng(public_state, private_state),
4204
+ history = imagine_history(public_state, private_state),
4205
+ player_scores = imagine_player_scores(public_state, private_state),
4206
+ )
4207
+
4208
+
4451
4209
  @dispatch(State)
4452
4210
  def getpublicstate(s):
4453
4211
  return PublicState(
@@ -4459,8 +4217,8 @@ def getpublicstate(s):
4459
4217
  bonus_statuses=s.bonus_statuses,
4460
4218
  starting_decks=s.starting_decks,
4461
4219
  starting_piles=s.starting_piles,
4462
- history=[action.get_public(s) for action in s.history],
4463
- player_scores=[getpublicplayerscore(s, player_score) for player_score in s.player_scores],
4220
+ history=get_public_history(s),
4221
+ player_scores=get_public_player_scores(s),
4464
4222
  player_graphs=s.player_graphs,
4465
4223
  goals=s.goals,
4466
4224
  nodes=s.nodes,
@@ -4469,7 +4227,6 @@ def getpublicstate(s):
4469
4227
  decks=[getpublicdeck(s, deck) for deck in s.decks],
4470
4228
  piles=s.piles,
4471
4229
  player_idxs=s.player_idxs,
4472
- initial_to_play=s.initial_to_play,
4473
4230
  players=[getpublicplayer(s, p) for p in s.players],
4474
4231
  last_to_play=s.last_to_play,
4475
4232
  winners=s.winners,
@@ -4619,18 +4376,6 @@ def gettoplay(s, last_action_type):
4619
4376
  return [getlastplayeridxplus1(s)]
4620
4377
 
4621
4378
 
4622
- # Implementing the following Julia function:
4623
- @dispatch(State, NoAction)
4624
- # function gettoplay(s::State, last_action_key::Nothing)
4625
- # if getsettingvalue(s, :action_route_discard)
4626
- # return collect(1:s.game_config.num_players)
4627
- # end
4628
- # [getfirstplayeridx(s.game)]
4629
- # end
4630
- def gettoplay(s, last_action_type):
4631
- return s.initial_to_play
4632
-
4633
-
4634
4379
  def getrng(seed):
4635
4380
  rng = random.Random()
4636
4381
  rng.seed(seed)
@@ -4791,262 +4536,6 @@ def combinations(a, n=None):
4791
4536
  # then the state is "terminal".
4792
4537
  ###
4793
4538
 
4794
- # Implementing the following Julia function:
4795
- # function getrouteoptionsets(s::State, player_idx, min_required)
4796
- # num_choices = length(s.player_hands[player_idx].new_route_cards)
4797
- # max_return_size = num_choices - min_required
4798
- # set = collect(1:num_choices)
4799
- # OptionSet.(
4800
- # Set{Int}.(
4801
- # reduce(
4802
- # vcat,
4803
- # [collect(combinations(set, n)) for n in 0:max_return_size],
4804
- # )
4805
- # )
4806
- # )
4807
- # end
4808
- def getrouteoptionsets(s, player_idx, min_required):
4809
- num_choices = len(s.player_hands[player_idx].new_route_cards)
4810
- max_return_size = num_choices - min_required
4811
- choice_set = list(range(num_choices))
4812
- all_combinations = [
4813
- set(comb)
4814
- for n in range(max_return_size + 1)
4815
- for comb in combinations(choice_set, n)
4816
- ]
4817
- return [OptionSet(option_idxs=comb) for comb in all_combinations]
4818
-
4819
-
4820
-
4821
- # Implementing the following Julia function:
4822
- # function getlegalactionsforplayer(s::State, player_idx, repeat_player, last_action)
4823
- # min_initial_routes = getsettingvalue(s.fig, :min_initial_routes)
4824
- # min_chosen_routes = getsettingvalue(s.fig, :min_chosen_routes)
4825
-
4826
- # action_specs = ActionSpec[]
4827
- # if getsettingvalue(s, :action_draw_unit_faceup) && !isempty(getvalidspotnums(s))
4828
- # push!(
4829
- # action_specs,
4830
- # ActionSpec(
4831
- # player_idx=player_idx,
4832
- # action_name=DRAW_UNIT_FACEUP,
4833
- # draw_faceup_spots=Dict((spot_num, s.faceup_spots[spot_num]) for spot_num in getvalidspotnums(s)),
4834
- # )
4835
- # )
4836
- # end
4837
-
4838
- # if getsettingvalue(s, :action_draw_route) && (length(s.route_cards) + length(s.route_discards)) >= min_chosen_routes
4839
- # push!(action_specs, ActionSpec(s.fig, player_idx, :DRAW_ROUTE))
4840
- # end
4841
-
4842
- # if getsettingvalue(s, :action_draw_unit_deck) && (!isempty(s.unit_cards) || !isempty(s.unit_discards))
4843
- # push!(action_specs, ActionSpec(s.fig, player_idx, :DRAW_UNIT_DECK))
4844
- # end
4845
-
4846
- # if getsettingvalue(s, :action_claim_path)
4847
- # append!(action_specs, getclaimpathactionspecs(s, player_idx))
4848
- # end
4849
-
4850
- # if getsettingvalue(s.fig, :action_claim_point)
4851
- # append!(action_specs, getclaimpointactionspecs(s, player_idx))
4852
- # end
4853
-
4854
- # action_specs
4855
- # end
4856
- @dispatch(State, int, object, object)
4857
- def getlegalactionspecsforplayer(s, player_idx, repeat_player, last_action):
4858
- min_chosen_routes = getsettingvalue(s, 'min_chosen_routes')
4859
-
4860
- action_specs = []
4861
- if getsettingvalue(s, 'action_draw_unit_faceup') and s.faceup_spots:
4862
-
4863
- # Convert this Julia to Python:
4864
- # Julia:
4865
- # draw_faceup_spots = Dict((spot_num, s.faceup_spots[spot_num]) for spot_num in getvalidspotnums(s))
4866
- # Python:
4867
- draw_faceup_spots = {spot_num: s.faceup_spots[spot_num-1] for spot_num in getvalidspotnums(s)}
4868
-
4869
- action_specs.append(
4870
- ActionSpec(
4871
- player_idx=player_idx,
4872
- action_name="DRAW_UNIT_FACEUP",
4873
- return_route_option_sets = [],
4874
- draw_faceup_spots=draw_faceup_spots,
4875
- points = [],
4876
- paths = [],
4877
- )
4878
- )
4879
-
4880
- if getsettingvalue(s, 'action_draw_route') and (len(s.route_cards) + len(s.route_discards)) >= min_chosen_routes:
4881
- action_specs.append(
4882
- AltAction(
4883
- player_idx=player_idx,
4884
- action_name="DRAW_ROUTE",
4885
- return_route_option_sets = [],
4886
- draw_faceup_spots={},
4887
- points = [],
4888
- paths = [],
4889
- )
4890
- )
4891
-
4892
- if getsettingvalue(s, 'action_draw_unit_deck') and (s.unit_cards or s.unit_discards):
4893
- action_specs.append(
4894
- ActionSpec(
4895
- player_idx=player_idx,
4896
- action_name="DRAW_UNIT_DECK",
4897
- return_route_option_sets = [],
4898
- draw_faceup_spots={},
4899
- points = [],
4900
- paths = [],
4901
- )
4902
- )
4903
-
4904
- if getsettingvalue(s, 'action_claim_path'):
4905
- action_specs.extend(getclaimpathactionspecs(s, player_idx))
4906
- pass
4907
-
4908
- if getsettingvalue(s, 'action_claim_point'):
4909
- action_specs.extend(getclaimpointactionspecs(s, player_idx))
4910
-
4911
- return action_specs
4912
-
4913
-
4914
- # Implementing the following Julia function:
4915
- # function getclaimpointactionspecs(s::State, player_idx::Int; log=false)
4916
- # action_specs = ActionSpec[]
4917
- # available_point_statuses = getavailablepoints(s, player_idx)
4918
- # points = map(available_point_statuses) do available_point_status
4919
- # (; uuid, sample_fulfillment) = available_point_status
4920
- # fulfillment_sorted = sample_fulfillment
4921
- # sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
4922
- # fulfillment_str = join(sample_fulfillment, "-")
4923
- # PointCombos(uuid, fulfillment_str, sample_fulfillment)
4924
- # end
4925
- # if !isempty(points)
4926
- # push!(
4927
- # action_specs,
4928
- # ActionSpec(
4929
- # action_name=CLAIM_POINT,
4930
- # player_idx=player_idx,
4931
- # points=points,
4932
- # )
4933
- # )
4934
- # end
4935
- # action_specs
4936
- # end
4937
- def getclaimpointactionspecs(s, player_idx, log=False):
4938
- action_specs = []
4939
- available_point_statuses = getavailablepoints(s, player_idx)
4940
-
4941
- # points = map(available_point_statuses) do available_point_status
4942
- # (; uuid, sample_fulfillment) = available_point_status
4943
- # fulfillment_sorted = sample_fulfillment
4944
- # sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
4945
- # fulfillment_str = join(sample_fulfillment, "-")
4946
- # PointCombos(uuid, fulfillment_str, sample_fulfillment)
4947
- # end
4948
-
4949
- def process_point_status(available_point_status):
4950
- uuid = available_point_status['uuid']
4951
- sample_fulfillment = available_point_status['sample_fulfillment']
4952
- fulfillment_sorted = sample_fulfillment
4953
- sample_fulfillment = [x['unit_card_num'] for x in fulfillment_sorted]
4954
- fulfillment_str = '-'.join(map(str, sample_fulfillment))
4955
- return PointCombos(
4956
- point_uuid=uuid,
4957
- default_combo=fulfillment_str,
4958
- sample_fulfillment=sample_fulfillment
4959
- )
4960
-
4961
- point_combos = list(map(process_point_status, available_point_statuses))
4962
-
4963
- if point_combos:
4964
- action_specs.append(
4965
- ActionSpec(
4966
- player_idx=player_idx,
4967
- action_name="CLAIM_POINT",
4968
- return_route_option_sets = [],
4969
- draw_faceup_spots = {},
4970
- points=point_combos,
4971
- paths = [],
4972
- )
4973
- )
4974
-
4975
- return action_specs
4976
-
4977
-
4978
- # Implementing the following Julia function:
4979
- # function getclaimpathactionspecs(s::State, player_idx::Int; log=false)
4980
- # action_specs = ActionSpec[]
4981
- # available_path_statuses = getavailablepaths(s, player_idx)
4982
- # paths = map(available_path_statuses) do available_path_status
4983
- # (; num, sample_fulfillment) = available_path_status
4984
- # fulfillment_sorted = Base.sort(sample_fulfillment; by=x -> x.segment_num)
4985
- # sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
4986
- # fulfillment_str = join(sample_fulfillment, "-")
4987
- # PathCombos(num, fulfillment_str, sample_fulfillment)
4988
- # end
4989
- # if !isempty(paths)
4990
- # push!(
4991
- # action_specs,
4992
- # ActionSpec(
4993
- # action_name=CLAIM_PATH,
4994
- # player_idx=player_idx,
4995
- # paths=paths,
4996
- # )
4997
- # )
4998
- # end
4999
- # action_specs
5000
- # end
5001
- def getclaimpathactionspecs(s, player_idx, log=False):
5002
- action_specs = []
5003
- available_path_statuses = getavailablepathstatuses(s, player_idx)
5004
-
5005
- def process_path_status(available_path_status):
5006
- num = available_path_status.num
5007
- sample_fulfillment = available_path_status.sample_fulfillment
5008
- fulfillment_sorted = sorted(sample_fulfillment, key=lambda x: x.segment_num)
5009
- sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
5010
- fulfillment_str = '-'.join(map(str, sample_fulfillment))
5011
- return PathCombos(
5012
- path_idx=(num-1),
5013
- default_combo=fulfillment_str,
5014
- sample_fulfillment=sample_fulfillment
5015
- )
5016
-
5017
- paths = list(map(process_path_status, available_path_statuses))
5018
-
5019
- if paths:
5020
- action_specs.append(
5021
- ActionSpec(
5022
- player_idx=player_idx,
5023
- action_name="CLAIM_PATH",
5024
- return_route_option_sets = [],
5025
- draw_faceup_spots={},
5026
- points=[],
5027
- paths=paths,
5028
- )
5029
- )
5030
-
5031
- return action_specs
5032
-
5033
-
5034
- # Implementing the following Julia function:
5035
- # function getavailablepaths(s::State, player_num::Int)
5036
- # balance = s.player_hands[player_num].unit_cards
5037
- # path_statuses = map(getpotentialpathnums(s, player_num)) do path_num
5038
- # getpathstatus(s, player_num, path_num)
5039
- # end
5040
- # filter(x -> x.fulfillable, path_statuses)
5041
- # end
5042
- def getavailablepathstatuses(s, player_num):
5043
- balance = s.player_hands[player_num].unit_cards
5044
- path_statuses = [
5045
- getpathstatus(s, player_num, path_idx)
5046
- for path_idx in getpotentialpathidxs(s, player_num)
5047
- ]
5048
- return list(filter(lambda x: x.fulfillable, path_statuses))
5049
-
5050
4539
 
5051
4540
  # Implementing the following Julia function:
5052
4541
  # function getpotentialpathnums(s::State, player_num::Int)
@@ -5275,409 +4764,9 @@ def getclaimedpathidxs(s):
5275
4764
  return claimed
5276
4765
 
5277
4766
 
5278
- # Implementing the following Julia function:
5279
- # function getpathstatus(s::State, player_idx, path_num)
5280
- # balance = s.player_hands[player_idx].unit_cards
5281
- # (; fig) = s
5282
- # (; board_config) = fig
5283
- # (; deck_units, board_paths) = board_config
5284
- # unituuid2deckunit = Dict(x.unit_uuid => x for x in deck_units)
5285
- # path = board_paths[path_num]
5286
- # ordered_segments = prioritysort(fig, path.path.segments)
5287
- # fulfillment = OrderedFullfillment[]
5288
- # wild_unit_uuids = getwildunituuids(fig)
5289
- # # @show wild_unit_uuids
5290
- # non_wild_unit_uuids = getnonwildunituuids(fig)
5291
- # # @show non_wild_unit_uuids
5292
-
5293
- # # @show balance
5294
-
5295
- # balance_unituuid2deckcardnums = Dict()
5296
- # for deck_card_num in balance
5297
- # unit_uuid = getunituuid(fig, deck_card_num)
5298
- # if !haskey(balance_unituuid2deckcardnums, unit_uuid)
5299
- # balance_unituuid2deckcardnums[unit_uuid] = []
5300
- # end
5301
- # push!(balance_unituuid2deckcardnums[unit_uuid], deck_card_num)
5302
- # end
5303
4767
 
5304
- # # @show balance_unituuid2deckcardnums
5305
4768
 
5306
- # function hasexactunitmatch(unit_uuid)
5307
- # (
5308
- # haskey(balance_unituuid2deckcardnums, unit_uuid) &&
5309
- # length(balance_unituuid2deckcardnums[unit_uuid]) > 0
5310
- # )
5311
- # end
5312
4769
 
5313
- # function anywildsleft()
5314
- # for wild_unit_uuid in wild_unit_uuids
5315
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5316
- # if !isempty(balance_unituuid2deckcardnums[wild_unit_uuid])
5317
- # return true
5318
- # end
5319
- # end
5320
- # end
5321
- # false
5322
- # end
5323
-
5324
- # function gettotalwildcount()
5325
- # count = 0
5326
- # for wild_unit_uuid in wild_unit_uuids
5327
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5328
- # count += length(balance_unituuid2deckcardnums[wild_unit_uuid])
5329
- # end
5330
- # end
5331
- # count
5332
- # end
5333
-
5334
- # function popawildcard!()
5335
- # for wild_unit_uuid in wild_unit_uuids
5336
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5337
- # if !isempty(balance_unituuid2deckcardnums[wild_unit_uuid])
5338
- # return pop!(balance_unituuid2deckcardnums[wild_unit_uuid])
5339
- # end
5340
- # end
5341
- # end
5342
- # nothing
5343
- # end
5344
-
5345
- # function getnonemptywildstack()
5346
- # for wild_unit_uuid in wild_unit_uuids
5347
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5348
- # if !isempty(balance_unituuid2deckcardnums[wild_unit_uuid])
5349
- # return balance_unituuid2deckcardnums[wild_unit_uuid]
5350
- # end
5351
- # end
5352
- # end
5353
- # nothing
5354
- # end
5355
-
5356
- # function getlargestnonwildstack()
5357
- # largest_non_wild_unit_uuid = nothing
5358
- # largest_found = 0
5359
- # for non_wild_unit_uuid in non_wild_unit_uuids
5360
- # if haskey(balance_unituuid2deckcardnums, non_wild_unit_uuid)
5361
- # curr_length = length(balance_unituuid2deckcardnums[non_wild_unit_uuid])
5362
- # if curr_length > largest_found
5363
- # largest_found = curr_length
5364
- # largest_non_wild_unit_uuid = non_wild_unit_uuid
5365
- # end
5366
- # end
5367
- # end
5368
- # if !isnothing(largest_non_wild_unit_uuid)
5369
- # return balance_unituuid2deckcardnums[largest_non_wild_unit_uuid]
5370
- # end
5371
- # nothing
5372
- # end
5373
-
5374
- # for ordered_segment in ordered_segments
5375
- # target_segment = ordered_segment.segment
5376
- # segment_num = ordered_segment.path_segment_num
5377
- # (; unit_uuid) = target_segment
5378
- # # @show unit_uuid
5379
- # # @show keys(unituuid2deckunit)
5380
- # target_unit = isnothing(unit_uuid) ? nothing : unituuid2deckunit[unit_uuid]
5381
- # # @show target_unit
5382
-
5383
- # if isnothing(target_unit)
5384
- # # do nothing (this is a blank segment)
5385
- # elseif target_unit.is_wild
5386
- # if hasexactunitmatch(unit_uuid)
5387
- # popped = pop!(balance_unituuid2deckcardnums[unit_uuid])
5388
- # push!(fulfillment, OrderedFullfillment(segment_num, popped))
5389
- # end
5390
- # else
5391
- # # @show 3
5392
- # if hasexactunitmatch(unit_uuid)
5393
- # # @show 4
5394
- # popped = pop!(balance_unituuid2deckcardnums[unit_uuid])
5395
- # push!(fulfillment, OrderedFullfillment(segment_num, popped))
5396
- # elseif anywildsleft()
5397
- # # @show 5
5398
- # non_empty_wild_stack = getnonemptywildstack()
5399
- # popped = pop!(non_empty_wild_stack)
5400
- # push!(fulfillment, OrderedFullfillment(segment_num, popped))
5401
- # end
5402
- # end
5403
- # end
5404
-
5405
- # blank_remaining_segments = filter(
5406
- # ordered_segment -> isblank(ordered_segment.segment.unit_uuid),
5407
- # ordered_segments,
5408
- # )
5409
- # # @show blank_remaining_segments
5410
- # largest_non_wild_stack = getlargestnonwildstack()
5411
- # # @show largest_non_wild_stack
5412
- # for blank_remaining_segment in blank_remaining_segments
5413
- # if !isnothing(largest_non_wild_stack) && !isempty(largest_non_wild_stack)
5414
- # popped = pop!(largest_non_wild_stack)
5415
- # push!(fulfillment, OrderedFullfillment(blank_remaining_segment.path_segment_num, popped))
5416
- # elseif gettotalwildcount() > 0
5417
- # popped = popawildcard!()
5418
- # push!(fulfillment, OrderedFullfillment(blank_remaining_segment.path_segment_num, popped))
5419
- # end
5420
- # end
5421
-
5422
- # # @show fulfillment
5423
- # deepq_edges = map(ordered_segments) do ordered_segment
5424
- # (; path_segment_num) = ordered_segment
5425
- # (; segment) = ordered_segment
5426
- # fullfillable_by_me = in(path_segment_num, [x.segment_num for x in fulfillment])
5427
- # captured_by_me = in(path_num, s.player_hands[player_idx].paths)
5428
- # captured_by_other = !captured_by_me && in(path_num, getclaimedpathidxs(s))
5429
- # available_to_me = !(captured_by_me || captured_by_other) && fullfillable_by_me
5430
- # status = "Other"
5431
- # if captured_by_me
5432
- # status = "CapturedByMe"
5433
- # elseif captured_by_other
5434
- # status = "CapturedByOther"
5435
- # elseif available_to_me
5436
- # status = "AvailableToMe"
5437
- # end
5438
- # SegmentStatus(
5439
- # path_num,
5440
- # path_segment_num,
5441
- # captured_by_me,
5442
- # captured_by_other,
5443
- # available_to_me,
5444
- # status,
5445
- # segment,
5446
- # )
5447
- # end
5448
-
5449
- # fulfillable = Base.all([x.available_to_me for x in deepq_edges])
5450
- # PathStatus(path_num, fulfillable, deepq_edges, fulfillment)
5451
- # end
5452
- def getpathstatus(s, player_idx, path_idx):
5453
- path_num = path_idx + 1
5454
- balance = s.player_hands[player_idx].unit_cards
5455
- fig = s.game_config.fig
5456
- board_config = fig.board_config
5457
- deck_units = board_config.deck_units
5458
- board_paths = board_config.board_paths
5459
- unituuid2deckunit = {x.unit_uuid: x for x in deck_units}
5460
- path = board_paths[path_idx]
5461
- ordered_segments = prioritysort(fig, path.path.segments)
5462
- fulfillment = []
5463
- wild_unit_uuids = getwildunituuids(fig)
5464
- non_wild_unit_uuids = getnonwildunituuids(fig)
5465
-
5466
- balance_unituuid2deckcardnums = {}
5467
-
5468
- for deck_card_num in balance:
5469
- unit_uuid = getunituuid(fig, deck_card_num)
5470
- if unit_uuid not in balance_unituuid2deckcardnums:
5471
- balance_unituuid2deckcardnums[unit_uuid] = []
5472
- balance_unituuid2deckcardnums[unit_uuid].append(deck_card_num)
5473
-
5474
- def hasexactunitmatch(unit_uuid):
5475
- # print("unit_uuid: ", unit_uuid)
5476
- # print("balance_unituuid2deckcardnums: ", balance_unituuid2deckcardnums)
5477
- print("")
5478
- return (
5479
- unit_uuid in balance_unituuid2deckcardnums and
5480
- len(balance_unituuid2deckcardnums[unit_uuid]) > 0
5481
- )
5482
-
5483
- def anywildsleft():
5484
- for wild_unit_uuid in wild_unit_uuids:
5485
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5486
- if balance_unituuid2deckcardnums[wild_unit_uuid]:
5487
- return True
5488
- return False
5489
-
5490
- def gettotalwildcount():
5491
- count = 0
5492
- for wild_unit_uuid in wild_unit_uuids:
5493
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5494
- count += len(balance_unituuid2deckcardnums[wild_unit_uuid])
5495
- return count
5496
-
5497
- def popawildcard():
5498
- for wild_unit_uuid in wild_unit_uuids:
5499
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5500
- if balance_unituuid2deckcardnums[wild_unit_uuid]:
5501
- return balance_unituuid2deckcardnums[wild_unit_uuid].pop()
5502
- return None
5503
-
5504
- def getnonemptywildstack():
5505
- for wild_unit_uuid in wild_unit_uuids:
5506
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5507
- if balance_unituuid2deckcardnums[wild_unit_uuid]:
5508
- return balance_unituuid2deckcardnums[wild_unit_uuid]
5509
- return None
5510
-
5511
- def getlargestnonwildstack():
5512
- largest_non_wild_unit_uuid = None
5513
- largest_found = 0
5514
- for non_wild_unit_uuid in non_wild_unit_uuids:
5515
- if non_wild_unit_uuid in balance_unituuid2deckcardnums:
5516
- curr_length = len(balance_unituuid2deckcardnums[non_wild_unit_uuid])
5517
- if curr_length > largest_found:
5518
- largest_found = curr_length
5519
- largest_non_wild_unit_uuid = non_wild_unit_uuid
5520
- if largest_non_wild_unit_uuid is not None:
5521
- return balance_unituuid2deckcardnums[largest_non_wild_unit_uuid]
5522
- return None
5523
-
5524
- for ordered_segment in ordered_segments:
5525
- target_segment = ordered_segment.segment
5526
- segment_num = ordered_segment.path_segment_num
5527
- unit_uuid = target_segment.unit_uuid
5528
- target_unit = None if unit_uuid is None else unituuid2deckunit[unit_uuid]
5529
-
5530
- if target_unit is None:
5531
- # do nothing (this is a blank segment)
5532
- pass
5533
- elif target_unit.is_wild:
5534
- if hasexactunitmatch(unit_uuid):
5535
- popped = balance_unituuid2deckcardnums[unit_uuid].pop()
5536
- fulfillment.append(OrderedFullfillment(segment_num=segment_num, unit_card_num=popped))
5537
- else:
5538
- # print("anywildsleft(): ", anywildsleft())
5539
- if hasexactunitmatch(unit_uuid):
5540
- popped = balance_unituuid2deckcardnums[unit_uuid].pop()
5541
- fulfillment.append(OrderedFullfillment(segment_num=segment_num, unit_card_num=popped))
5542
- elif anywildsleft():
5543
- non_empty_wild_stack = getnonemptywildstack()
5544
- popped = non_empty_wild_stack.pop()
5545
- fulfillment.append(OrderedFullfillment(segment_num=segment_num, unit_card_num=popped))
5546
- # @show 5
5547
-
5548
- blank_remaining_segments = list(filter(
5549
- lambda ordered_segment: ordered_segment.segment.unit_uuid is None,
5550
- ordered_segments,
5551
- ))
5552
-
5553
- largest_non_wild_stack = getlargestnonwildstack()
5554
-
5555
- for blank_remaining_segment in blank_remaining_segments:
5556
- if largest_non_wild_stack is not None and largest_non_wild_stack:
5557
- popped = largest_non_wild_stack.pop()
5558
- fulfillment.append(OrderedFullfillment(segment_num=blank_remaining_segment.path_segment_num, unit_card_num=popped))
5559
- elif gettotalwildcount() > 0:
5560
- popped = popawildcard()
5561
- fulfillment.append(OrderedFullfillment(segment_num=blank_remaining_segment.path_segment_num, unit_card_num=popped))
5562
-
5563
- # Implementing the following Julia code:
5564
- # deepq_edges = map(ordered_segments) do ordered_segment
5565
- # (; path_segment_num) = ordered_segment
5566
- # (; segment) = ordered_segment
5567
- # fullfillable_by_me = in(path_segment_num, [x.segment_num for x in fulfillment])
5568
- # captured_by_me = in(path_num, s.player_hands[player_idx].paths)
5569
- # captured_by_other = !captured_by_me && in(path_num, getclaimedpathidxs(s))
5570
- # available_to_me = !(captured_by_me || captured_by_other) && fullfillable_by_me
5571
- # status = "Other"
5572
- # if captured_by_me
5573
- # status = "CapturedByMe"
5574
- # elseif captured_by_other
5575
- # status = "CapturedByOther"
5576
- # elseif available_to_me
5577
- # status = "AvailableToMe"
5578
- # end
5579
- # SegmentStatus(
5580
- # path_num,
5581
- # path_segment_num,
5582
- # captured_by_me,
5583
- # captured_by_other,
5584
- # available_to_me,
5585
- # status,
5586
- # segment,
5587
- # )
5588
- # end
5589
- # fulfillable = Base.all([x.available_to_me for x in deepq_edges])
5590
- # PathStatus(path_num, fulfillable, deepq_edges, fulfillment)
5591
- deepq_edges = []
5592
- for ordered_segment in ordered_segments:
5593
- path_segment_num = ordered_segment.path_segment_num
5594
- segment = ordered_segment.segment
5595
- fullfillable_by_me = path_segment_num in [x.segment_num for x in fulfillment]
5596
- captured_by_me = path_idx in s.player_hands[player_idx].paths
5597
- captured_by_other = not captured_by_me and path_idx in getclaimedpathidxs(s)
5598
- available_to_me = not (captured_by_me or captured_by_other) and fullfillable_by_me
5599
- status = "Other"
5600
- if captured_by_me:
5601
- status = "CapturedByMe"
5602
- elif captured_by_other:
5603
- status = "CapturedByOther"
5604
- elif available_to_me:
5605
- status = "AvailableToMe"
5606
-
5607
- deepq_edges.append(
5608
- SegmentStatus(
5609
- path_idx=path_idx,
5610
- path_num=path_num,
5611
- path_segment_num=path_segment_num,
5612
- captured_by_me=captured_by_me,
5613
- captured_by_other=captured_by_other,
5614
- available_to_me=available_to_me,
5615
- status=status,
5616
- segment=segment
5617
- )
5618
- )
5619
-
5620
- fulfillable = all([x.available_to_me for x in deepq_edges])
5621
- return PathStatus(
5622
- idx=path_idx,
5623
- num=path_num,
5624
- fulfillable=fulfillable,
5625
- segment_statuses=deepq_edges,
5626
- sample_fulfillment=fulfillment
5627
- )
5628
-
5629
-
5630
- # Implementing the following Julia function:
5631
- # function getavailablepoints(s::State, player_num::Int)
5632
- # point_statuses = map(getpotentialpointuuids(s, player_num)) do point_uuid
5633
- # getpointstatus(s, player_num, point_uuid)
5634
- # end
5635
- # sort(filter(x -> x.fulfillable, point_statuses); by=x -> x.uuid)
5636
- # end
5637
- def getavailablepoints(s, player_num):
5638
- point_statuses = [
5639
- getpointstatus(s, player_num, point_uuid)
5640
- for point_uuid in getpotentialpointuuids(s, player_num)
5641
- ]
5642
- return sorted(
5643
- filter(lambda x: x['fulfillable'], point_statuses),
5644
- key=lambda x: x['uuid']
5645
- )
5646
-
5647
- # Implementing the following Julia function:
5648
- # function getpointstatus(s::State, player_idx::Int, point_uuid::UUID)
5649
- # balance = s.player_hands[player_idx].unit_cards
5650
- # fulfillment = OrderedPointFullfillment[]
5651
- # if !isempty(balance)
5652
- # push!(fulfillment, OrderedPointFullfillment(balance[1]))
5653
- # end
5654
- # PointStatus(point_uuid, true, fulfillment)
5655
- # end
5656
- def getpointstatus(s, player_idx, point_uuid):
5657
- balance = s.player_hands[player_idx].unit_cards
5658
- fulfillment = []
5659
- if balance:
5660
- fulfillment.append({'unit_card_num': balance[0]})
5661
- return {
5662
- 'uuid': point_uuid,
5663
- 'fulfillable': True,
5664
- 'sample_fulfillment': fulfillment
5665
- }
5666
-
5667
- # Implementing the following Julia function:
5668
- # function getpotentialpointuuids(s::State, player_num::Int)
5669
- # (; num_point_pieces) = s.player_hands[player_num]
5670
- # setdiff(
5671
- # Set(getnodeuuids(s.fig, num_point_pieces)),
5672
- # Set(getunavailablepoints(s)),
5673
- # ) |> collect
5674
- # end
5675
- def getpotentialpointuuids(s, player_num):
5676
- num_point_pieces = s.player_hands[player_num].num_point_pieces
5677
- return list(
5678
- set(getnodeuuids(s.game_config.fig, num_point_pieces)) -
5679
- set(getunavailablepoints(s))
5680
- )
5681
4770
 
5682
4771
  # Implementing the following Julia function:
5683
4772
  # function getnodeuuids(f::Fig, remaining_pieces::Int)
@@ -5714,33 +4803,6 @@ def getunavailablepoints(s):
5714
4803
  return unavailable_points
5715
4804
 
5716
4805
 
5717
- # Implementing the following Julia function:
5718
- # function calcfinalscores(s::State)
5719
- # if !s.terminal
5720
- # return s
5721
- # end
5722
- # @reset s.player_hands = calcfinalscore.(s, s.player_hands)
5723
- # s
5724
- # end
5725
- @dispatch(State)
5726
- def calcfinalscores(s):
5727
- if not s.terminal:
5728
- return s
5729
- return s.set(player_hands=pvector([calcfinalscore(s, h) for h in s.player_hands]))
5730
-
5731
-
5732
- # Implementing the following Julia function:
5733
- # function calcfinalscore(s::State, hand::PlayerInfo)
5734
- # (; total, breakdown) = getprivatescore(s, hand)
5735
- # @reset hand.final_score = PlayerScore(total, breakdown)
5736
- # hand
5737
- # end
5738
- @dispatch(State, PlayerInfo)
5739
- def calcfinalscore(s, hand):
5740
- total, breakdown = getprivatescore(s, hand)
5741
- return hand.set(final_score=PlayerScore(total=total, breakdown=breakdown))
5742
-
5743
-
5744
4806
  # Implementing the following Julia function:
5745
4807
  # function calcwinners(s::State)
5746
4808
  # if !s.terminal
@@ -5764,158 +4826,15 @@ def calcwinners(s):
5764
4826
 
5765
4827
 
5766
4828
  def printplayer(s, player_idx):
5767
- hand = s.player_hands[player_idx]
5768
- legal_actions = getlegalactionspecs(s, player_idx)
5769
- print(f"~~~~~~~~~~~~ P{player_idx} ~~~~~~~~~~~~")
5770
- print(f"private score: {getprivatescore(s, hand)}")
5771
- print(f"public score: {getpublicscore(s, player_idx)}")
5772
- print(f"completed clusters: {list(str(c) for c in hand.completed_clusters)}")
5773
- print(f"units: {list(hand.unit_cards)}")
5774
- if getsettingvalue(s, "route_scoring"):
5775
- print(f"routes: {list(hand.route_cards)} choices:{list(hand.new_route_cards)}")
5776
- print(f"captured points: {list(str(p) for p in hand.points)}")
5777
- print(f"legal actions: {list(a.action_name for a in legal_actions)}")
4829
+ pass
5778
4830
 
5779
4831
 
5780
4832
  def printstate(s):
5781
- print(f"*************** State {state_idx} ***************")
5782
- print(f"Last to play: {s.last_to_play}")
5783
- print(f"Winners: {list(s.winners)}")
5784
- print(f"Route Deck: {list(s.route_cards)}")
5785
- print(f"Route Disc: {list(s.route_discards)}")
5786
- print(f"Unit Deck: ...{list(s.unit_cards[60:])}")
5787
- print(f"Unit Disc: {list(s.unit_discards)}")
5788
- print(f"FaceUp: {list(s.faceup_spots)}")
5789
- print(f"ToPlay: {gettoplay(s)}")
5790
- print(f"Terminal: {s.terminal}")
5791
-
5792
- for i in range(s.game_config.num_players):
5793
- printplayer(s, i)
5794
- print(f"****************************************\n")
4833
+ pass
5795
4834
 
5796
4835
 
5797
4836
  def printaction(a, i):
5798
- print(f"\n\n*************** Action {i} ***************")
5799
- print(f"{a}")
5800
- print(f"****************************************\n\n\n")
5801
-
5802
-
5803
- # Implementing the following Julia function:
5804
- # function getprivatescore(s::State, hand::PlayerInfo; bonus=true)
5805
- # player_idx = hand.player_idx
5806
- # breakdown = []
5807
-
5808
- # # Path scores
5809
- # if getsettingvalue(s, :path_scoring)
5810
- # (; path_scores) = s.fig
5811
- # for len in getplayerpathlens(s, player_idx)
5812
- # push!(
5813
- # breakdown,
5814
- # ScoreItem(
5815
- # code_idx=getscorecodeidx(s.fig, :PATH),
5816
- # amount=path_scores[len],
5817
- # )
5818
- # )
5819
- # end
5820
- # end
5821
-
5822
- # # Bonus: most clusters
5823
- # if getsettingvalue(s, :most_clusters_bonus)
5824
- # bonus_most_clusters_score = getsettingvalue(s.fig, :bonus_most_clusters_score)
5825
- # if in(player_idx, s.most_clusters_player_idxs)
5826
- # push!(
5827
- # breakdown,
5828
- # ScoreItem(
5829
- # code_idx=getscorecodeidx(s.fig, :MOST_CLUSTERS),
5830
- # amount=bonus_most_clusters_score,
5831
- # )
5832
- # )
5833
- # end
5834
- # end
5835
- #
5836
- # # Completed routes
5837
- # if getsettingvalue(s, :route_scoring)
5838
- # hand = s.player_hands[player_idx]
5839
- # (; board_config) = s.fig
5840
- # (; routes) = board_config
5841
- # for route_idx in hand.route_cards
5842
- # route_score = routes[route_idx].score
5843
- # amount = in(route_idx, hand.completed_routes) ? route_score : -1*route_score
5844
- # push!(
5845
- # breakdown,
5846
- # ScoreItem(
5847
- # code_idx=getscorecodeidx(s.fig, :ROUTE),
5848
- # amount=amount
5849
- # )
5850
- # )
5851
- # end
5852
- # end
5853
-
5854
- # # Completed clusters
5855
- # if getsettingvalue(s, :cluster_scoring)
5856
- # (; clusters) = s.fig.board_config
5857
- # uuid2cluster = Dict((x.uuid, x) for x in clusters)
5858
- # (; completed_clusters) = s.player_hands[player_idx]
5859
- # cluster_scores = map(completed_clusters) do cluster_uuid
5860
- # uuid2cluster[cluster_uuid].score
5861
- # end
5862
- # if !isempty(cluster_scores)
5863
- # push!(breakdown,
5864
- # ScoreItem(
5865
- # code_idx=getscorecodeidx(s.fig, :CLUSTER),
5866
- # amount=sum(cluster_scores)
5867
- # )
5868
- # )
5869
- # end
5870
- # end
5871
-
5872
- # amounts = [item.amount for item in breakdown]
5873
- # total = sum(amounts; init=0)
5874
- # (
5875
- # total=total,
5876
- # breakdown=breakdown,
5877
- # )
5878
- # end
5879
- @dispatch(State, PlayerInfo)
5880
- def getprivatescore(s, hand):
5881
- player_idx = hand.player_idx
5882
- breakdown = []
5883
-
5884
- # Path scores
5885
- if getsettingvalue(s, 'path_scoring'):
5886
- path_scores = s.game_config.fig.path_scores
5887
- for len in getplayerpathlens(s, player_idx):
5888
- breakdown.append(ScoreItem(
5889
- code_idx=getscorecodeidx(s.game_config.fig, 'PATH'),
5890
- amount=path_scores[len],
5891
- ))
5892
-
5893
- # Completed routes
5894
- if False and getsettingvalue(s, 'route_scoring'):
5895
- routes = s.game_config.fig.board_config.routes
5896
- for route_idx in hand.route_cards:
5897
- route_score = routes[route_idx].score
5898
- amount = route_score if route_idx in hand.completed_routes else -1 * route_score
5899
- breakdown.append(ScoreItem(
5900
- code_idx=getscorecodeidx(s.game_config.fig, 'ROUTE'),
5901
- amount=amount
5902
- ))
5903
-
5904
- # Completed clusters
5905
- if getsettingvalue(s, 'cluster_scoring'):
5906
- clusters = s.game_config.fig.board_config.clusters
5907
- uuid2cluster = {x.uuid: x for x in clusters}
5908
- completed_clusters = hand.completed_clusters
5909
- cluster_scores = [uuid2cluster[cluster_uuid].score for cluster_uuid in completed_clusters]
5910
- if cluster_scores:
5911
- breakdown.append(ScoreItem(
5912
- code_idx=getscorecodeidx(s.game_config.fig, 'CLUSTER'),
5913
- amount=sum(cluster_scores)
5914
- ))
5915
-
5916
- amounts = [item.amount for item in breakdown]
5917
- total = sum(amounts)
5918
- return total, breakdown
4837
+ pass
5919
4838
 
5920
4839
 
5921
4840
  # Implementing the following Julia function:
@@ -5954,46 +4873,6 @@ def getscorecodes(f):
5954
4873
  return score_codes
5955
4874
 
5956
4875
 
5957
- # Implementing the following Julia function:
5958
- # function assertunitcardsaccountedfor(s::State)
5959
- # total_num_unit_cards = gettotaldeckcards(s.fig)
5960
- # total_found = getunitcardstotalfound(s)
5961
- # @assert total_num_unit_cards == total_found "Unit cards not accounted for. $(total_num_unit_cards) != $(total_found)"
5962
- # end
5963
- def assertunitcardsaccountedfor(s):
5964
- total_num_unit_cards = gettotaldeckcards(s.game_config.fig)
5965
- total_found = getunitcardstotalfound(s)
5966
- assert total_num_unit_cards == total_found, f"Unit cards not accounted for. {total_num_unit_cards} != {total_found}"
5967
-
5968
-
5969
- # Implementing the following Julia function:
5970
- # function getunitcardstotalfound(s::State)
5971
- # num_player_unit_cards = sum(gettotalnumunitcards.(s.player_hands))
5972
- # total_found = sum([
5973
- # num_player_unit_cards,
5974
- # length(s.unit_discards),
5975
- # length(s.unit_cards),
5976
- # length(getvalidspotnums(s)),
5977
- # ])
5978
- # total_found
5979
- # end
5980
- def getunitcardstotalfound(s):
5981
- num_player_unit_cards = sum(gettotalnumunitcards(p) for p in s.player_hands)
5982
- total_found = sum([
5983
- num_player_unit_cards,
5984
- len(s.unit_discards),
5985
- len(s.unit_cards),
5986
- len(getvalidspotnums(s)),
5987
- ])
5988
- return total_found
5989
-
5990
-
5991
- # Implementing the following Julia function:
5992
- # gettotalnumunitcards(player_hand::PlayerInfo) = length(player_hand.unit_cards)
5993
- def gettotalnumunitcards(player_hand):
5994
- return len(player_hand.unit_cards)
5995
-
5996
-
5997
4876
  # Implementing the following Julia function:
5998
4877
  # function getvalidspotnums(s::State)
5999
4878
  # filter(n -> !isnothing(s.faceup_spots[n]), 1:length(s.faceup_spots))
@@ -6002,44 +4881,6 @@ def getvalidspotnums(s):
6002
4881
  return [n for n in range(1, len(s.faceup_spots) + 1) if s.faceup_spots[n-1] is not None]
6003
4882
 
6004
4883
 
6005
- # Implementing the following Julia function:
6006
- # function assertroutecardsaccountedfor(s::State)
6007
- # total_num_route_cards = getnumroutecards(s.fig)
6008
- # num_player_route_cards = sum(gettotalnumroutecards.(s.player_hands))
6009
- # total_found = sum([
6010
- # num_player_route_cards,
6011
- # length(s.route_discards),
6012
- # length(s.route_cards),
6013
- # ])
6014
- # @assert total_num_route_cards == total_found "Route cards not accounted for. $(total_num_route_cards) != $(total_found)"
6015
- # end
6016
- def assertroutecardsaccountedfor(s):
6017
- total_num_route_cards = getnumroutecards(s.game_config.fig)
6018
- num_player_route_cards = sum(gettotalnumroutecards(p) for p in s.player_hands)
6019
- total_found = sum([
6020
- num_player_route_cards,
6021
- len(s.route_discards),
6022
- len(s.route_cards),
6023
- ])
6024
- assert total_num_route_cards == total_found, f"Route cards not accounted for. {total_num_route_cards} != {total_found}"
6025
-
6026
-
6027
- # Implementing the following Julia function:
6028
- # gettotalnumroutecards(player_hand::PlayerInfo) = length(player_hand.route_cards) + length(player_hand.new_route_cards)
6029
- def gettotalnumroutecards(player_hand):
6030
- return len(player_hand.route_cards) + len(player_hand.new_route_cards)
6031
-
6032
-
6033
- # Implementing the following Julia function:
6034
- # function assertallcardsaccountedfor(s::State)
6035
- # assertroutecardsaccountedfor(s)
6036
- # assertunitcardsaccountedfor(s)
6037
- # end
6038
- def assertallcardsaccountedfor(s):
6039
- assertroutecardsaccountedfor(s)
6040
- assertunitcardsaccountedfor(s)
6041
-
6042
-
6043
4884
  # Implementing the following Julia function:
6044
4885
  # function getlegalactions(s::State)
6045
4886
  # getlegalactions(s, gettoplay(s))
@@ -6126,7 +4967,6 @@ def getprivatestate(s, player_idx):
6126
4967
  player=s.players[player_idx],
6127
4968
  legal_actions_2 = get_legal_actions(s, player_idx),
6128
4969
  legal_actions=legal_actions,
6129
- hand=s.player_hands[player_idx],
6130
4970
  goal_completions=goal_completions,
6131
4971
  )
6132
4972
 
@@ -6274,132 +5114,92 @@ def diff(A, dims=None):
6274
5114
  return [[A[i][j] - A[i][j - 1] for j in range(1, len(A[0]))] for i in range(len(A))]
6275
5115
  else:
6276
5116
  raise ValueError("dims must be either 1 or 2")
6277
-
6278
5117
 
6279
- @dispatch(StaticBoardConfig, PlayerState)
6280
- def get_imagined_state(static_board_config, player_state):
6281
- board_config = static_board_config.board_config
6282
- public_state = player_state.public
6283
- private_state = player_state.private
6284
- my_hand = private_state.hand
6285
-
6286
- fig = initfig("af472d67-05ec-4b5d-9eb7-6b0cea9eec5a", board_config)
6287
- seed = 4012489341 # TODO: this should be random (or if non-stochastic, loaded from the net.seed)
6288
- rng = getrng(seed)
6289
-
6290
- # TODO: this needs to come from x_json['game_config']
6291
- game_config = GameConfig(
6292
- uuid = str(generate_uuid_with_rng(rng)),
6293
- started_at = "2025-01-01 00:00:00",
6294
- num_players = 2,
6295
- fig = fig,
6296
- seed = seed
6297
- )
6298
5118
 
6299
- possible_route_card_idxs = list(range(getnumroutecards(fig)))
6300
- possible_unit_card_idxs = list(range(gettotaldeckcards(fig)))
5119
+ def get_default_toplay(s):
5120
+ if s.legal_actions_2:
5121
+ return s.legal_actions_2[0].player_idx
5122
+ return None
6301
5123
 
6302
- def remove_card_idx(to_mutate, card_idx):
6303
- if card_idx in to_mutate:
6304
- to_mutate.remove(card_idx)
6305
5124
 
6306
- def remove_card_idxs(to_mutate, card_idxs):
6307
- for card_idx in card_idxs:
6308
- remove_card_idx(to_mutate, card_idx)
5125
+ def get_intuited_best_actions(ps):
5126
+ if not ps.legal_actions_2:
5127
+ return None
5128
+ return ps.legal_actions_2[:8]
6309
5129
 
6310
-
6311
- # imagined_route_card_idxs = rng.sample(possible_route_card_idxs, public_state.num_route_cards)
6312
- remove_card_idxs(possible_route_card_idxs, imagined_route_card_idxs)
6313
- # imagined_route_discard_idxs = rng.sample(possible_route_card_idxs, public_state.num_route_discards)
6314
- remove_card_idxs(possible_route_card_idxs, imagined_route_discard_idxs)
6315
5130
 
6316
- imagined_route_cards = [x+1 for x in imagined_route_card_idxs]
6317
- imagined_route_discards = [x+1 for x in imagined_route_discard_idxs]
5131
+ def get_spread(q_values, p_idx):
5132
+ my_q = q_values[p_idx]
5133
+ other_qs = [q for i, q in enumerate(q_values) if i != p_idx]
5134
+ spread = my_q - max(other_qs)
5135
+ return spread
6318
5136
 
6319
- for unit_card in public_state.unit_discards:
6320
- remove_card_idx(possible_unit_card_idxs, unit_card-1)
6321
5137
 
6322
- for unit_card in my_hand.unit_cards:
6323
- remove_card_idx(possible_unit_card_idxs, unit_card-1)
5138
+ def getvproxy0(ps):
5139
+ return 0
6324
5140
 
6325
- # imagined_unit_card_idxs = rng.sample(possible_unit_card_idxs, public_state.num_unit_cards)
6326
- # imagined_unit_cards = [x+1 for x in imagined_unit_card_idxs]
6327
- # remove_card_idxs(possible_unit_card_idxs, imagined_unit_card_idxs)
6328
5141
 
5142
+ def imagine_dynamics(ps, a):
5143
+ return dynamics(imagine_state(ps), a)
6329
5144
 
6330
- imagined_player_hands = []
6331
5145
 
6332
- for (player_idx, public_player_info) in enumerate(public_state.player_hands):
6333
- if player_idx == my_hand.player_idx:
6334
- imagined_player_hands.append(PlayerInfo.clone(my_hand))
6335
- else:
6336
- # imagined_player_unit_card_idxs = rng.sample(possible_unit_card_idxs, public_player_info.num_unit_cards)
6337
- imagined_player_unit_cards = [x+1 for x in imagined_player_unit_card_idxs]
6338
- remove_card_idxs(possible_unit_card_idxs, imagined_player_unit_card_idxs)
6339
- # imagined_player_route_card_idxs = rng.sample(possible_route_card_idxs, public_player_info.num_route_cards)
6340
- remove_card_idxs(possible_route_card_idxs, imagined_player_route_card_idxs)
6341
- imagined_player_new_route_card_idxs = rng.sample(possible_route_card_idxs, public_player_info.num_new_route_cards)
6342
- remove_card_idxs(possible_route_card_idxs, imagined_player_new_route_card_idxs)
6343
- imagined_player_route_cards = [x+1 for x in imagined_player_route_card_idxs]
6344
- imagined_player_new_route_cards = [x+1 for x in imagined_player_new_route_card_idxs]
6345
- imagined_player_hands.append(
6346
- PlayerInfo(
6347
- fig = fig,
6348
- player_idx = player_idx,
6349
- new_route_cards = pvector(imagined_player_new_route_cards), # Guess at this.
6350
- route_cards = pvector(imagined_player_route_cards), # Guess at this.
6351
- unit_cards = pvector(imagined_player_unit_cards), # Guess at this.
6352
- completed_routes = [], # Guess at this.
6353
- completed_clusters = public_player_info.completed_clusters,
6354
- paths = public_player_info.paths,
6355
- points = public_player_info.points,
6356
- tokens = public_player_info.tokens,
6357
- num_pieces = public_player_info.num_pieces,
6358
- num_point_pieces = public_player_info.num_point_pieces,
6359
- longest_trail = public_player_info.longest_trail,
6360
- longest_trail_len = public_player_info.longest_trail_len,
6361
- final_score = public_player_info.final_score,
6362
- )
6363
- )
5146
+ def dynamics(s, a):
5147
+ scores = get_public_player_scores(s)
5148
+ next_s = getnextstate2(s, a)
5149
+ next_scores = get_public_player_scores(next_s)
5150
+ rewards = [next_scores[i] - scores[i] for i in range(len(scores))]
5151
+ return next_s, rewards
6364
5152
 
6365
5153
 
6366
- nodeuuid2idx = {node.uuid: idx for idx, node in enumerate(board_config.points)}
6367
- edges = get_edges(rng, board_config, nodeuuid2idx)
6368
- edgeuuid2idx = {edge.uuid: idx for idx, edge in enumerate(edges)}
6369
- edgetuple2uuid = {}
6370
- for edge in edges:
6371
- node_1_idx = nodeuuid2idx[edge.node_1_uuid]
6372
- node_2_idx = nodeuuid2idx[edge.node_2_uuid]
6373
- edge_tuple = (min(node_1_idx, node_2_idx), max(node_1_idx, node_2_idx))
6374
- edgetuple2uuid[edge_tuple] = edge.uuid
6375
-
6376
- return State(
6377
- final_scores = None,
6378
- player_graphs = [],
6379
- nodes = get_nodes(board_config),
6380
- nodeuuid2idx = nodeuuid2idx,
6381
- edges = edges,
6382
- edgeuuid2idx = edgeuuid2idx,
6383
- edgetuple2uuid = edgetuple2uuid,
6384
- regions = get_regions(board_config),
6385
- legal_actions = [], # TODO: Should use PublicState, but empty for now.
6386
- piles = [], # TODO: Should use PublicState, but empty for now.
6387
- players = [], # TODO: Should use PublicState, but empty for now.
6388
- player_idxs = public_state.player_idxs,
6389
- decks = [], # TODO: Should use PublicState, but empty for now.
6390
- game_config = game_config,
6391
- rng = rng, # TODO: again figure out this stochasticity
6392
- terminal = public_state.terminal,
6393
- initial_to_play = public_state.initial_to_play,
6394
- route_cards = pvector(imagined_route_cards), # Guess at this.
6395
- route_discards = pvector(imagined_route_discards), # Guess at this.
6396
- player_hands = pvector(imagined_player_hands), # Guess at this.
6397
- unit_cards = pvector(imagined_unit_cards), # Guess at this.
6398
- faceup_spots = pvector(public_state.faceup_spots),
6399
- unit_discards = pvector(public_state.unit_discards),
6400
- last_to_play = public_state.last_to_play,
6401
- winners = public_state.winners,
6402
- )
5154
+ def alpha0(ps):
5155
+ td = 3
5156
+ legal_actions = ps.legal_actions_2
5157
+ if not legal_actions:
5158
+ return None
5159
+ intuited = get_intuited_best_actions(ps)
5160
+ q_proxies = [getqproxy0(ps, a, td) for a in intuited]
5161
+ max_spread_idx = get_max_spread_idx(q_proxies, ps.player.player_idx)
5162
+ return intuited[max_spread_idx]
5163
+
5164
+
5165
+ def get_max_spread_idx(q_proxies, p_idx):
5166
+ spreads = [get_spread(q_proxy, p_idx) for q_proxy in q_proxies]
5167
+ max_spread_idx = np.argmax(spreads)
5168
+ return max_spread_idx
5169
+
5170
+
5171
+ def getqproxy0(ps, a, td):
5172
+
5173
+ def qproxybase():
5174
+ next_s, rewards = imagine_dynamics(ps, a)
5175
+ if next_s.terminal:
5176
+ return rewards
5177
+ v_proxies = [
5178
+ getvproxy0(getprivatestate(next_s, i))
5179
+ for i in range(next_s.game_config.num_players)
5180
+ ]
5181
+ q_proxies = [
5182
+ r + v_proxies[i]
5183
+ for i, r in enumerate(rewards)
5184
+ ]
5185
+ return q_proxies
5186
+
5187
+ def qproxyrecurse():
5188
+ next_s, rewards = imagine_dynamics(ps, a)
5189
+ if next_s.terminal:
5190
+ return rewards
5191
+ next_p_idx = get_default_toplay(next_s)
5192
+ next_ps = getprivatestate(next_s, next_p_idx)
5193
+ next_p_idx = next_ps.player.player_idx
5194
+ next_intuited = get_intuited_best_actions(next_ps)
5195
+ competing_next_q_values = [getqproxy0(next_ps, a, td-1) for a in next_intuited]
5196
+ max_next_spread_idx = get_max_spread_idx(competing_next_q_values, next_p_idx)
5197
+ next_q_values = competing_next_q_values[max_next_spread_idx]
5198
+ q_values = [r + next_q_values[i] for i, r in enumerate(rewards)]
5199
+ return q_values
5200
+
5201
+ return qproxyrecurse() if td > 0 else qproxybase()
5202
+
6403
5203
 
6404
5204
  INIT_HOOK_1 = """def handler(game):
6405
5205
  return shuffle_all_decks(game)