graph-games-proto 0.3.1865__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,207 +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
- # num_route_cards::Int
1013
- # num_route_discards::Int
1014
- # num_unit_cards::Int
1015
- # num_unit_discards::Int
1016
- # faceup_spots::Vector{Union{Nothing,Int}}
1017
- # player_hands::Vector{PublicPlayerInfo}
1018
- # captured_segments::Vector{CapturedSegment}
1019
- # captured_points::Vector{CapturedPoint}
1020
- # last_to_play::Union{Nothing,Int}
1021
- # terminal::Bool
1022
- # winners::Vector{Int}
1023
- # market_refills::Vector{MarketRefill}
1024
-
1025
-
1026
- class AltAction(PClass):
1027
- player_idx = field(type=int)
1028
- action_name = field(type=str)
1029
- path_idx = field(type=(int, type(None)), initial=None)
1030
- return_route_cards = field(type=list, initial=[]) # List[int]
1031
- draw_faceup_unit_card_num = field(type=(int, type(None)), initial=None)
1032
- draw_faceup_spot_num = field(type=(int, type(None)), initial=None)
1033
- point_uuid = field(type=(str, type(None)), initial=None)
1034
- unit_combo = field(type=(str, type(None)), initial=None) # TODO: should be list of int
1035
- def __todict__(self):
1036
- return {
1037
- "player_idx": self.player_idx,
1038
- "action_name": self.action_name,
1039
- "path_idx": self.path_idx,
1040
- "return_route_cards": self.return_route_cards,
1041
- "draw_faceup_unit_card_num": self.draw_faceup_unit_card_num,
1042
- "draw_faceup_spot_num": self.draw_faceup_spot_num,
1043
- "point_uuid": self.point_uuid,
1044
- "unit_combo": self.unit_combo
1045
- }
1046
- @staticmethod
1047
- def __fromdict__(json_dict):
1048
- return AltAction(
1049
- player_idx=json_dict["player_idx"],
1050
- action_name=json_dict["action_name"],
1051
- path_idx=json_dict.get("path_idx", None), # Handle missing key gracefully
1052
- return_route_cards=json_dict.get("return_route_cards", []), # Handle missing key gracefully
1053
- draw_faceup_unit_card_num=json_dict.get("draw_faceup_unit_card_num", None), # Handle missing key gracefully
1054
- draw_faceup_spot_num=json_dict.get("draw_faceup_spot_num", None), # Handle missing key gracefully
1055
- point_uuid=json_dict.get("point_uuid", None), # Handle missing key gracefully
1056
- unit_combo=json_dict.get("unit_combo", None) # Handle missing key gracefully
1057
- )
1058
-
1059
-
1060
- class ActionSpec(PClass):
1061
- # # TODO: should remove "player_idx" as it's always the same as "to_play"
1062
- player_idx = field(type=int)
1063
- action_name = field(type=str)
1064
- return_route_option_sets = field(type=list, initial=[]) # List[OptionSet]
1065
- draw_faceup_spots = field(type=dict, initial={}) # Dict{Int, int}
1066
- points = field(type=list, initial=[]) # List[PointCombos]
1067
- paths = field(type=list, initial=[]) # List[PathCombos]
1068
- def __todict__(self):
1069
- return {
1070
- "player_idx": self.player_idx,
1071
- "action_name": self.action_name,
1072
- "return_route_option_sets": [x.__todict__() for x in self.return_route_option_sets],
1073
- "draw_faceup_spots": self.draw_faceup_spots,
1074
- "points": [x.__todict__() for x in self.points],
1075
- "paths": [x.__todict__() for x in self.paths],
1076
- }
1077
- @staticmethod
1078
- def __fromdict__(d):
1079
- print("""d["return_route_option_sets"]""", d["return_route_option_sets"])
1080
- return ActionSpec(
1081
- player_idx=d["player_idx"],
1082
- action_name=d["action_name"],
1083
- return_route_option_sets=[OptionSet.__fromdict__(x) for x in d["return_route_option_sets"]],
1084
- draw_faceup_spots=d["draw_faceup_spots"],
1085
- points=[PointCombos.__fromdict__(x) for x in d["points"]],
1086
- paths=[PathCombos.__fromdict__(x) for x in d["paths"]],
1087
- )
1088
-
1089
-
1090
- # Implementing the following Julia function:
1091
- # struct PathCombos
1092
- # path_idx::Int
1093
- # default_combo::String
1094
- # sample_fulfillment::Vector{Int}
1095
- # end
1096
- class PathCombos(PClass):
1097
- path_idx = field(type=int)
1098
- default_combo = field(type=str)
1099
- sample_fulfillment = field(type=list) # List[int]
1100
- def __todict__(self):
1101
- return {
1102
- "path_idx": self.path_idx,
1103
- "default_combo": self.default_combo,
1104
- "sample_fulfillment": self.sample_fulfillment,
1105
- }
1106
- @staticmethod
1107
- def __fromdict__(d):
1108
- return PathCombos(
1109
- path_idx=d["path_idx"],
1110
- default_combo=d["default_combo"],
1111
- sample_fulfillment=d["sample_fulfillment"]
1112
- )
1113
-
1114
-
1115
- # Implementing the following Julia function:
1116
- # struct OptionSet
1117
- # option_idxs::Set{Int}
1118
- # end
1119
- class OptionSet(PClass):
1120
- option_idxs = field(type=set) # Set[int]
1121
- def __todict__(self):
1122
- return {
1123
- "option_idxs": list(self.option_idxs),
1124
- }
1125
- @staticmethod
1126
- def __fromdict__(d):
1127
- return OptionSet(
1128
- option_idxs=set(d["option_idxs"])
1129
- )
1130
-
1131
-
1132
- class PointCombos(PClass):
1133
- point_uuid = field(type=str)
1134
- default_combo = field(type=str)
1135
- sample_fulfillment = field(type=list) # List[int]
1136
- def __todict__(self):
1137
- return {
1138
- "point_uuid": self.point_uuid,
1139
- "default_combo": self.default_combo,
1140
- "sample_fulfillment": self.sample_fulfillment,
1141
- }
1142
- @staticmethod
1143
- def __fromdict__(d):
1144
- return PointCombos(
1145
- point_uuid=d["point_uuid"],
1146
- default_combo=d["default_combo"],
1147
- sample_fulfillment=d["sample_fulfillment"]
1148
- )
1149
-
1150
-
1151
- class PlayerInfo(PClass):
1152
- fig = field(type=Fig)
1153
- player_idx = field(type=int)
1154
- new_route_cards = field(type=PVector) # List[int]
1155
- route_cards = field(type=PVector) # List[int]
1156
- unit_cards = field(type=PVector) # List[int]
1157
- completed_routes = field(type=list) # List[int]
1158
- completed_clusters = field(type=list) # List[UUID]
1159
- paths = field(type=list) # List[int]
1160
- points = field(type=list) # List[UUID]
1161
- tokens = field(type=list) # List[UUID]
1162
- num_pieces = field(type=int)
1163
- num_point_pieces = field(type=int)
1164
- longest_trail = field(type=list) # List[int]
1165
- longest_trail_len = field(type=int)
1166
- final_score = field(type=object) # Union{Nothing, PlayerScore}
1167
- def __todict__(self):
1168
- return {
1169
- "fig": self.fig.__todict__(),
1170
- "player_idx": self.player_idx,
1171
- "new_route_cards": list(self.new_route_cards),
1172
- "route_cards": list(self.route_cards),
1173
- "unit_cards": list(self.unit_cards),
1174
- "completed_routes": self.completed_routes,
1175
- "completed_clusters": self.completed_clusters,
1176
- "paths": self.paths,
1177
- "points": self.points,
1178
- "tokens": self.tokens,
1179
- "num_pieces": self.num_pieces,
1180
- "num_point_pieces": self.num_point_pieces,
1181
- "longest_trail": self.longest_trail,
1182
- "longest_trail_len": self.longest_trail_len,
1183
- "final_score": self.final_score.__todict__() if self.final_score else None,
1184
- }
1185
- @staticmethod
1186
- def __fromdict__(d):
1187
- return PlayerInfo(
1188
- fig=Fig.__fromdict__(d["fig"]),
1189
- player_idx=d["player_idx"],
1190
- new_route_cards=pvector(d["new_route_cards"]),
1191
- route_cards=pvector(d["route_cards"]),
1192
- unit_cards=pvector(d["unit_cards"]),
1193
- completed_routes=d["completed_routes"],
1194
- completed_clusters=d["completed_clusters"],
1195
- paths=d["paths"],
1196
- points=d["points"],
1197
- tokens=d["tokens"],
1198
- num_pieces=d["num_pieces"],
1199
- num_point_pieces=d["num_point_pieces"],
1200
- longest_trail=d["longest_trail"],
1201
- longest_trail_len=d["longest_trail_len"],
1202
- final_score=PlayerScore.__fromdict__(d["final_score"]) if d.get("final_score") else None,
1203
- )
1204
- @staticmethod
1205
- def clone(hand):
1206
- return PlayerInfo.__fromdict__(hand.__todict__())
1207
-
1208
-
1209
992
  class PublicPlayer(PClass):
1210
993
  idx = field(type=int)
1211
994
  pieces = field(type=list) # List[Piece]
@@ -1316,36 +1099,27 @@ class PrivatePlayerScore(PClass):
1316
1099
  )
1317
1100
 
1318
1101
 
1319
- # Implementing the following Julia function:
1320
- # struct PrivateState
1321
- # legal_actions::Vector{ActionSpec}
1322
- # segment_statuses::Vector{SegmentStatus}
1323
- # hand::PlayerInfo
1324
- # end
1325
1102
  class PrivateState(PClass):
1103
+ my_history = field(type=list) # List[Action2]
1326
1104
  player_score = field(type=PrivatePlayerScore)
1327
1105
  player = field(type=Player)
1328
1106
  legal_actions_2 = field(type=list) # List[LegalAction]
1329
- legal_actions = field(type=list) # List[ActionSpec]
1330
- hand = field(type=PlayerInfo)
1331
1107
  goal_completions = field(type=list, initial=[]) # List[GoalCompletion]
1332
1108
  def __todict__(self):
1333
1109
  return {
1110
+ "my_history": [x.__todict__() for x in self.my_history],
1334
1111
  "player_score": self.player_score.__todict__(),
1335
1112
  "player": self.player.__todict__(),
1336
1113
  "legal_actions_2": [x.__todict__() for x in self.legal_actions_2],
1337
- "legal_actions": [x.__todict__() for x in self.legal_actions],
1338
- "hand": self.hand.__todict__(),
1339
1114
  "goal_completions": [x.__todict__() for x in self.goal_completions],
1340
1115
  }
1341
1116
  @staticmethod
1342
1117
  def __fromdict__(d):
1343
1118
  return PrivateState(
1119
+ my_history=[Action2.__fromdict__(x) for x in d["my_history"]],
1344
1120
  player_score=PrivatePlayerScore.__fromdict__(d["player_score"]),
1345
1121
  player=Player.__fromdict__(d["player"]),
1346
1122
  legal_actions_2=[LegalAction.__fromdict__(x) for x in d["legal_actions_2"]],
1347
- legal_actions=[ActionSpec.__fromdict__(x) for x in d["legal_actions"]],
1348
- hand=PlayerInfo.__fromdict__(d["hand"]),
1349
1123
  goal_completions=[GoalCompletion.__fromdict__(x) for x in d["goal_completions"]],
1350
1124
  )
1351
1125
 
@@ -2164,7 +1938,6 @@ class State(PClass):
2164
1938
  uuid2segment = field(type=dict) # Dict[str, Segment]
2165
1939
  pieceuuid2piece = field(type=dict) # Dict[str, Piece]
2166
1940
  carduuid2card = field(type=dict) # Dict[str, Card]
2167
- final_scores = field(type=(list, type(None)), initial=None) # Optional[List[int]]
2168
1941
  bonus_statuses = field(type=list) # List[BonusStatus]
2169
1942
  bonusuuid2bonusidx = field(type=dict) # Dict[str, int]
2170
1943
  carduuid2deckidx = field(type=dict) # Dict[str, int]
@@ -2188,16 +1961,8 @@ class State(PClass):
2188
1961
  game_config = field(type=GameConfig)
2189
1962
  rng = field(type=random.Random)
2190
1963
  terminal = field(type=bool)
2191
- initial_to_play = field(type=list) # List[int]
2192
- route_cards = field(type=PVector) # List[int]
2193
- route_discards = field(type=PVector) # List[int]
2194
- player_hands = field(type=PVector) # List[PlayerInfo]
2195
- unit_cards = field(type=PVector) # List[int]
2196
- faceup_spots = field(type=PVector) # List[Union{Nothing, int}]
2197
- unit_discards = field(type=PVector) # List[int]
2198
1964
  last_to_play = field(type=(int, type(None)), initial=None)
2199
1965
  winners = field(type=list) # List[int]
2200
- # market_refills::Vector{MarketRefill}
2201
1966
  def __todict__(self):
2202
1967
  return {
2203
1968
  "uuid2edge": {k: v.__todict__() for k, v in self.uuid2edge.items()},
@@ -2205,7 +1970,6 @@ class State(PClass):
2205
1970
  "uuid2segment": {k: v.__todict__() for k, v in self.uuid2segment.items()},
2206
1971
  "pieceuuid2piece": {k: v.__todict__() for k, v in self.pieceuuid2piece.items()},
2207
1972
  "carduuid2card": {k: v.__todict__() for k, v in self.carduuid2card.items()},
2208
- "final_scores": self.final_scores,
2209
1973
  "bonus_statuses": [status.__todict__() for status in self.bonus_statuses],
2210
1974
  "bonusuuid2bonusidx": self.bonusuuid2bonusidx,
2211
1975
  "carduuid2deckidx": self.carduuid2deckidx,
@@ -2229,13 +1993,6 @@ class State(PClass):
2229
1993
  "game_config": self.game_config.__todict__(),
2230
1994
  "rng": rng2json(self.rng),
2231
1995
  "terminal": self.terminal,
2232
- "initial_to_play": self.initial_to_play,
2233
- "route_cards": list(self.route_cards),
2234
- "route_discards": list(self.route_discards),
2235
- "player_hands": [x.__todict__() for x in self.player_hands],
2236
- "unit_cards": list(self.unit_cards),
2237
- "faceup_spots": list(self.faceup_spots),
2238
- "unit_discards": list(self.unit_discards),
2239
1996
  "last_to_play": self.last_to_play,
2240
1997
  "winners": self.winners,
2241
1998
  }
@@ -2247,7 +2004,6 @@ class State(PClass):
2247
2004
  uuid2segment={k: Segment2.__fromdict__(v) for k, v in d["uuid2segment"].items()},
2248
2005
  pieceuuid2piece={k: Piece.__fromdict__(v) for k, v in d["pieceuuid2piece"].items()},
2249
2006
  carduuid2card={k: Card.__fromdict__(v) for k, v in d["carduuid2card"].items()},
2250
- final_scores=d["final_scores"],
2251
2007
  bonus_statuses=[BonusStatus.__fromdict__(x) for x in d["bonus_statuses"]],
2252
2008
  bonusuuid2bonusidx=d["bonusuuid2bonusidx"],
2253
2009
  carduuid2deckidx=d["carduuid2deckidx"],
@@ -2271,13 +2027,6 @@ class State(PClass):
2271
2027
  game_config=GameConfig.__fromdict__(d["game_config"]),
2272
2028
  rng=json2rng(d["rng"]),
2273
2029
  terminal=d["terminal"],
2274
- initial_to_play=d["initial_to_play"],
2275
- route_cards=pvector(d["route_cards"]),
2276
- route_discards=pvector(d["route_discards"]),
2277
- player_hands=pvector([PlayerInfo.__fromdict__(h) for h in d["player_hands"]]),
2278
- unit_cards=pvector(d["unit_cards"]),
2279
- faceup_spots=pvector(d["faceup_spots"]),
2280
- unit_discards=pvector(d["unit_discards"]),
2281
2030
  last_to_play=d.get("last_to_play"),
2282
2031
  winners=d["winners"],
2283
2032
  )
@@ -2479,70 +2228,6 @@ class ScoreItem(PClass):
2479
2228
  )
2480
2229
 
2481
2230
 
2482
- # Implementing the following GraphQL type:
2483
- # type PublicPlayerInfo {
2484
- # final_score: PlayerScore
2485
- # longest_trail: [Int]!
2486
- # longest_trail_len: Int!
2487
- # num_pieces: Int!
2488
- # num_route_cards: Int!
2489
- # num_unit_cards: Int!
2490
- # paths: [Int]!
2491
- # route_statuses: [RouteStatus]
2492
- # score: Int!
2493
- # }
2494
- class PublicPlayerInfo(PClass):
2495
- final_score = field(type=(PlayerScore, type(None)), initial=None) # Union{Nothing, PlayerScore}
2496
- longest_trail = field(type=list) # List[int]
2497
- longest_trail_len = field(type=int)
2498
- num_pieces = field(type=int)
2499
- num_route_cards = field(type=int)
2500
- num_new_route_cards = field(type=int)
2501
- num_unit_cards = field(type=int)
2502
- paths = field(type=list) # List[int]
2503
- points = field(type=list) # List[UUID]
2504
- tokens = field(type=list) # List[UUID]
2505
- route_statuses = field(type=list) # List[RouteStatus]
2506
- score = field(type=int)
2507
- num_point_pieces = field(type=int, initial=0) # Added to match PlayerInfo
2508
- completed_clusters = field(type=list, initial=[]) # Added to match PlayerInfo
2509
- def __todict__(self):
2510
- return {
2511
- "final_score": self.final_score.__todict__() if self.final_score else None,
2512
- "longest_trail": self.longest_trail,
2513
- "longest_trail_len": self.longest_trail_len,
2514
- "num_pieces": self.num_pieces,
2515
- "num_route_cards": self.num_route_cards,
2516
- "num_new_route_cards": self.num_new_route_cards,
2517
- "num_unit_cards": self.num_unit_cards,
2518
- "paths": self.paths,
2519
- "points": self.points,
2520
- "tokens": self.tokens,
2521
- "route_statuses": [x.__todict__() for x in self.route_statuses],
2522
- "score": self.score,
2523
- "num_point_pieces": self.num_point_pieces,
2524
- "completed_clusters": self.completed_clusters,
2525
- }
2526
- @staticmethod
2527
- def __fromdict__(d):
2528
- return PublicPlayerInfo(
2529
- final_score=PlayerScore.__fromdict__(d["final_score"]) if d.get("final_score") else None,
2530
- longest_trail=d["longest_trail"],
2531
- longest_trail_len=d["longest_trail_len"],
2532
- num_pieces=d["num_pieces"],
2533
- num_route_cards=d["num_route_cards"],
2534
- num_new_route_cards=d["num_new_route_cards"],
2535
- num_unit_cards=d["num_unit_cards"],
2536
- paths=d["paths"],
2537
- points=d["points"],
2538
- tokens=d["tokens"],
2539
- route_statuses=[RouteStatus.__fromdict__(x) for x in d["route_statuses"]],
2540
- score=d["score"],
2541
- num_point_pieces=d.get("num_point_pieces", 0),
2542
- completed_clusters=d.get("completed_clusters", []),
2543
- )
2544
-
2545
-
2546
2231
  class AllottedTime(PClass):
2547
2232
  seconds = field(type=int)
2548
2233
  since_action_idx = field(type=int)
@@ -2597,21 +2282,10 @@ class PublicState(PClass):
2597
2282
  decks = field(type=list) # List[PublicDeck]
2598
2283
  piles = field(type=list) # List[Pile]
2599
2284
  player_idxs = field(type=list) # List[int]
2600
- initial_to_play = field(type=list) # List[int]
2601
- to_play = field(type=list) # List[int]
2602
- unit_discards = field(type=list) # List[int]
2603
- num_route_cards = field(type=int)
2604
- num_route_discards = field(type=int)
2605
- num_unit_cards = field(type=int)
2606
- num_unit_discards = field(type=int)
2607
- faceup_spots = field(type=list) # List[Union{Nothing, int}]
2608
2285
  players = field(type=list) # List[PublicPlayer]
2609
- player_hands = field(type=list) # List[PublicPlayerInfo]
2610
2286
  last_to_play = field(type=(int, type(None)), initial=None)
2611
2287
  winners = field(type=list)
2612
2288
  terminal = field(type=bool)
2613
- captured_points = field(type=list) # List[CapturedPoint]
2614
- captured_segments = field(type=list) # List[CapturedSegment]
2615
2289
  def __todict__(self):
2616
2290
  return {
2617
2291
  "deadlines": [deadline.__todict__() if deadline else None for deadline in self.deadlines],
@@ -2632,21 +2306,10 @@ class PublicState(PClass):
2632
2306
  "decks": [deck.__todict__() for deck in self.decks],
2633
2307
  "piles": [pile.__todict__() for pile in self.piles],
2634
2308
  "player_idxs": self.player_idxs,
2635
- "initial_to_play": self.initial_to_play,
2636
- "to_play": self.to_play,
2637
- "unit_discards": self.unit_discards,
2638
- "num_route_cards": self.num_route_cards,
2639
- "num_route_discards": self.num_route_discards,
2640
- "num_unit_cards": self.num_unit_cards,
2641
- "num_unit_discards": self.num_unit_discards,
2642
- "faceup_spots": self.faceup_spots,
2643
2309
  "players": [x.__todict__() for x in self.players],
2644
- "player_hands": [x.__todict__() for x in self.player_hands],
2645
2310
  "last_to_play": self.last_to_play,
2646
2311
  "winners": self.winners,
2647
2312
  "terminal": self.terminal,
2648
- "captured_points": [x.__todict__() for x in self.captured_points],
2649
- "captured_segments": [x.__todict__() for x in self.captured_segments],
2650
2313
  }
2651
2314
  @staticmethod
2652
2315
  def __fromdict__(d):
@@ -2669,26 +2332,11 @@ class PublicState(PClass):
2669
2332
  decks=[PublicDeck.__fromdict__(deck) for deck in d["decks"]],
2670
2333
  piles=[Pile.__fromdict__(x) for x in d["piles"]],
2671
2334
  player_idxs=d["player_idxs"],
2672
- initial_to_play=d["initial_to_play"],
2673
- to_play=d["to_play"],
2674
- unit_discards=d["unit_discards"],
2675
- num_route_cards=d["num_route_cards"],
2676
- num_route_discards=d["num_route_discards"],
2677
- num_unit_cards=d["num_unit_cards"],
2678
- num_unit_discards=d["num_unit_discards"],
2679
- faceup_spots=d["faceup_spots"],
2680
2335
  players=[PublicPlayer.__fromdict__(x) for x in d["players"]],
2681
- player_hands=[PublicPlayerInfo.__fromdict__(x) for x in d["player_hands"]],
2682
2336
  last_to_play=d.get("last_to_play"),
2683
2337
  winners=d["winners"],
2684
2338
  terminal=d["terminal"],
2685
- captured_points=[CapturedPoint.__fromdict__(x) for x in d["captured_points"]],
2686
- captured_segments=[CapturedSegment.__fromdict__(x) for x in d["captured_segments"]],
2687
2339
  )
2688
- # fig::Fig
2689
- # captured_segments::Vector{CapturedSegment}
2690
- # captured_points::Vector{CapturedPoint}
2691
- # market_refills::Vector{MarketRefill}
2692
2340
 
2693
2341
 
2694
2342
  class PlayerState(PClass):
@@ -2837,50 +2485,9 @@ def getsettingvalue(s, setting_name):
2837
2485
  def getinitialstate(game_config):
2838
2486
  fig = game_config.fig
2839
2487
  rng = getrng(game_config.seed)
2840
- route_deck = shuffledeck(getnumroutecards(fig), rng)
2841
2488
  unit_deck = shuffledeck(gettotaldeckcards(fig), rng)
2842
2489
  route_deck_idx, unit_deck_idx = 0, 0
2843
- player_hands = []
2844
- initial_num_route_choices = getsettingvalue(fig, "initial_num_route_choices")
2845
- num_initial_unit_cards = getsettingvalue(fig, "num_initial_unit_cards")
2846
- num_segment_pieces_per_player = getsettingvalue(fig, "num_segment_pieces_per_player")
2847
- num_point_pieces_per_player = getsettingvalue(fig, "num_point_pieces_per_player")
2848
-
2849
-
2850
- for player_idx in range(game_config.num_players):
2851
- player_hand = PlayerInfo(
2852
- fig=fig,
2853
- player_idx=player_idx,
2854
- new_route_cards=pvector(route_deck[route_deck_idx:(route_deck_idx+(initial_num_route_choices))]),
2855
- route_cards=pvector([]),
2856
- unit_cards=pvector(unit_deck[unit_deck_idx:(unit_deck_idx + num_initial_unit_cards)]),
2857
- completed_routes=[],
2858
- completed_clusters=[],
2859
- paths=[],
2860
- points=[],
2861
- tokens=[],
2862
- num_pieces=num_segment_pieces_per_player,
2863
- num_point_pieces=num_point_pieces_per_player,
2864
- longest_trail=[],
2865
- longest_trail_len=0,
2866
- final_score=None,
2867
- )
2868
- player_hands.append(player_hand)
2869
- route_deck_idx += initial_num_route_choices
2870
- unit_deck_idx += num_initial_unit_cards
2871
-
2872
- faceup_spots = getfaceupspots(fig, unit_deck, unit_deck_idx)
2873
2490
  unit_deck_idx += 5
2874
- # Implementing the following Julia function:
2875
- # unit_cards = unit_deck[unit_deck_idx:end]
2876
- unit_cards = unit_deck[unit_deck_idx:] if unit_deck_idx < len(unit_deck) else []
2877
- route_cards = route_deck[route_deck_idx:]
2878
-
2879
- if getsettingvalue(fig, 'action_route_discard'):
2880
- initial_to_play = list(range(game_config.num_players))
2881
- else:
2882
- initial_to_play = [getfirstplayeridx(rng, game_config.num_players)]
2883
-
2884
2491
  board_config = fig.board_config
2885
2492
  deck_0_rng = getrng(1234321)
2886
2493
  deck_1_rng = getrng(8738758)
@@ -2965,7 +2572,6 @@ def getinitialstate(game_config):
2965
2572
  uuid2segment=uuid2segment,
2966
2573
  pieceuuid2piece=pieceuuid2piece,
2967
2574
  carduuid2card=carduuid2card,
2968
- final_scores=None,
2969
2575
  bonus_statuses=bonus_statuses,
2970
2576
  bonusuuid2bonusidx=bonusuuid2bonusidx,
2971
2577
  carduuid2deckidx=carduuid2deckidx,
@@ -2996,14 +2602,7 @@ def getinitialstate(game_config):
2996
2602
  player_idxs=list(range(game_config.num_players)),
2997
2603
  decks=decks,
2998
2604
  game_config=game_config,
2999
- initial_to_play=initial_to_play,
3000
2605
  rng=rng,
3001
- route_cards=pvector(route_cards),
3002
- route_discards=pvector([]),
3003
- player_hands=pvector(player_hands),
3004
- unit_cards=pvector(unit_cards),
3005
- unit_discards=pvector([]),
3006
- faceup_spots=pvector(faceup_spots),
3007
2606
  last_to_play=None,
3008
2607
  winners=[],
3009
2608
  terminal=False,
@@ -3114,15 +2713,20 @@ def handle_last_to_play(game):
3114
2713
  return game
3115
2714
 
3116
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
+
3117
2723
  def handle_calc_winners(game):
3118
2724
  if game.terminal:
3119
2725
  players_with_highest_score = []
3120
2726
  highest_score = -1000
3121
- final_scores = []
2727
+ final_scores = getfinalscores(game)
3122
2728
  for player_idx in range(len(game.players)):
3123
- player_score = game.player_scores[player_idx]
3124
- final_score = getpublicplayerscore(game, player_score).total
3125
- final_scores.append(final_score)
2729
+ final_score = final_scores[player_idx]
3126
2730
  if final_score > highest_score:
3127
2731
  highest_score = final_score
3128
2732
  players_with_highest_score = [player_idx]
@@ -3130,7 +2734,6 @@ def handle_calc_winners(game):
3130
2734
  players_with_highest_score.append(player_idx)
3131
2735
  return game.set(
3132
2736
  winners=players_with_highest_score,
3133
- final_scores=final_scores,
3134
2737
  )
3135
2738
 
3136
2739
  return game
@@ -4428,63 +4031,6 @@ def getnextstate2(s, a, log=False):
4428
4031
  return s
4429
4032
 
4430
4033
 
4431
-
4432
- @dispatch(State, QValueLearningPolicy)
4433
- def getnextaction(s, policy):
4434
- player_idx = gettoplay(s)[0]
4435
- legal_action_specs = getlegalactionspecsforplayer(s, player_idx, None, None)
4436
- legal_actions = get_all_legal_actions(s, player_idx, legal_action_specs)
4437
-
4438
- if s.rng.random() <= policy.epsilon:
4439
- random_action = legal_actions[s.rng.randint(0, len(legal_actions) - 1)]
4440
- return random_action
4441
-
4442
- q_values = policy.qvalue_fn(s, legal_actions)
4443
- argmax_idx = max(range(len(q_values)), key=lambda i: q_values[i])
4444
-
4445
- return legal_actions[argmax_idx]
4446
-
4447
-
4448
- @dispatch(State, RandoPolicy)
4449
- def getnextaction(s, policy):
4450
- player_idx = gettoplay(s)[0]
4451
- legal_actions = getlegalactionspecsforplayer(s, player_idx, None, None)
4452
- action_spec = legal_actions[s.rng.randint(0, len(legal_actions) - 1)]
4453
-
4454
- if action_spec.action_name == "ROUTE_DISCARD":
4455
- return AltAction(
4456
- action_name="ROUTE_DISCARD",
4457
- player_idx=player_idx,
4458
- return_route_cards=[0],
4459
- )
4460
-
4461
- if action_spec.action_name == "DRAW_UNIT_FACEUP":
4462
- draw_faceup_spot_num = 1
4463
- return AltAction(
4464
- action_name="DRAW_UNIT_FACEUP",
4465
- player_idx=player_idx,
4466
- draw_faceup_unit_card_num=s.faceup_spots[draw_faceup_spot_num-1],
4467
- draw_faceup_spot_num=draw_faceup_spot_num,
4468
- )
4469
-
4470
- if action_spec.action_name == "DRAW_UNIT_DECK":
4471
- return AltAction(
4472
- action_name="DRAW_UNIT_DECK",
4473
- player_idx=player_idx,
4474
- )
4475
-
4476
- if action_spec.action_name == "CLAIM_POINT":
4477
- point = action_spec.points[s.rng.randint(0, len(action_spec.points) - 1)]
4478
- return AltAction(
4479
- action_name="CLAIM_POINT",
4480
- player_idx=player_idx,
4481
- point_uuid=str(point.point_uuid),
4482
- unit_combo=point.default_combo,
4483
- )
4484
-
4485
- return None
4486
-
4487
-
4488
4034
  def getpublicplayerscore(s, player_score):
4489
4035
  if s.terminal:
4490
4036
  # Join the arrays of public and private items
@@ -4568,6 +4114,98 @@ def get_deadlines(s):
4568
4114
  ]
4569
4115
 
4570
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
+
4571
4209
  @dispatch(State)
4572
4210
  def getpublicstate(s):
4573
4211
  return PublicState(
@@ -4579,8 +4217,8 @@ def getpublicstate(s):
4579
4217
  bonus_statuses=s.bonus_statuses,
4580
4218
  starting_decks=s.starting_decks,
4581
4219
  starting_piles=s.starting_piles,
4582
- history=[action.get_public(s) for action in s.history],
4583
- 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),
4584
4222
  player_graphs=s.player_graphs,
4585
4223
  goals=s.goals,
4586
4224
  nodes=s.nodes,
@@ -4589,21 +4227,10 @@ def getpublicstate(s):
4589
4227
  decks=[getpublicdeck(s, deck) for deck in s.decks],
4590
4228
  piles=s.piles,
4591
4229
  player_idxs=s.player_idxs,
4592
- initial_to_play=s.initial_to_play,
4593
- to_play=gettoplay(s),
4594
- unit_discards=list(s.unit_discards),
4595
- num_route_cards=len(s.route_cards),
4596
- num_route_discards=len(s.route_discards),
4597
- num_unit_cards=len(s.unit_cards),
4598
- num_unit_discards=len(s.unit_discards),
4599
- faceup_spots=list(s.faceup_spots),
4600
4230
  players=[getpublicplayer(s, p) for p in s.players],
4601
- player_hands=[getpublicplayerinfo(s, p) for p in s.player_hands],
4602
4231
  last_to_play=s.last_to_play,
4603
4232
  winners=s.winners,
4604
4233
  terminal=s.terminal,
4605
- captured_points=getcapturedpoints(s),
4606
- captured_segments=getcapturedsegments(s),
4607
4234
  )
4608
4235
 
4609
4236
 
@@ -4635,31 +4262,6 @@ def getpublicplayer(s, p):
4635
4262
  )
4636
4263
 
4637
4264
 
4638
- @dispatch(State, PlayerInfo)
4639
- def getpublicplayerinfo(s, p):
4640
- # if s.terminal
4641
- # route_statuses = getroutestatuses(p)
4642
- # else
4643
- # route_statuses = []
4644
- # end
4645
- return PublicPlayerInfo(
4646
- final_score=p.final_score,
4647
- longest_trail=p.longest_trail,
4648
- longest_trail_len=p.longest_trail_len,
4649
- num_pieces=p.num_pieces,
4650
- num_route_cards=len(p.route_cards),
4651
- num_new_route_cards=len(p.new_route_cards),
4652
- num_unit_cards=len(p.unit_cards),
4653
- paths=p.paths,
4654
- points=p.points,
4655
- tokens=p.tokens,
4656
- route_statuses=[], # TODO: implement!
4657
- score=getpublicscore(s, p.player_idx),
4658
- num_point_pieces=p.num_point_pieces,
4659
- completed_clusters=p.completed_clusters,
4660
- )
4661
-
4662
-
4663
4265
  # Implementing the following Julia function:
4664
4266
  # function getpublicscore(s::State, player_idx::Int)
4665
4267
  # addends = Int[]
@@ -4774,18 +4376,6 @@ def gettoplay(s, last_action_type):
4774
4376
  return [getlastplayeridxplus1(s)]
4775
4377
 
4776
4378
 
4777
- # Implementing the following Julia function:
4778
- @dispatch(State, NoAction)
4779
- # function gettoplay(s::State, last_action_key::Nothing)
4780
- # if getsettingvalue(s, :action_route_discard)
4781
- # return collect(1:s.game_config.num_players)
4782
- # end
4783
- # [getfirstplayeridx(s.game)]
4784
- # end
4785
- def gettoplay(s, last_action_type):
4786
- return s.initial_to_play
4787
-
4788
-
4789
4379
  def getrng(seed):
4790
4380
  rng = random.Random()
4791
4381
  rng.seed(seed)
@@ -4946,273 +4536,6 @@ def combinations(a, n=None):
4946
4536
  # then the state is "terminal".
4947
4537
  ###
4948
4538
 
4949
- # Implementing the following Julia function:
4950
- # function getrouteoptionsets(s::State, player_idx, min_required)
4951
- # num_choices = length(s.player_hands[player_idx].new_route_cards)
4952
- # max_return_size = num_choices - min_required
4953
- # set = collect(1:num_choices)
4954
- # OptionSet.(
4955
- # Set{Int}.(
4956
- # reduce(
4957
- # vcat,
4958
- # [collect(combinations(set, n)) for n in 0:max_return_size],
4959
- # )
4960
- # )
4961
- # )
4962
- # end
4963
- def getrouteoptionsets(s, player_idx, min_required):
4964
- num_choices = len(s.player_hands[player_idx].new_route_cards)
4965
- max_return_size = num_choices - min_required
4966
- choice_set = list(range(num_choices))
4967
- all_combinations = [
4968
- set(comb)
4969
- for n in range(max_return_size + 1)
4970
- for comb in combinations(choice_set, n)
4971
- ]
4972
- return [OptionSet(option_idxs=comb) for comb in all_combinations]
4973
-
4974
-
4975
-
4976
- # Implementing the following Julia function:
4977
- # function getlegalactionsforplayer(s::State, player_idx, repeat_player, last_action)
4978
- # min_initial_routes = getsettingvalue(s.fig, :min_initial_routes)
4979
- # min_chosen_routes = getsettingvalue(s.fig, :min_chosen_routes)
4980
-
4981
- # # Initial Route Card Discard
4982
- # if getsettingvalue(s, :action_route_discard) && length(s.action_history) < s.game_config.num_players
4983
- # return [
4984
- # ActionSpec(
4985
- # player_idx=player_idx,
4986
- # action_name=ROUTE_DISCARD,
4987
- # return_route_option_sets=getrouteoptionsets(s, player_idx, min_initial_routes),
4988
- # )
4989
- # ]
4990
- # end
4991
-
4992
- # action_specs = ActionSpec[]
4993
- # if getsettingvalue(s, :action_draw_unit_faceup) && !isempty(getvalidspotnums(s))
4994
- # push!(
4995
- # action_specs,
4996
- # ActionSpec(
4997
- # player_idx=player_idx,
4998
- # action_name=DRAW_UNIT_FACEUP,
4999
- # draw_faceup_spots=Dict((spot_num, s.faceup_spots[spot_num]) for spot_num in getvalidspotnums(s)),
5000
- # )
5001
- # )
5002
- # end
5003
-
5004
- # if getsettingvalue(s, :action_draw_route) && (length(s.route_cards) + length(s.route_discards)) >= min_chosen_routes
5005
- # push!(action_specs, ActionSpec(s.fig, player_idx, :DRAW_ROUTE))
5006
- # end
5007
-
5008
- # if getsettingvalue(s, :action_draw_unit_deck) && (!isempty(s.unit_cards) || !isempty(s.unit_discards))
5009
- # push!(action_specs, ActionSpec(s.fig, player_idx, :DRAW_UNIT_DECK))
5010
- # end
5011
-
5012
- # if getsettingvalue(s, :action_claim_path)
5013
- # append!(action_specs, getclaimpathactionspecs(s, player_idx))
5014
- # end
5015
-
5016
- # if getsettingvalue(s.fig, :action_claim_point)
5017
- # append!(action_specs, getclaimpointactionspecs(s, player_idx))
5018
- # end
5019
-
5020
- # action_specs
5021
- # end
5022
- @dispatch(State, int, object, object)
5023
- def getlegalactionspecsforplayer(s, player_idx, repeat_player, last_action):
5024
- min_chosen_routes = getsettingvalue(s, 'min_chosen_routes')
5025
-
5026
- action_specs = []
5027
- if getsettingvalue(s, 'action_draw_unit_faceup') and s.faceup_spots:
5028
-
5029
- # Convert this Julia to Python:
5030
- # Julia:
5031
- # draw_faceup_spots = Dict((spot_num, s.faceup_spots[spot_num]) for spot_num in getvalidspotnums(s))
5032
- # Python:
5033
- draw_faceup_spots = {spot_num: s.faceup_spots[spot_num-1] for spot_num in getvalidspotnums(s)}
5034
-
5035
- action_specs.append(
5036
- ActionSpec(
5037
- player_idx=player_idx,
5038
- action_name="DRAW_UNIT_FACEUP",
5039
- return_route_option_sets = [],
5040
- draw_faceup_spots=draw_faceup_spots,
5041
- points = [],
5042
- paths = [],
5043
- )
5044
- )
5045
-
5046
- if getsettingvalue(s, 'action_draw_route') and (len(s.route_cards) + len(s.route_discards)) >= min_chosen_routes:
5047
- action_specs.append(
5048
- AltAction(
5049
- player_idx=player_idx,
5050
- action_name="DRAW_ROUTE",
5051
- return_route_option_sets = [],
5052
- draw_faceup_spots={},
5053
- points = [],
5054
- paths = [],
5055
- )
5056
- )
5057
-
5058
- if getsettingvalue(s, 'action_draw_unit_deck') and (s.unit_cards or s.unit_discards):
5059
- action_specs.append(
5060
- ActionSpec(
5061
- player_idx=player_idx,
5062
- action_name="DRAW_UNIT_DECK",
5063
- return_route_option_sets = [],
5064
- draw_faceup_spots={},
5065
- points = [],
5066
- paths = [],
5067
- )
5068
- )
5069
-
5070
- if getsettingvalue(s, 'action_claim_path'):
5071
- action_specs.extend(getclaimpathactionspecs(s, player_idx))
5072
- pass
5073
-
5074
- if getsettingvalue(s, 'action_claim_point'):
5075
- action_specs.extend(getclaimpointactionspecs(s, player_idx))
5076
-
5077
- return action_specs
5078
-
5079
-
5080
- # Implementing the following Julia function:
5081
- # function getclaimpointactionspecs(s::State, player_idx::Int; log=false)
5082
- # action_specs = ActionSpec[]
5083
- # available_point_statuses = getavailablepoints(s, player_idx)
5084
- # points = map(available_point_statuses) do available_point_status
5085
- # (; uuid, sample_fulfillment) = available_point_status
5086
- # fulfillment_sorted = sample_fulfillment
5087
- # sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
5088
- # fulfillment_str = join(sample_fulfillment, "-")
5089
- # PointCombos(uuid, fulfillment_str, sample_fulfillment)
5090
- # end
5091
- # if !isempty(points)
5092
- # push!(
5093
- # action_specs,
5094
- # ActionSpec(
5095
- # action_name=CLAIM_POINT,
5096
- # player_idx=player_idx,
5097
- # points=points,
5098
- # )
5099
- # )
5100
- # end
5101
- # action_specs
5102
- # end
5103
- def getclaimpointactionspecs(s, player_idx, log=False):
5104
- action_specs = []
5105
- available_point_statuses = getavailablepoints(s, player_idx)
5106
-
5107
- # points = map(available_point_statuses) do available_point_status
5108
- # (; uuid, sample_fulfillment) = available_point_status
5109
- # fulfillment_sorted = sample_fulfillment
5110
- # sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
5111
- # fulfillment_str = join(sample_fulfillment, "-")
5112
- # PointCombos(uuid, fulfillment_str, sample_fulfillment)
5113
- # end
5114
-
5115
- def process_point_status(available_point_status):
5116
- uuid = available_point_status['uuid']
5117
- sample_fulfillment = available_point_status['sample_fulfillment']
5118
- fulfillment_sorted = sample_fulfillment
5119
- sample_fulfillment = [x['unit_card_num'] for x in fulfillment_sorted]
5120
- fulfillment_str = '-'.join(map(str, sample_fulfillment))
5121
- return PointCombos(
5122
- point_uuid=uuid,
5123
- default_combo=fulfillment_str,
5124
- sample_fulfillment=sample_fulfillment
5125
- )
5126
-
5127
- point_combos = list(map(process_point_status, available_point_statuses))
5128
-
5129
- if point_combos:
5130
- action_specs.append(
5131
- ActionSpec(
5132
- player_idx=player_idx,
5133
- action_name="CLAIM_POINT",
5134
- return_route_option_sets = [],
5135
- draw_faceup_spots = {},
5136
- points=point_combos,
5137
- paths = [],
5138
- )
5139
- )
5140
-
5141
- return action_specs
5142
-
5143
-
5144
- # Implementing the following Julia function:
5145
- # function getclaimpathactionspecs(s::State, player_idx::Int; log=false)
5146
- # action_specs = ActionSpec[]
5147
- # available_path_statuses = getavailablepaths(s, player_idx)
5148
- # paths = map(available_path_statuses) do available_path_status
5149
- # (; num, sample_fulfillment) = available_path_status
5150
- # fulfillment_sorted = Base.sort(sample_fulfillment; by=x -> x.segment_num)
5151
- # sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
5152
- # fulfillment_str = join(sample_fulfillment, "-")
5153
- # PathCombos(num, fulfillment_str, sample_fulfillment)
5154
- # end
5155
- # if !isempty(paths)
5156
- # push!(
5157
- # action_specs,
5158
- # ActionSpec(
5159
- # action_name=CLAIM_PATH,
5160
- # player_idx=player_idx,
5161
- # paths=paths,
5162
- # )
5163
- # )
5164
- # end
5165
- # action_specs
5166
- # end
5167
- def getclaimpathactionspecs(s, player_idx, log=False):
5168
- action_specs = []
5169
- available_path_statuses = getavailablepathstatuses(s, player_idx)
5170
-
5171
- def process_path_status(available_path_status):
5172
- num = available_path_status.num
5173
- sample_fulfillment = available_path_status.sample_fulfillment
5174
- fulfillment_sorted = sorted(sample_fulfillment, key=lambda x: x.segment_num)
5175
- sample_fulfillment = [x.unit_card_num for x in fulfillment_sorted]
5176
- fulfillment_str = '-'.join(map(str, sample_fulfillment))
5177
- return PathCombos(
5178
- path_idx=(num-1),
5179
- default_combo=fulfillment_str,
5180
- sample_fulfillment=sample_fulfillment
5181
- )
5182
-
5183
- paths = list(map(process_path_status, available_path_statuses))
5184
-
5185
- if paths:
5186
- action_specs.append(
5187
- ActionSpec(
5188
- player_idx=player_idx,
5189
- action_name="CLAIM_PATH",
5190
- return_route_option_sets = [],
5191
- draw_faceup_spots={},
5192
- points=[],
5193
- paths=paths,
5194
- )
5195
- )
5196
-
5197
- return action_specs
5198
-
5199
-
5200
- # Implementing the following Julia function:
5201
- # function getavailablepaths(s::State, player_num::Int)
5202
- # balance = s.player_hands[player_num].unit_cards
5203
- # path_statuses = map(getpotentialpathnums(s, player_num)) do path_num
5204
- # getpathstatus(s, player_num, path_num)
5205
- # end
5206
- # filter(x -> x.fulfillable, path_statuses)
5207
- # end
5208
- def getavailablepathstatuses(s, player_num):
5209
- balance = s.player_hands[player_num].unit_cards
5210
- path_statuses = [
5211
- getpathstatus(s, player_num, path_idx)
5212
- for path_idx in getpotentialpathidxs(s, player_num)
5213
- ]
5214
- return list(filter(lambda x: x.fulfillable, path_statuses))
5215
-
5216
4539
 
5217
4540
  # Implementing the following Julia function:
5218
4541
  # function getpotentialpathnums(s::State, player_num::Int)
@@ -5441,409 +4764,9 @@ def getclaimedpathidxs(s):
5441
4764
  return claimed
5442
4765
 
5443
4766
 
5444
- # Implementing the following Julia function:
5445
- # function getpathstatus(s::State, player_idx, path_num)
5446
- # balance = s.player_hands[player_idx].unit_cards
5447
- # (; fig) = s
5448
- # (; board_config) = fig
5449
- # (; deck_units, board_paths) = board_config
5450
- # unituuid2deckunit = Dict(x.unit_uuid => x for x in deck_units)
5451
- # path = board_paths[path_num]
5452
- # ordered_segments = prioritysort(fig, path.path.segments)
5453
- # fulfillment = OrderedFullfillment[]
5454
- # wild_unit_uuids = getwildunituuids(fig)
5455
- # # @show wild_unit_uuids
5456
- # non_wild_unit_uuids = getnonwildunituuids(fig)
5457
- # # @show non_wild_unit_uuids
5458
-
5459
- # # @show balance
5460
-
5461
- # balance_unituuid2deckcardnums = Dict()
5462
- # for deck_card_num in balance
5463
- # unit_uuid = getunituuid(fig, deck_card_num)
5464
- # if !haskey(balance_unituuid2deckcardnums, unit_uuid)
5465
- # balance_unituuid2deckcardnums[unit_uuid] = []
5466
- # end
5467
- # push!(balance_unituuid2deckcardnums[unit_uuid], deck_card_num)
5468
- # end
5469
-
5470
- # # @show balance_unituuid2deckcardnums
5471
-
5472
- # function hasexactunitmatch(unit_uuid)
5473
- # (
5474
- # haskey(balance_unituuid2deckcardnums, unit_uuid) &&
5475
- # length(balance_unituuid2deckcardnums[unit_uuid]) > 0
5476
- # )
5477
- # end
5478
-
5479
- # function anywildsleft()
5480
- # for wild_unit_uuid in wild_unit_uuids
5481
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5482
- # if !isempty(balance_unituuid2deckcardnums[wild_unit_uuid])
5483
- # return true
5484
- # end
5485
- # end
5486
- # end
5487
- # false
5488
- # end
5489
-
5490
- # function gettotalwildcount()
5491
- # count = 0
5492
- # for wild_unit_uuid in wild_unit_uuids
5493
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5494
- # count += length(balance_unituuid2deckcardnums[wild_unit_uuid])
5495
- # end
5496
- # end
5497
- # count
5498
- # end
5499
-
5500
- # function popawildcard!()
5501
- # for wild_unit_uuid in wild_unit_uuids
5502
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5503
- # if !isempty(balance_unituuid2deckcardnums[wild_unit_uuid])
5504
- # return pop!(balance_unituuid2deckcardnums[wild_unit_uuid])
5505
- # end
5506
- # end
5507
- # end
5508
- # nothing
5509
- # end
5510
-
5511
- # function getnonemptywildstack()
5512
- # for wild_unit_uuid in wild_unit_uuids
5513
- # if haskey(balance_unituuid2deckcardnums, wild_unit_uuid)
5514
- # if !isempty(balance_unituuid2deckcardnums[wild_unit_uuid])
5515
- # return balance_unituuid2deckcardnums[wild_unit_uuid]
5516
- # end
5517
- # end
5518
- # end
5519
- # nothing
5520
- # end
5521
-
5522
- # function getlargestnonwildstack()
5523
- # largest_non_wild_unit_uuid = nothing
5524
- # largest_found = 0
5525
- # for non_wild_unit_uuid in non_wild_unit_uuids
5526
- # if haskey(balance_unituuid2deckcardnums, non_wild_unit_uuid)
5527
- # curr_length = length(balance_unituuid2deckcardnums[non_wild_unit_uuid])
5528
- # if curr_length > largest_found
5529
- # largest_found = curr_length
5530
- # largest_non_wild_unit_uuid = non_wild_unit_uuid
5531
- # end
5532
- # end
5533
- # end
5534
- # if !isnothing(largest_non_wild_unit_uuid)
5535
- # return balance_unituuid2deckcardnums[largest_non_wild_unit_uuid]
5536
- # end
5537
- # nothing
5538
- # end
5539
-
5540
- # for ordered_segment in ordered_segments
5541
- # target_segment = ordered_segment.segment
5542
- # segment_num = ordered_segment.path_segment_num
5543
- # (; unit_uuid) = target_segment
5544
- # # @show unit_uuid
5545
- # # @show keys(unituuid2deckunit)
5546
- # target_unit = isnothing(unit_uuid) ? nothing : unituuid2deckunit[unit_uuid]
5547
- # # @show target_unit
5548
-
5549
- # if isnothing(target_unit)
5550
- # # do nothing (this is a blank segment)
5551
- # elseif target_unit.is_wild
5552
- # if hasexactunitmatch(unit_uuid)
5553
- # popped = pop!(balance_unituuid2deckcardnums[unit_uuid])
5554
- # push!(fulfillment, OrderedFullfillment(segment_num, popped))
5555
- # end
5556
- # else
5557
- # # @show 3
5558
- # if hasexactunitmatch(unit_uuid)
5559
- # # @show 4
5560
- # popped = pop!(balance_unituuid2deckcardnums[unit_uuid])
5561
- # push!(fulfillment, OrderedFullfillment(segment_num, popped))
5562
- # elseif anywildsleft()
5563
- # # @show 5
5564
- # non_empty_wild_stack = getnonemptywildstack()
5565
- # popped = pop!(non_empty_wild_stack)
5566
- # push!(fulfillment, OrderedFullfillment(segment_num, popped))
5567
- # end
5568
- # end
5569
- # end
5570
-
5571
- # blank_remaining_segments = filter(
5572
- # ordered_segment -> isblank(ordered_segment.segment.unit_uuid),
5573
- # ordered_segments,
5574
- # )
5575
- # # @show blank_remaining_segments
5576
- # largest_non_wild_stack = getlargestnonwildstack()
5577
- # # @show largest_non_wild_stack
5578
- # for blank_remaining_segment in blank_remaining_segments
5579
- # if !isnothing(largest_non_wild_stack) && !isempty(largest_non_wild_stack)
5580
- # popped = pop!(largest_non_wild_stack)
5581
- # push!(fulfillment, OrderedFullfillment(blank_remaining_segment.path_segment_num, popped))
5582
- # elseif gettotalwildcount() > 0
5583
- # popped = popawildcard!()
5584
- # push!(fulfillment, OrderedFullfillment(blank_remaining_segment.path_segment_num, popped))
5585
- # end
5586
- # end
5587
-
5588
- # # @show fulfillment
5589
- # deepq_edges = map(ordered_segments) do ordered_segment
5590
- # (; path_segment_num) = ordered_segment
5591
- # (; segment) = ordered_segment
5592
- # fullfillable_by_me = in(path_segment_num, [x.segment_num for x in fulfillment])
5593
- # captured_by_me = in(path_num, s.player_hands[player_idx].paths)
5594
- # captured_by_other = !captured_by_me && in(path_num, getclaimedpathidxs(s))
5595
- # available_to_me = !(captured_by_me || captured_by_other) && fullfillable_by_me
5596
- # status = "Other"
5597
- # if captured_by_me
5598
- # status = "CapturedByMe"
5599
- # elseif captured_by_other
5600
- # status = "CapturedByOther"
5601
- # elseif available_to_me
5602
- # status = "AvailableToMe"
5603
- # end
5604
- # SegmentStatus(
5605
- # path_num,
5606
- # path_segment_num,
5607
- # captured_by_me,
5608
- # captured_by_other,
5609
- # available_to_me,
5610
- # status,
5611
- # segment,
5612
- # )
5613
- # end
5614
-
5615
- # fulfillable = Base.all([x.available_to_me for x in deepq_edges])
5616
- # PathStatus(path_num, fulfillable, deepq_edges, fulfillment)
5617
- # end
5618
- def getpathstatus(s, player_idx, path_idx):
5619
- path_num = path_idx + 1
5620
- balance = s.player_hands[player_idx].unit_cards
5621
- fig = s.game_config.fig
5622
- board_config = fig.board_config
5623
- deck_units = board_config.deck_units
5624
- board_paths = board_config.board_paths
5625
- unituuid2deckunit = {x.unit_uuid: x for x in deck_units}
5626
- path = board_paths[path_idx]
5627
- ordered_segments = prioritysort(fig, path.path.segments)
5628
- fulfillment = []
5629
- wild_unit_uuids = getwildunituuids(fig)
5630
- non_wild_unit_uuids = getnonwildunituuids(fig)
5631
-
5632
- balance_unituuid2deckcardnums = {}
5633
-
5634
- for deck_card_num in balance:
5635
- unit_uuid = getunituuid(fig, deck_card_num)
5636
- if unit_uuid not in balance_unituuid2deckcardnums:
5637
- balance_unituuid2deckcardnums[unit_uuid] = []
5638
- balance_unituuid2deckcardnums[unit_uuid].append(deck_card_num)
5639
-
5640
- def hasexactunitmatch(unit_uuid):
5641
- # print("unit_uuid: ", unit_uuid)
5642
- # print("balance_unituuid2deckcardnums: ", balance_unituuid2deckcardnums)
5643
- print("")
5644
- return (
5645
- unit_uuid in balance_unituuid2deckcardnums and
5646
- len(balance_unituuid2deckcardnums[unit_uuid]) > 0
5647
- )
5648
-
5649
- def anywildsleft():
5650
- for wild_unit_uuid in wild_unit_uuids:
5651
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5652
- if balance_unituuid2deckcardnums[wild_unit_uuid]:
5653
- return True
5654
- return False
5655
-
5656
- def gettotalwildcount():
5657
- count = 0
5658
- for wild_unit_uuid in wild_unit_uuids:
5659
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5660
- count += len(balance_unituuid2deckcardnums[wild_unit_uuid])
5661
- return count
5662
-
5663
- def popawildcard():
5664
- for wild_unit_uuid in wild_unit_uuids:
5665
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5666
- if balance_unituuid2deckcardnums[wild_unit_uuid]:
5667
- return balance_unituuid2deckcardnums[wild_unit_uuid].pop()
5668
- return None
5669
4767
 
5670
- def getnonemptywildstack():
5671
- for wild_unit_uuid in wild_unit_uuids:
5672
- if wild_unit_uuid in balance_unituuid2deckcardnums:
5673
- if balance_unituuid2deckcardnums[wild_unit_uuid]:
5674
- return balance_unituuid2deckcardnums[wild_unit_uuid]
5675
- return None
5676
4768
 
5677
- def getlargestnonwildstack():
5678
- largest_non_wild_unit_uuid = None
5679
- largest_found = 0
5680
- for non_wild_unit_uuid in non_wild_unit_uuids:
5681
- if non_wild_unit_uuid in balance_unituuid2deckcardnums:
5682
- curr_length = len(balance_unituuid2deckcardnums[non_wild_unit_uuid])
5683
- if curr_length > largest_found:
5684
- largest_found = curr_length
5685
- largest_non_wild_unit_uuid = non_wild_unit_uuid
5686
- if largest_non_wild_unit_uuid is not None:
5687
- return balance_unituuid2deckcardnums[largest_non_wild_unit_uuid]
5688
- return None
5689
-
5690
- for ordered_segment in ordered_segments:
5691
- target_segment = ordered_segment.segment
5692
- segment_num = ordered_segment.path_segment_num
5693
- unit_uuid = target_segment.unit_uuid
5694
- target_unit = None if unit_uuid is None else unituuid2deckunit[unit_uuid]
5695
-
5696
- if target_unit is None:
5697
- # do nothing (this is a blank segment)
5698
- pass
5699
- elif target_unit.is_wild:
5700
- if hasexactunitmatch(unit_uuid):
5701
- popped = balance_unituuid2deckcardnums[unit_uuid].pop()
5702
- fulfillment.append(OrderedFullfillment(segment_num=segment_num, unit_card_num=popped))
5703
- else:
5704
- # print("anywildsleft(): ", anywildsleft())
5705
- if hasexactunitmatch(unit_uuid):
5706
- popped = balance_unituuid2deckcardnums[unit_uuid].pop()
5707
- fulfillment.append(OrderedFullfillment(segment_num=segment_num, unit_card_num=popped))
5708
- elif anywildsleft():
5709
- non_empty_wild_stack = getnonemptywildstack()
5710
- popped = non_empty_wild_stack.pop()
5711
- fulfillment.append(OrderedFullfillment(segment_num=segment_num, unit_card_num=popped))
5712
- # @show 5
5713
-
5714
- blank_remaining_segments = list(filter(
5715
- lambda ordered_segment: ordered_segment.segment.unit_uuid is None,
5716
- ordered_segments,
5717
- ))
5718
-
5719
- largest_non_wild_stack = getlargestnonwildstack()
5720
-
5721
- for blank_remaining_segment in blank_remaining_segments:
5722
- if largest_non_wild_stack is not None and largest_non_wild_stack:
5723
- popped = largest_non_wild_stack.pop()
5724
- fulfillment.append(OrderedFullfillment(segment_num=blank_remaining_segment.path_segment_num, unit_card_num=popped))
5725
- elif gettotalwildcount() > 0:
5726
- popped = popawildcard()
5727
- fulfillment.append(OrderedFullfillment(segment_num=blank_remaining_segment.path_segment_num, unit_card_num=popped))
5728
-
5729
- # Implementing the following Julia code:
5730
- # deepq_edges = map(ordered_segments) do ordered_segment
5731
- # (; path_segment_num) = ordered_segment
5732
- # (; segment) = ordered_segment
5733
- # fullfillable_by_me = in(path_segment_num, [x.segment_num for x in fulfillment])
5734
- # captured_by_me = in(path_num, s.player_hands[player_idx].paths)
5735
- # captured_by_other = !captured_by_me && in(path_num, getclaimedpathidxs(s))
5736
- # available_to_me = !(captured_by_me || captured_by_other) && fullfillable_by_me
5737
- # status = "Other"
5738
- # if captured_by_me
5739
- # status = "CapturedByMe"
5740
- # elseif captured_by_other
5741
- # status = "CapturedByOther"
5742
- # elseif available_to_me
5743
- # status = "AvailableToMe"
5744
- # end
5745
- # SegmentStatus(
5746
- # path_num,
5747
- # path_segment_num,
5748
- # captured_by_me,
5749
- # captured_by_other,
5750
- # available_to_me,
5751
- # status,
5752
- # segment,
5753
- # )
5754
- # end
5755
- # fulfillable = Base.all([x.available_to_me for x in deepq_edges])
5756
- # PathStatus(path_num, fulfillable, deepq_edges, fulfillment)
5757
- deepq_edges = []
5758
- for ordered_segment in ordered_segments:
5759
- path_segment_num = ordered_segment.path_segment_num
5760
- segment = ordered_segment.segment
5761
- fullfillable_by_me = path_segment_num in [x.segment_num for x in fulfillment]
5762
- captured_by_me = path_idx in s.player_hands[player_idx].paths
5763
- captured_by_other = not captured_by_me and path_idx in getclaimedpathidxs(s)
5764
- available_to_me = not (captured_by_me or captured_by_other) and fullfillable_by_me
5765
- status = "Other"
5766
- if captured_by_me:
5767
- status = "CapturedByMe"
5768
- elif captured_by_other:
5769
- status = "CapturedByOther"
5770
- elif available_to_me:
5771
- status = "AvailableToMe"
5772
-
5773
- deepq_edges.append(
5774
- SegmentStatus(
5775
- path_idx=path_idx,
5776
- path_num=path_num,
5777
- path_segment_num=path_segment_num,
5778
- captured_by_me=captured_by_me,
5779
- captured_by_other=captured_by_other,
5780
- available_to_me=available_to_me,
5781
- status=status,
5782
- segment=segment
5783
- )
5784
- )
5785
-
5786
- fulfillable = all([x.available_to_me for x in deepq_edges])
5787
- return PathStatus(
5788
- idx=path_idx,
5789
- num=path_num,
5790
- fulfillable=fulfillable,
5791
- segment_statuses=deepq_edges,
5792
- sample_fulfillment=fulfillment
5793
- )
5794
-
5795
-
5796
- # Implementing the following Julia function:
5797
- # function getavailablepoints(s::State, player_num::Int)
5798
- # point_statuses = map(getpotentialpointuuids(s, player_num)) do point_uuid
5799
- # getpointstatus(s, player_num, point_uuid)
5800
- # end
5801
- # sort(filter(x -> x.fulfillable, point_statuses); by=x -> x.uuid)
5802
- # end
5803
- def getavailablepoints(s, player_num):
5804
- point_statuses = [
5805
- getpointstatus(s, player_num, point_uuid)
5806
- for point_uuid in getpotentialpointuuids(s, player_num)
5807
- ]
5808
- return sorted(
5809
- filter(lambda x: x['fulfillable'], point_statuses),
5810
- key=lambda x: x['uuid']
5811
- )
5812
-
5813
- # Implementing the following Julia function:
5814
- # function getpointstatus(s::State, player_idx::Int, point_uuid::UUID)
5815
- # balance = s.player_hands[player_idx].unit_cards
5816
- # fulfillment = OrderedPointFullfillment[]
5817
- # if !isempty(balance)
5818
- # push!(fulfillment, OrderedPointFullfillment(balance[1]))
5819
- # end
5820
- # PointStatus(point_uuid, true, fulfillment)
5821
- # end
5822
- def getpointstatus(s, player_idx, point_uuid):
5823
- balance = s.player_hands[player_idx].unit_cards
5824
- fulfillment = []
5825
- if balance:
5826
- fulfillment.append({'unit_card_num': balance[0]})
5827
- return {
5828
- 'uuid': point_uuid,
5829
- 'fulfillable': True,
5830
- 'sample_fulfillment': fulfillment
5831
- }
5832
4769
 
5833
- # Implementing the following Julia function:
5834
- # function getpotentialpointuuids(s::State, player_num::Int)
5835
- # (; num_point_pieces) = s.player_hands[player_num]
5836
- # setdiff(
5837
- # Set(getnodeuuids(s.fig, num_point_pieces)),
5838
- # Set(getunavailablepoints(s)),
5839
- # ) |> collect
5840
- # end
5841
- def getpotentialpointuuids(s, player_num):
5842
- num_point_pieces = s.player_hands[player_num].num_point_pieces
5843
- return list(
5844
- set(getnodeuuids(s.game_config.fig, num_point_pieces)) -
5845
- set(getunavailablepoints(s))
5846
- )
5847
4770
 
5848
4771
  # Implementing the following Julia function:
5849
4772
  # function getnodeuuids(f::Fig, remaining_pieces::Int)
@@ -5880,33 +4803,6 @@ def getunavailablepoints(s):
5880
4803
  return unavailable_points
5881
4804
 
5882
4805
 
5883
- # Implementing the following Julia function:
5884
- # function calcfinalscores(s::State)
5885
- # if !s.terminal
5886
- # return s
5887
- # end
5888
- # @reset s.player_hands = calcfinalscore.(s, s.player_hands)
5889
- # s
5890
- # end
5891
- @dispatch(State)
5892
- def calcfinalscores(s):
5893
- if not s.terminal:
5894
- return s
5895
- return s.set(player_hands=pvector([calcfinalscore(s, h) for h in s.player_hands]))
5896
-
5897
-
5898
- # Implementing the following Julia function:
5899
- # function calcfinalscore(s::State, hand::PlayerInfo)
5900
- # (; total, breakdown) = getprivatescore(s, hand)
5901
- # @reset hand.final_score = PlayerScore(total, breakdown)
5902
- # hand
5903
- # end
5904
- @dispatch(State, PlayerInfo)
5905
- def calcfinalscore(s, hand):
5906
- total, breakdown = getprivatescore(s, hand)
5907
- return hand.set(final_score=PlayerScore(total=total, breakdown=breakdown))
5908
-
5909
-
5910
4806
  # Implementing the following Julia function:
5911
4807
  # function calcwinners(s::State)
5912
4808
  # if !s.terminal
@@ -5930,172 +4826,15 @@ def calcwinners(s):
5930
4826
 
5931
4827
 
5932
4828
  def printplayer(s, player_idx):
5933
- hand = s.player_hands[player_idx]
5934
- legal_actions = getlegalactionspecs(s, player_idx)
5935
- print(f"~~~~~~~~~~~~ P{player_idx} ~~~~~~~~~~~~")
5936
- print(f"private score: {getprivatescore(s, hand)}")
5937
- print(f"public score: {getpublicscore(s, player_idx)}")
5938
- print(f"completed clusters: {list(str(c) for c in hand.completed_clusters)}")
5939
- print(f"units: {list(hand.unit_cards)}")
5940
- if getsettingvalue(s, "route_scoring"):
5941
- print(f"routes: {list(hand.route_cards)} choices:{list(hand.new_route_cards)}")
5942
- print(f"captured points: {list(str(p) for p in hand.points)}")
5943
- print(f"legal actions: {list(a.action_name for a in legal_actions)}")
4829
+ pass
5944
4830
 
5945
4831
 
5946
4832
  def printstate(s):
5947
- print(f"*************** State {state_idx} ***************")
5948
- print(f"Last to play: {s.last_to_play}")
5949
- print(f"Winners: {list(s.winners)}")
5950
- print(f"Route Deck: {list(s.route_cards)}")
5951
- print(f"Route Disc: {list(s.route_discards)}")
5952
- print(f"Unit Deck: ...{list(s.unit_cards[60:])}")
5953
- print(f"Unit Disc: {list(s.unit_discards)}")
5954
- print(f"FaceUp: {list(s.faceup_spots)}")
5955
- print(f"ToPlay: {gettoplay(s)}")
5956
- print(f"Terminal: {s.terminal}")
5957
-
5958
- for i in range(s.game_config.num_players):
5959
- printplayer(s, i)
5960
- print(f"****************************************\n")
4833
+ pass
5961
4834
 
5962
4835
 
5963
4836
  def printaction(a, i):
5964
- print(f"\n\n*************** Action {i} ***************")
5965
- print(f"{a}")
5966
- print(f"****************************************\n\n\n")
5967
-
5968
-
5969
- # Implementing the following Julia function:
5970
- # function getprivatescore(s::State, hand::PlayerInfo; bonus=true)
5971
- # player_idx = hand.player_idx
5972
- # breakdown = []
5973
-
5974
- # # Path scores
5975
- # if getsettingvalue(s, :path_scoring)
5976
- # (; path_scores) = s.fig
5977
- # for len in getplayerpathlens(s, player_idx)
5978
- # push!(
5979
- # breakdown,
5980
- # ScoreItem(
5981
- # code_idx=getscorecodeidx(s.fig, :PATH),
5982
- # amount=path_scores[len],
5983
- # )
5984
- # )
5985
- # end
5986
- # end
5987
-
5988
- # # Bonus: most clusters
5989
- # if getsettingvalue(s, :most_clusters_bonus)
5990
- # bonus_most_clusters_score = getsettingvalue(s.fig, :bonus_most_clusters_score)
5991
- # if in(player_idx, s.most_clusters_player_idxs)
5992
- # push!(
5993
- # breakdown,
5994
- # ScoreItem(
5995
- # code_idx=getscorecodeidx(s.fig, :MOST_CLUSTERS),
5996
- # amount=bonus_most_clusters_score,
5997
- # )
5998
- # )
5999
- # end
6000
- # end
6001
-
6002
- # # Longest trail
6003
- # if !getsettingvalue(s, :disable_longest_path_bonus)
6004
- # longest_path_score = getsettingvalue(s.fig, :longest_path_score)
6005
- # if in(player_idx, s.longest_trail_player_idxs)
6006
- # push!(
6007
- # breakdown,
6008
- # ScoreItem(
6009
- # code_idx=getscorecodeidx(s.fig, :LONGEST_ROAD),
6010
- # amount=longest_path_score,
6011
- # )
6012
- # )
6013
- # end
6014
- # end
6015
-
6016
- # # Completed routes
6017
- # if getsettingvalue(s, :route_scoring)
6018
- # hand = s.player_hands[player_idx]
6019
- # (; board_config) = s.fig
6020
- # (; routes) = board_config
6021
- # for route_idx in hand.route_cards
6022
- # route_score = routes[route_idx].score
6023
- # amount = in(route_idx, hand.completed_routes) ? route_score : -1*route_score
6024
- # push!(
6025
- # breakdown,
6026
- # ScoreItem(
6027
- # code_idx=getscorecodeidx(s.fig, :ROUTE),
6028
- # amount=amount
6029
- # )
6030
- # )
6031
- # end
6032
- # end
6033
-
6034
- # # Completed clusters
6035
- # if getsettingvalue(s, :cluster_scoring)
6036
- # (; clusters) = s.fig.board_config
6037
- # uuid2cluster = Dict((x.uuid, x) for x in clusters)
6038
- # (; completed_clusters) = s.player_hands[player_idx]
6039
- # cluster_scores = map(completed_clusters) do cluster_uuid
6040
- # uuid2cluster[cluster_uuid].score
6041
- # end
6042
- # if !isempty(cluster_scores)
6043
- # push!(breakdown,
6044
- # ScoreItem(
6045
- # code_idx=getscorecodeidx(s.fig, :CLUSTER),
6046
- # amount=sum(cluster_scores)
6047
- # )
6048
- # )
6049
- # end
6050
- # end
6051
-
6052
- # amounts = [item.amount for item in breakdown]
6053
- # total = sum(amounts; init=0)
6054
- # (
6055
- # total=total,
6056
- # breakdown=breakdown,
6057
- # )
6058
- # end
6059
- @dispatch(State, PlayerInfo)
6060
- def getprivatescore(s, hand):
6061
- player_idx = hand.player_idx
6062
- breakdown = []
6063
-
6064
- # Path scores
6065
- if getsettingvalue(s, 'path_scoring'):
6066
- path_scores = s.game_config.fig.path_scores
6067
- for len in getplayerpathlens(s, player_idx):
6068
- breakdown.append(ScoreItem(
6069
- code_idx=getscorecodeidx(s.game_config.fig, 'PATH'),
6070
- amount=path_scores[len],
6071
- ))
6072
-
6073
- # Completed routes
6074
- if False and getsettingvalue(s, 'route_scoring'):
6075
- routes = s.game_config.fig.board_config.routes
6076
- for route_idx in hand.route_cards:
6077
- route_score = routes[route_idx].score
6078
- amount = route_score if route_idx in hand.completed_routes else -1 * route_score
6079
- breakdown.append(ScoreItem(
6080
- code_idx=getscorecodeidx(s.game_config.fig, 'ROUTE'),
6081
- amount=amount
6082
- ))
6083
-
6084
- # Completed clusters
6085
- if getsettingvalue(s, 'cluster_scoring'):
6086
- clusters = s.game_config.fig.board_config.clusters
6087
- uuid2cluster = {x.uuid: x for x in clusters}
6088
- completed_clusters = hand.completed_clusters
6089
- cluster_scores = [uuid2cluster[cluster_uuid].score for cluster_uuid in completed_clusters]
6090
- if cluster_scores:
6091
- breakdown.append(ScoreItem(
6092
- code_idx=getscorecodeidx(s.game_config.fig, 'CLUSTER'),
6093
- amount=sum(cluster_scores)
6094
- ))
6095
-
6096
- amounts = [item.amount for item in breakdown]
6097
- total = sum(amounts)
6098
- return total, breakdown
4837
+ pass
6099
4838
 
6100
4839
 
6101
4840
  # Implementing the following Julia function:
@@ -6134,46 +4873,6 @@ def getscorecodes(f):
6134
4873
  return score_codes
6135
4874
 
6136
4875
 
6137
- # Implementing the following Julia function:
6138
- # function assertunitcardsaccountedfor(s::State)
6139
- # total_num_unit_cards = gettotaldeckcards(s.fig)
6140
- # total_found = getunitcardstotalfound(s)
6141
- # @assert total_num_unit_cards == total_found "Unit cards not accounted for. $(total_num_unit_cards) != $(total_found)"
6142
- # end
6143
- def assertunitcardsaccountedfor(s):
6144
- total_num_unit_cards = gettotaldeckcards(s.game_config.fig)
6145
- total_found = getunitcardstotalfound(s)
6146
- assert total_num_unit_cards == total_found, f"Unit cards not accounted for. {total_num_unit_cards} != {total_found}"
6147
-
6148
-
6149
- # Implementing the following Julia function:
6150
- # function getunitcardstotalfound(s::State)
6151
- # num_player_unit_cards = sum(gettotalnumunitcards.(s.player_hands))
6152
- # total_found = sum([
6153
- # num_player_unit_cards,
6154
- # length(s.unit_discards),
6155
- # length(s.unit_cards),
6156
- # length(getvalidspotnums(s)),
6157
- # ])
6158
- # total_found
6159
- # end
6160
- def getunitcardstotalfound(s):
6161
- num_player_unit_cards = sum(gettotalnumunitcards(p) for p in s.player_hands)
6162
- total_found = sum([
6163
- num_player_unit_cards,
6164
- len(s.unit_discards),
6165
- len(s.unit_cards),
6166
- len(getvalidspotnums(s)),
6167
- ])
6168
- return total_found
6169
-
6170
-
6171
- # Implementing the following Julia function:
6172
- # gettotalnumunitcards(player_hand::PlayerInfo) = length(player_hand.unit_cards)
6173
- def gettotalnumunitcards(player_hand):
6174
- return len(player_hand.unit_cards)
6175
-
6176
-
6177
4876
  # Implementing the following Julia function:
6178
4877
  # function getvalidspotnums(s::State)
6179
4878
  # filter(n -> !isnothing(s.faceup_spots[n]), 1:length(s.faceup_spots))
@@ -6182,44 +4881,6 @@ def getvalidspotnums(s):
6182
4881
  return [n for n in range(1, len(s.faceup_spots) + 1) if s.faceup_spots[n-1] is not None]
6183
4882
 
6184
4883
 
6185
- # Implementing the following Julia function:
6186
- # function assertroutecardsaccountedfor(s::State)
6187
- # total_num_route_cards = getnumroutecards(s.fig)
6188
- # num_player_route_cards = sum(gettotalnumroutecards.(s.player_hands))
6189
- # total_found = sum([
6190
- # num_player_route_cards,
6191
- # length(s.route_discards),
6192
- # length(s.route_cards),
6193
- # ])
6194
- # @assert total_num_route_cards == total_found "Route cards not accounted for. $(total_num_route_cards) != $(total_found)"
6195
- # end
6196
- def assertroutecardsaccountedfor(s):
6197
- total_num_route_cards = getnumroutecards(s.game_config.fig)
6198
- num_player_route_cards = sum(gettotalnumroutecards(p) for p in s.player_hands)
6199
- total_found = sum([
6200
- num_player_route_cards,
6201
- len(s.route_discards),
6202
- len(s.route_cards),
6203
- ])
6204
- assert total_num_route_cards == total_found, f"Route cards not accounted for. {total_num_route_cards} != {total_found}"
6205
-
6206
-
6207
- # Implementing the following Julia function:
6208
- # gettotalnumroutecards(player_hand::PlayerInfo) = length(player_hand.route_cards) + length(player_hand.new_route_cards)
6209
- def gettotalnumroutecards(player_hand):
6210
- return len(player_hand.route_cards) + len(player_hand.new_route_cards)
6211
-
6212
-
6213
- # Implementing the following Julia function:
6214
- # function assertallcardsaccountedfor(s::State)
6215
- # assertroutecardsaccountedfor(s)
6216
- # assertunitcardsaccountedfor(s)
6217
- # end
6218
- def assertallcardsaccountedfor(s):
6219
- assertroutecardsaccountedfor(s)
6220
- assertunitcardsaccountedfor(s)
6221
-
6222
-
6223
4884
  # Implementing the following Julia function:
6224
4885
  # function getlegalactions(s::State)
6225
4886
  # getlegalactions(s, gettoplay(s))
@@ -6245,74 +4906,6 @@ def getlegalactionspecs(s, player_idxs):
6245
4906
  return legal_actions
6246
4907
 
6247
4908
 
6248
- # Implementing the following Julia function:
6249
- # function getcapturedsegments(s::State)
6250
- # (; fig) = s
6251
- # (; board_config) = fig
6252
- # public_player_hands = PublicPlayerInfo.(s, s.player_hands)
6253
- # (; board_paths) = board_config
6254
- # captured_segments = CapturedSegment[]
6255
- # for (player_num, player_hand) in enumerate(public_player_hands)
6256
- # for path_num in player_hand.paths
6257
- # link_path = board_paths[path_num].path
6258
- # for segment in link_path.segments
6259
- # captured_segment = CapturedSegment(
6260
- # player_num,
6261
- # segment.uuid,
6262
- # )
6263
- # push!(captured_segments, captured_segment)
6264
- # end
6265
- # end
6266
- # end
6267
- # captured_segments
6268
- # end
6269
- @dispatch(State)
6270
- def getcapturedsegments(s):
6271
- public_player_hands = [getpublicplayerinfo(s, p) for p in s.player_hands]
6272
- board_paths = s.game_config.fig.board_config.board_paths
6273
- captured_segments = []
6274
- for player_idx, player_hand in enumerate(public_player_hands):
6275
- for path_idx in player_hand.paths:
6276
- link_path = board_paths[path_idx].path
6277
- for segment in link_path.segments:
6278
- captured_segment = CapturedSegment(
6279
- player_num=(player_idx+1),
6280
- segment_uuid=segment.uuid,
6281
- )
6282
- captured_segments.append(captured_segment)
6283
- return captured_segments
6284
-
6285
-
6286
- # Implementing the following Julia function:
6287
- # function getcapturedpoints(s::State)
6288
- # (; fig) = s
6289
- # public_player_hands = PublicPlayerInfo.(s, s.player_hands)
6290
- # captured_points = CapturedPoint[]
6291
- # for (player_num, player_hand) in enumerate(public_player_hands)
6292
- # for point_uuid in player_hand.points
6293
- # captured_point = CapturedPoint(
6294
- # player_num,
6295
- # point_uuid,
6296
- # )
6297
- # push!(captured_points, captured_point)
6298
- # end
6299
- # end
6300
- # captured_points
6301
- # end
6302
- @dispatch(State)
6303
- def getcapturedpoints(s):
6304
- public_player_hands = [getpublicplayerinfo(s, p) for p in s.player_hands]
6305
- captured_points = []
6306
- for player_idx, player_hand in enumerate(public_player_hands):
6307
- for point_uuid in player_hand.points:
6308
- captured_point = CapturedPoint(
6309
- player_num=player_idx+1,
6310
- point_uuid=point_uuid,
6311
- )
6312
- captured_points.append(captured_point)
6313
- return captured_points
6314
-
6315
-
6316
4909
  def json_serializer(obj):
6317
4910
  if isinstance(obj, set):
6318
4911
  return list(obj)
@@ -6374,7 +4967,6 @@ def getprivatestate(s, player_idx):
6374
4967
  player=s.players[player_idx],
6375
4968
  legal_actions_2 = get_legal_actions(s, player_idx),
6376
4969
  legal_actions=legal_actions,
6377
- hand=s.player_hands[player_idx],
6378
4970
  goal_completions=goal_completions,
6379
4971
  )
6380
4972
 
@@ -6522,132 +5114,92 @@ def diff(A, dims=None):
6522
5114
  return [[A[i][j] - A[i][j - 1] for j in range(1, len(A[0]))] for i in range(len(A))]
6523
5115
  else:
6524
5116
  raise ValueError("dims must be either 1 or 2")
6525
-
6526
5117
 
6527
- @dispatch(StaticBoardConfig, PlayerState)
6528
- def get_imagined_state(static_board_config, player_state):
6529
- board_config = static_board_config.board_config
6530
- public_state = player_state.public
6531
- private_state = player_state.private
6532
- my_hand = private_state.hand
6533
-
6534
- fig = initfig("af472d67-05ec-4b5d-9eb7-6b0cea9eec5a", board_config)
6535
- seed = 4012489341 # TODO: this should be random (or if non-stochastic, loaded from the net.seed)
6536
- rng = getrng(seed)
6537
-
6538
- # TODO: this needs to come from x_json['game_config']
6539
- game_config = GameConfig(
6540
- uuid = str(generate_uuid_with_rng(rng)),
6541
- started_at = "2025-01-01 00:00:00",
6542
- num_players = 2,
6543
- fig = fig,
6544
- seed = seed
6545
- )
6546
5118
 
6547
- possible_route_card_idxs = list(range(getnumroutecards(fig)))
6548
- 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
6549
5123
 
6550
- def remove_card_idx(to_mutate, card_idx):
6551
- if card_idx in to_mutate:
6552
- to_mutate.remove(card_idx)
6553
5124
 
6554
- def remove_card_idxs(to_mutate, card_idxs):
6555
- for card_idx in card_idxs:
6556
- 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]
6557
5129
 
6558
-
6559
- imagined_route_card_idxs = rng.sample(possible_route_card_idxs, public_state.num_route_cards)
6560
- remove_card_idxs(possible_route_card_idxs, imagined_route_card_idxs)
6561
- imagined_route_discard_idxs = rng.sample(possible_route_card_idxs, public_state.num_route_discards)
6562
- remove_card_idxs(possible_route_card_idxs, imagined_route_discard_idxs)
6563
5130
 
6564
- imagined_route_cards = [x+1 for x in imagined_route_card_idxs]
6565
- 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
6566
5136
 
6567
- for unit_card in public_state.unit_discards:
6568
- remove_card_idx(possible_unit_card_idxs, unit_card-1)
6569
5137
 
6570
- for unit_card in my_hand.unit_cards:
6571
- remove_card_idx(possible_unit_card_idxs, unit_card-1)
5138
+ def getvproxy0(ps):
5139
+ return 0
6572
5140
 
6573
- imagined_unit_card_idxs = rng.sample(possible_unit_card_idxs, public_state.num_unit_cards)
6574
- imagined_unit_cards = [x+1 for x in imagined_unit_card_idxs]
6575
- remove_card_idxs(possible_unit_card_idxs, imagined_unit_card_idxs)
6576
5141
 
5142
+ def imagine_dynamics(ps, a):
5143
+ return dynamics(imagine_state(ps), a)
6577
5144
 
6578
- imagined_player_hands = []
6579
5145
 
6580
- for (player_idx, public_player_info) in enumerate(public_state.player_hands):
6581
- if player_idx == my_hand.player_idx:
6582
- imagined_player_hands.append(PlayerInfo.clone(my_hand))
6583
- else:
6584
- imagined_player_unit_card_idxs = rng.sample(possible_unit_card_idxs, public_player_info.num_unit_cards)
6585
- imagined_player_unit_cards = [x+1 for x in imagined_player_unit_card_idxs]
6586
- remove_card_idxs(possible_unit_card_idxs, imagined_player_unit_card_idxs)
6587
- imagined_player_route_card_idxs = rng.sample(possible_route_card_idxs, public_player_info.num_route_cards)
6588
- remove_card_idxs(possible_route_card_idxs, imagined_player_route_card_idxs)
6589
- imagined_player_new_route_card_idxs = rng.sample(possible_route_card_idxs, public_player_info.num_new_route_cards)
6590
- remove_card_idxs(possible_route_card_idxs, imagined_player_new_route_card_idxs)
6591
- imagined_player_route_cards = [x+1 for x in imagined_player_route_card_idxs]
6592
- imagined_player_new_route_cards = [x+1 for x in imagined_player_new_route_card_idxs]
6593
- imagined_player_hands.append(
6594
- PlayerInfo(
6595
- fig = fig,
6596
- player_idx = player_idx,
6597
- new_route_cards = pvector(imagined_player_new_route_cards), # Guess at this.
6598
- route_cards = pvector(imagined_player_route_cards), # Guess at this.
6599
- unit_cards = pvector(imagined_player_unit_cards), # Guess at this.
6600
- completed_routes = [], # Guess at this.
6601
- completed_clusters = public_player_info.completed_clusters,
6602
- paths = public_player_info.paths,
6603
- points = public_player_info.points,
6604
- tokens = public_player_info.tokens,
6605
- num_pieces = public_player_info.num_pieces,
6606
- num_point_pieces = public_player_info.num_point_pieces,
6607
- longest_trail = public_player_info.longest_trail,
6608
- longest_trail_len = public_player_info.longest_trail_len,
6609
- final_score = public_player_info.final_score,
6610
- )
6611
- )
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
6612
5152
 
6613
5153
 
6614
- nodeuuid2idx = {node.uuid: idx for idx, node in enumerate(board_config.points)}
6615
- edges = get_edges(rng, board_config, nodeuuid2idx)
6616
- edgeuuid2idx = {edge.uuid: idx for idx, edge in enumerate(edges)}
6617
- edgetuple2uuid = {}
6618
- for edge in edges:
6619
- node_1_idx = nodeuuid2idx[edge.node_1_uuid]
6620
- node_2_idx = nodeuuid2idx[edge.node_2_uuid]
6621
- edge_tuple = (min(node_1_idx, node_2_idx), max(node_1_idx, node_2_idx))
6622
- edgetuple2uuid[edge_tuple] = edge.uuid
6623
-
6624
- return State(
6625
- final_scores = None,
6626
- player_graphs = [],
6627
- nodes = get_nodes(board_config),
6628
- nodeuuid2idx = nodeuuid2idx,
6629
- edges = edges,
6630
- edgeuuid2idx = edgeuuid2idx,
6631
- edgetuple2uuid = edgetuple2uuid,
6632
- regions = get_regions(board_config),
6633
- legal_actions = [], # TODO: Should use PublicState, but empty for now.
6634
- piles = [], # TODO: Should use PublicState, but empty for now.
6635
- players = [], # TODO: Should use PublicState, but empty for now.
6636
- player_idxs = public_state.player_idxs,
6637
- decks = [], # TODO: Should use PublicState, but empty for now.
6638
- game_config = game_config,
6639
- rng = rng, # TODO: again figure out this stochasticity
6640
- terminal = public_state.terminal,
6641
- initial_to_play = public_state.initial_to_play,
6642
- route_cards = pvector(imagined_route_cards), # Guess at this.
6643
- route_discards = pvector(imagined_route_discards), # Guess at this.
6644
- player_hands = pvector(imagined_player_hands), # Guess at this.
6645
- unit_cards = pvector(imagined_unit_cards), # Guess at this.
6646
- faceup_spots = pvector(public_state.faceup_spots),
6647
- unit_discards = pvector(public_state.unit_discards),
6648
- last_to_play = public_state.last_to_play,
6649
- winners = public_state.winners,
6650
- )
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
+
6651
5203
 
6652
5204
  INIT_HOOK_1 = """def handler(game):
6653
5205
  return shuffle_all_decks(game)