graph-games-proto 0.3.1991__py3-none-any.whl → 0.3.2031__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 +661 -345
- {graph_games_proto-0.3.1991.dist-info → graph_games_proto-0.3.2031.dist-info}/METADATA +1 -1
- {graph_games_proto-0.3.1991.dist-info → graph_games_proto-0.3.2031.dist-info}/RECORD +5 -5
- {graph_games_proto-0.3.1991.dist-info → graph_games_proto-0.3.2031.dist-info}/WHEEL +0 -0
- {graph_games_proto-0.3.1991.dist-info → graph_games_proto-0.3.2031.dist-info}/top_level.txt +0 -0
graph_games_proto/fns.py
CHANGED
@@ -1936,12 +1936,13 @@ class StateKernel(PClass):
|
|
1936
1936
|
rng = field(type=random.Random)
|
1937
1937
|
game_config = field(type=GameConfig)
|
1938
1938
|
edges = field(type=list) # List[BiEdge]
|
1939
|
+
nodes = field(type=list) # List[Node]
|
1940
|
+
regions = field(type=list) # List[Region]
|
1939
1941
|
decks = field(type=list) # List[Deck]
|
1940
1942
|
piles = field(type=list) # List[Pile]
|
1941
1943
|
players = field(type=list) # List[Player]
|
1942
1944
|
player_idxs = field(type=list) # List[int]
|
1943
1945
|
history = field(type=list) # List[PublicAction]
|
1944
|
-
player_scores = field(type=list) # List[PlayerScore]
|
1945
1946
|
idx2path = field(type=list) # List[Path2]
|
1946
1947
|
pieceuuid2piece = field(type=dict) # Dict[str, Piece]
|
1947
1948
|
edgeuuid2idx = field(type=dict) # Dict[str, int]
|
@@ -1953,17 +1954,20 @@ class StateKernel(PClass):
|
|
1953
1954
|
starting_decks = field(type=list) # List[Deck]
|
1954
1955
|
starting_piles = field(type=list) # List[Pile]
|
1955
1956
|
goals = field(type=list) # List[FrozenGoal]
|
1957
|
+
last_to_play = field(type=(int, type(None)), initial=None)
|
1958
|
+
player_graphs_3 = field(type=list) # List[PlayerGraph]
|
1956
1959
|
def __todict__(self):
|
1957
1960
|
return {
|
1958
1961
|
"rng": rng2json(self.rng),
|
1959
1962
|
"game_config": self.game_config.__todict__(),
|
1960
1963
|
"edges": [edge.__todict__() for edge in self.edges],
|
1964
|
+
"nodes": [node.__todict__() for node in self.nodes],
|
1965
|
+
"regions": [region.__todict__() for region in self.regions],
|
1961
1966
|
"decks": [deck.__todict__() for deck in self.decks],
|
1962
1967
|
"piles": [pile.__todict__() for pile in self.piles],
|
1963
1968
|
"players": [player.__todict__() for player in self.players],
|
1964
1969
|
"player_idxs": self.player_idxs,
|
1965
1970
|
"history": [action.__todict__() for action in self.history],
|
1966
|
-
"player_scores": [score.__todict__() for score in self.player_scores],
|
1967
1971
|
"idx2path": [v.__todict__() for v in self.idx2path],
|
1968
1972
|
"pieceuuid2piece": {k: v.__todict__() for k, v in self.pieceuuid2piece.items()},
|
1969
1973
|
"edgeuuid2idx": self.edgeuuid2idx,
|
@@ -1975,6 +1979,8 @@ class StateKernel(PClass):
|
|
1975
1979
|
"starting_decks": [deck.__todict__() for deck in self.starting_decks],
|
1976
1980
|
"starting_piles": [pile.__todict__() for pile in self.starting_piles],
|
1977
1981
|
"goals": [goal.__todict__() for goal in self.goals],
|
1982
|
+
"last_to_play": self.last_to_play,
|
1983
|
+
"player_graphs_3": [x.__todict__() for x in self.player_graphs_3],
|
1978
1984
|
}
|
1979
1985
|
@staticmethod
|
1980
1986
|
def __fromdict__(d):
|
@@ -1982,12 +1988,13 @@ class StateKernel(PClass):
|
|
1982
1988
|
rng=json2rng(d["rng"]),
|
1983
1989
|
game_config=GameConfig.__fromdict__(d["game_config"]),
|
1984
1990
|
edges=[BiEdge.__fromdict__(edge) for edge in d["edges"]],
|
1991
|
+
nodes=[Node.__fromdict__(n) for n in d["nodes"]],
|
1992
|
+
regions=[Region.__fromdict__(r) for r in d["regions"]],
|
1985
1993
|
decks=[Deck.__fromdict__(deck) for deck in d["decks"]],
|
1986
1994
|
piles=[Pile.__fromdict__(pile) for pile in d["piles"]],
|
1987
1995
|
players=[Player.__fromdict__(player) for player in d["players"]],
|
1988
1996
|
player_idxs=d["player_idxs"],
|
1989
1997
|
history=[PublicAction.__fromdict__(action) for action in d["history"]],
|
1990
|
-
player_scores=[PlayerScore.__fromdict__(score) for score in d["player_scores"]],
|
1991
1998
|
idx2path=[Path2.__fromdict(v) for v in d["idx2path"]],
|
1992
1999
|
pieceuuid2piece={k: Piece.__fromdict(v) for k, v in d["pieceuuid2piece"].items()},
|
1993
2000
|
edgeuuid2idx=d["edgeuuid2idx"],
|
@@ -1999,6 +2006,8 @@ class StateKernel(PClass):
|
|
1999
2006
|
starting_decks=[Deck.__fromdict__(x) for x in d["starting_decks"]],
|
2000
2007
|
starting_piles=[Pile.__fromdict__(x) for x in d["starting_piles"]],
|
2001
2008
|
goals=[FrozenGoal.__fromdict__(goal) for goal in d["goals"]],
|
2009
|
+
last_to_play=d.get("last_to_play"),
|
2010
|
+
player_graphs_3=[PlayerGraph.__fromdict__(x) for x in d["player_graphs_3"]],
|
2002
2011
|
)
|
2003
2012
|
|
2004
2013
|
|
@@ -2007,6 +2016,7 @@ def init_state_kernel(**kwargs):
|
|
2007
2016
|
game_config = kwargs.get('game_config')
|
2008
2017
|
fig = game_config.fig
|
2009
2018
|
board_config = fig.board_config
|
2019
|
+
nodes = kwargs.get('nodes', [])
|
2010
2020
|
edges = kwargs.get('edges', [])
|
2011
2021
|
idx2path = []
|
2012
2022
|
edgeuuid2idx = {edge.uuid: idx for idx, edge in enumerate(edges)}
|
@@ -2041,16 +2051,18 @@ def init_state_kernel(**kwargs):
|
|
2041
2051
|
bonuses = game_config.fig.board_config.bonuses
|
2042
2052
|
bonusuuid2bonusidx = {bonus.uuid: idx for idx, bonus in enumerate(bonuses)}
|
2043
2053
|
|
2054
|
+
player_graphs_3 = calc_player_graphs3(nodes, edges, pieceuuid2piece, game_config)
|
2055
|
+
|
2044
2056
|
return StateKernel(
|
2045
2057
|
rng=rng,
|
2046
2058
|
game_config=game_config,
|
2047
2059
|
edges=edges,
|
2060
|
+
nodes=kwargs.get('nodes'),
|
2048
2061
|
decks=kwargs.get('decks'),
|
2049
2062
|
piles=kwargs.get('piles'),
|
2050
2063
|
players=kwargs.get('players'),
|
2051
2064
|
player_idxs=kwargs.get('player_idxs'),
|
2052
2065
|
history=kwargs.get('history'),
|
2053
|
-
player_scores=kwargs.get('player_scores'),
|
2054
2066
|
idx2path=idx2path,
|
2055
2067
|
edgeuuid2idx=edgeuuid2idx,
|
2056
2068
|
carduuid2card=carduuid2card,
|
@@ -2062,79 +2074,40 @@ def init_state_kernel(**kwargs):
|
|
2062
2074
|
starting_decks=kwargs.get('starting_decks'),
|
2063
2075
|
starting_piles=kwargs.get('starting_piles'),
|
2064
2076
|
goals=kwargs.get('goals'),
|
2077
|
+
player_graphs_3=player_graphs_3,
|
2065
2078
|
)
|
2066
2079
|
|
2067
2080
|
|
2068
2081
|
class State(PClass):
|
2069
2082
|
kernel = field(type=StateKernel)
|
2070
2083
|
|
2071
|
-
# Identity: these fields should be in the kernel (set once at the start of the game and never changes)
|
2072
|
-
rng = field(type=random.Random)
|
2073
|
-
|
2074
|
-
# Identity: these fields should be in the kernel (can only be changed in "get_initial_state")
|
2075
|
-
player_idxs = field(type=list) # List[int]
|
2076
|
-
|
2077
2084
|
# Identity - these fields should be in the kernel (can only be changed in "get_initial_state" and "get_next_state")
|
2078
2085
|
# The struture should be this: uuid2segment, uuid2edge, uuid2path, uuid2region, uuid2node
|
2079
|
-
history = field(type=list) # List[Action2]
|
2080
|
-
players = field(type=list) # List[Player]
|
2081
|
-
nodes = field(type=list) # List[Node]
|
2082
|
-
edges = field(type=list) # List[BiEdge]
|
2083
|
-
regions = field(type=list) # List[Region]
|
2084
|
-
piles = field(type=list) # List[Pile]
|
2085
|
-
last_to_play = field(type=(int, type(None)), initial=None)
|
2086
|
-
decks = field(type=list) # List[Deck]
|
2087
|
-
|
2088
|
-
# Not sure yet
|
2089
|
-
idx2path = field(type=list) # List[Path2]
|
2090
2086
|
|
2091
2087
|
# Memoized
|
2092
|
-
player_graphs = field(type=list) # List[PlayerGraph]
|
2093
2088
|
legal_actions_3 = field(type=list) # List[LegalAction]
|
2089
|
+
bonus_statuses_3 = field(type=list) # List[BonusStatus]
|
2090
|
+
player_scores_3 = field(type=list) # List[PlayerScore2]
|
2091
|
+
winners = field(type=list) # List[int]
|
2092
|
+
|
2093
|
+
player_graphs = field(type=list) # List[PlayerGraph]
|
2094
2094
|
player_scores = field(type=list) # List[PlayerScore2]
|
2095
2095
|
bonus_statuses = field(type=list) # List[BonusStatus]
|
2096
|
-
winners = field(type=list) # List[int]
|
2097
2096
|
|
2098
2097
|
def __todict__(self):
|
2099
2098
|
return {
|
2100
2099
|
"kernel": self.kernel.__todict__(),
|
2101
|
-
"
|
2102
|
-
"
|
2103
|
-
"history": [x.__todict__() for x in self.history],
|
2104
|
-
"player_scores": [x.__todict__() for x in self.player_scores],
|
2105
|
-
"player_graphs": [x.__todict__() for x in self.player_graphs],
|
2106
|
-
"nodes": [node.__todict__() for node in self.nodes],
|
2107
|
-
"edges": [edge.__todict__() for edge in self.edges],
|
2108
|
-
"regions": [region.__todict__() for region in self.regions],
|
2100
|
+
"bonus_statuses_3": [status.__todict__() for status in self.bonus_statuses_3],
|
2101
|
+
"player_scores_3": [x.__todict__() for x in self.player_scores_3],
|
2109
2102
|
"legal_actions_3": [x.__todict__() for x in self.legal_actions_3],
|
2110
|
-
"piles": [pile.__todict__() for pile in self.piles],
|
2111
|
-
"players": [player.__todict__() for player in self.players],
|
2112
|
-
"player_idxs": self.player_idxs,
|
2113
|
-
"decks": [deck.__todict__() for deck in self.decks],
|
2114
|
-
"rng": rng2json(self.rng),
|
2115
|
-
"last_to_play": self.last_to_play,
|
2116
|
-
"winners": self.winners,
|
2117
2103
|
}
|
2118
2104
|
@staticmethod
|
2119
2105
|
def __fromdict__(d):
|
2120
2106
|
return State(
|
2121
2107
|
kernel=StateKernel.__fromdict__(d["kernel"]),
|
2122
|
-
|
2123
|
-
|
2124
|
-
history=[Action2.__fromdict__(x) for x in d["history"]],
|
2125
|
-
player_scores=[PlayerScore2.__fromdict__(x) for x in d["player_scores"]],
|
2126
|
-
player_graphs=[PlayerGraph.__fromdict__(x) for x in d["player_graphs"]],
|
2127
|
-
nodes=[Node.__fromdict__(n) for n in d["nodes"]],
|
2128
|
-
edges=[BiEdge.__fromdict__(e) for e in d["edges"]],
|
2129
|
-
regions=[Region.__fromdict__(r) for r in d["regions"]],
|
2108
|
+
bonus_statuses_3=[BonusStatus.__fromdict__(x) for x in d["bonus_statuses_3"]],
|
2109
|
+
player_scores_3=[PlayerScore2.__fromdict__(x) for x in d["player_scores_3"]],
|
2130
2110
|
legal_actions_3=[LegalAction.__fromdict__(x) for x in d["legal_actions_3"]],
|
2131
|
-
piles=[Pile.__fromdict__(p) for p in d["piles"]],
|
2132
|
-
players=[Player.__fromdict__(p) for p in d["players"]],
|
2133
|
-
player_idxs=d["player_idxs"],
|
2134
|
-
decks=[Deck.__fromdict__(deck) for deck in d["decks"]],
|
2135
|
-
rng=json2rng(d["rng"]),
|
2136
|
-
last_to_play=d.get("last_to_play"),
|
2137
|
-
winners=d["winners"],
|
2138
2111
|
)
|
2139
2112
|
|
2140
2113
|
|
@@ -2630,12 +2603,6 @@ def getinitialstate(game_config):
|
|
2630
2603
|
nodeuuid2idx = {node.uuid: idx for idx, node in enumerate(board_config.points)}
|
2631
2604
|
edges = get_edges(rng, board_config, nodeuuid2idx)
|
2632
2605
|
|
2633
|
-
idx2path = []
|
2634
|
-
|
2635
|
-
for edge in edges:
|
2636
|
-
for path in edge.paths:
|
2637
|
-
idx2path.append(path)
|
2638
|
-
|
2639
2606
|
bonuses = game_config.fig.board_config.bonuses
|
2640
2607
|
bonus_statuses = [
|
2641
2608
|
BonusStatus(
|
@@ -2652,57 +2619,81 @@ def getinitialstate(game_config):
|
|
2652
2619
|
)
|
2653
2620
|
for bonus in bonuses
|
2654
2621
|
]
|
2655
|
-
|
2656
|
-
starting_decks=[Deck.__fromdict__(x.__todict__()) for x in decks]
|
2657
|
-
starting_piles=[Pile.__fromdict__(x.__todict__()) for x in piles]
|
2658
|
-
|
2659
|
-
state = State(
|
2660
|
-
idx2path=idx2path,
|
2661
|
-
bonus_statuses=bonus_statuses,
|
2662
|
-
history=[],
|
2663
|
-
player_scores=[PlayerScore2(public_items=[], private_items=[]) for _ in range(game_config.num_players)],
|
2664
|
-
player_graphs=[
|
2665
|
-
PlayerGraph(
|
2666
|
-
player_idx=player_idx,
|
2667
|
-
neighbors=[[] for _ in range(len(nodes))]
|
2668
|
-
) for player_idx in range(game_config.num_players)
|
2669
|
-
],
|
2670
|
-
nodes = nodes,
|
2671
|
-
edges = edges,
|
2672
|
-
regions = get_regions(board_config),
|
2673
|
-
legal_actions_3=[],
|
2674
|
-
piles=piles,
|
2675
|
-
players=[Player(idx=idx, pieces=[], cards=[], discard_tray=[]) for idx in range(game_config.num_players)],
|
2676
|
-
player_idxs=list(range(game_config.num_players)),
|
2677
|
-
decks=decks,
|
2678
|
-
rng=rng,
|
2679
|
-
last_to_play=None,
|
2680
|
-
winners=[],
|
2681
|
-
)
|
2682
2622
|
|
2683
|
-
state =
|
2623
|
+
# state = State(
|
2624
|
+
# bonus_statuses=bonus_statuses,
|
2625
|
+
# history=[],
|
2626
|
+
# player_scores=[PlayerScore2(public_items=[], private_items=[]) for _ in range(game_config.num_players)],
|
2627
|
+
# player_graphs=[
|
2628
|
+
# PlayerGraph(
|
2629
|
+
# player_idx=player_idx,
|
2630
|
+
# neighbors=[[] for _ in range(len(nodes))]
|
2631
|
+
# ) for player_idx in range(game_config.num_players)
|
2632
|
+
# ],
|
2633
|
+
# nodes = nodes,
|
2634
|
+
# edges = edges,
|
2635
|
+
# regions = get_regions(board_config),
|
2636
|
+
# legal_actions_3=[],
|
2637
|
+
# piles=piles,
|
2638
|
+
# players=[Player(idx=idx, pieces=[], cards=[], discard_tray=[]) for idx in range(game_config.num_players)],
|
2639
|
+
# player_idxs=list(range(game_config.num_players)),
|
2640
|
+
# decks=decks,
|
2641
|
+
# rng=rng,
|
2642
|
+
# last_to_play=None,
|
2643
|
+
# winners=[],
|
2644
|
+
# )
|
2684
2645
|
|
2685
2646
|
kernel = init_state_kernel(
|
2686
2647
|
rng=rng,
|
2687
2648
|
game_config=game_config,
|
2688
|
-
edges=
|
2689
|
-
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2693
|
-
|
2694
|
-
|
2695
|
-
|
2696
|
-
|
2649
|
+
edges=edges,
|
2650
|
+
nodes=nodes,
|
2651
|
+
decks=decks,
|
2652
|
+
piles=piles,
|
2653
|
+
players=[Player(idx=idx, pieces=[], cards=[], discard_tray=[]) for idx in range(game_config.num_players)],
|
2654
|
+
player_idxs=list(range(game_config.num_players)),
|
2655
|
+
history=[],
|
2656
|
+
player_scores=[PlayerScore2(public_items=[], private_items=[]) for _ in range(game_config.num_players)],
|
2657
|
+
starting_decks=[Deck.__fromdict__(x.__todict__()) for x in decks],
|
2658
|
+
starting_piles=[Pile.__fromdict__(x.__todict__()) for x in piles],
|
2697
2659
|
goals=board_config.goals,
|
2698
2660
|
)
|
2699
2661
|
|
2700
|
-
|
2701
|
-
|
2662
|
+
kernel = run_kernel_hooks(kernel, INITIALIZATION_HOOKS, True)
|
2663
|
+
|
2664
|
+
state = State(
|
2665
|
+
kernel=kernel,
|
2666
|
+
legal_actions_3=calc_legal_actions3(kernel),
|
2667
|
+
bonus_statuses_3=calc_bonus_statuses3(kernel),
|
2668
|
+
)
|
2669
|
+
|
2670
|
+
state = state.set(player_scores_3=calc_player_scores3(state))
|
2671
|
+
state = state.set(winners=calc_winners_3(state))
|
2702
2672
|
|
2703
2673
|
return state
|
2704
2674
|
|
2705
2675
|
|
2676
|
+
@dispatch(StateKernel)
|
2677
|
+
def calc_bonus_statuses3(kernel):
|
2678
|
+
bonus_statuses = [
|
2679
|
+
calc_bonus_status3(kernel, bonus)
|
2680
|
+
for bonus in kernel.game_config.fig.board_config.bonuses
|
2681
|
+
]
|
2682
|
+
bonus_statuses = [bs for bs in bonus_statuses if bs is not None]
|
2683
|
+
return bonus_statuses
|
2684
|
+
|
2685
|
+
|
2686
|
+
@dispatch(State)
|
2687
|
+
def calc_player_scores3(state):
|
2688
|
+
player_scores = [
|
2689
|
+
PlayerScore2(
|
2690
|
+
public_items=score_public_items3(state, player_idx),
|
2691
|
+
private_items=score_private_items3(state.kernel, player_idx),
|
2692
|
+
) for player_idx in range(len(state.kernel.players))
|
2693
|
+
]
|
2694
|
+
return player_scores
|
2695
|
+
|
2696
|
+
|
2706
2697
|
def run_state_hooks(state, hooks, log=False):
|
2707
2698
|
return reduce(
|
2708
2699
|
lambda s, h: run_state_hook(s, h, log),
|
@@ -2711,6 +2702,15 @@ def run_state_hooks(state, hooks, log=False):
|
|
2711
2702
|
)
|
2712
2703
|
|
2713
2704
|
|
2705
|
+
@dispatch(StateKernel, list, bool)
|
2706
|
+
def run_kernel_hooks(kernel, hooks, log=False):
|
2707
|
+
return reduce(
|
2708
|
+
lambda k, h: run_kernel_hook(k, h, log),
|
2709
|
+
hooks,
|
2710
|
+
kernel
|
2711
|
+
)
|
2712
|
+
|
2713
|
+
|
2714
2714
|
def run_accept_action_hooks(state, action, hooks, log=False):
|
2715
2715
|
# Just like "run_state_action_hooks", but returns immediately returns True if any hook returns True, otherwise returns False
|
2716
2716
|
for hook in hooks:
|
@@ -2730,6 +2730,42 @@ def run_state_action_hooks(state, action, hooks, log=False):
|
|
2730
2730
|
)
|
2731
2731
|
|
2732
2732
|
|
2733
|
+
@dispatch(State, int)
|
2734
|
+
def score_public_items3(state, player_idx):
|
2735
|
+
items = []
|
2736
|
+
for edge in state.kernel.edges:
|
2737
|
+
for path in edge.paths:
|
2738
|
+
if len(path.segments) > 0:
|
2739
|
+
first_segment = path.segments[0]
|
2740
|
+
if first_segment.pieces and len(first_segment.pieces) > 0:
|
2741
|
+
first_piece = state.kernel.pieceuuid2piece[first_segment.pieces[0]]
|
2742
|
+
if first_piece.player_idx == player_idx:
|
2743
|
+
items.append(
|
2744
|
+
ScoreItem2(
|
2745
|
+
amount=edge.score,
|
2746
|
+
owns_path=ScoreItemOwnsPath(
|
2747
|
+
path_idx=path.idx,
|
2748
|
+
edge_uuid=edge.uuid,
|
2749
|
+
length=len(path.segments),
|
2750
|
+
),
|
2751
|
+
description="Player {} owns edge {}".format(player_idx, edge.uuid),
|
2752
|
+
)
|
2753
|
+
)
|
2754
|
+
for bonus_status in state.bonus_statuses_3:
|
2755
|
+
bonus_idx = state.kernel.bonusuuid2bonusidx.get(bonus_status.bonus_uuid)
|
2756
|
+
bonus = state.kernel.game_config.fig.board_config.bonuses[bonus_idx] if bonus_idx is not None else None
|
2757
|
+
if bonus:
|
2758
|
+
if player_idx in bonus_status.winners:
|
2759
|
+
items.append(
|
2760
|
+
ScoreItem2(
|
2761
|
+
amount=bonus.score,
|
2762
|
+
description="Player {} wins bonus {}".format(player_idx, bonus.code),
|
2763
|
+
bonus=ScoreItemBonus(bonus_uuid=bonus.uuid),
|
2764
|
+
)
|
2765
|
+
)
|
2766
|
+
return items
|
2767
|
+
|
2768
|
+
|
2733
2769
|
@dispatch(State, int)
|
2734
2770
|
def score_public_items(state, player_idx):
|
2735
2771
|
items = []
|
@@ -2794,6 +2830,34 @@ def score_private_items(state, player_idx):
|
|
2794
2830
|
return items
|
2795
2831
|
|
2796
2832
|
|
2833
|
+
@dispatch(StateKernel, int)
|
2834
|
+
def score_private_items3(kernel, player_idx):
|
2835
|
+
items = []
|
2836
|
+
goaluuid2goal = {goal.uuid: goal for goal in kernel.goals}
|
2837
|
+
goal_completions = get_goal_completions3(kernel, player_idx)
|
2838
|
+
complete_goal_uuids = [gc.goal_uuid for gc in goal_completions if gc.complete]
|
2839
|
+
incomplete_goal_uuids = [gc.goal_uuid for gc in goal_completions if not gc.complete]
|
2840
|
+
for complete_goal_uuid in complete_goal_uuids:
|
2841
|
+
goal = goaluuid2goal[complete_goal_uuid]
|
2842
|
+
items.append(
|
2843
|
+
ScoreItem2(
|
2844
|
+
amount=goal.score,
|
2845
|
+
description="Player {} completed goal {}".format(player_idx, complete_goal_uuid),
|
2846
|
+
goal=ScoreItemGoal(goal_uuid=complete_goal_uuid, complete=True)
|
2847
|
+
)
|
2848
|
+
)
|
2849
|
+
for incomplete_goal_uuid in incomplete_goal_uuids:
|
2850
|
+
goal = goaluuid2goal[incomplete_goal_uuid]
|
2851
|
+
items.append(
|
2852
|
+
ScoreItem2(
|
2853
|
+
amount=(-1*goal.score),
|
2854
|
+
description="Player {} incomplete goal {}".format(player_idx, incomplete_goal_uuid),
|
2855
|
+
goal=ScoreItemGoal(goal_uuid=incomplete_goal_uuid, complete=False)
|
2856
|
+
)
|
2857
|
+
)
|
2858
|
+
return items
|
2859
|
+
|
2860
|
+
|
2797
2861
|
def handle_last_to_play(game):
|
2798
2862
|
if game.last_to_play is None:
|
2799
2863
|
# If any player can less than 3 pieces, the game is terminal
|
@@ -2813,6 +2877,14 @@ def getfinalscores(game):
|
|
2813
2877
|
]
|
2814
2878
|
|
2815
2879
|
|
2880
|
+
@dispatch(State)
|
2881
|
+
def getfinalscores3(state):
|
2882
|
+
return [
|
2883
|
+
getpublicplayerscore(state, state.player_scores_3[player_idx]).total
|
2884
|
+
for player_idx in range(len(state.kernel.players))
|
2885
|
+
]
|
2886
|
+
|
2887
|
+
|
2816
2888
|
def handle_calc_winners(game):
|
2817
2889
|
if isterminal(game):
|
2818
2890
|
players_with_highest_score = []
|
@@ -2832,6 +2904,24 @@ def handle_calc_winners(game):
|
|
2832
2904
|
return game
|
2833
2905
|
|
2834
2906
|
|
2907
|
+
@dispatch(State)
|
2908
|
+
def calc_winners_3(state):
|
2909
|
+
if isterminal(state):
|
2910
|
+
players_with_highest_score = []
|
2911
|
+
highest_score = -1000
|
2912
|
+
final_scores = getfinalscores3(state)
|
2913
|
+
for player_idx in range(len(state.kernel.players)):
|
2914
|
+
final_score = final_scores[player_idx]
|
2915
|
+
if final_score > highest_score:
|
2916
|
+
highest_score = final_score
|
2917
|
+
players_with_highest_score = [player_idx]
|
2918
|
+
elif final_score == highest_score:
|
2919
|
+
players_with_highest_score.append(player_idx)
|
2920
|
+
return players_with_highest_score
|
2921
|
+
|
2922
|
+
return []
|
2923
|
+
|
2924
|
+
|
2835
2925
|
def default_handle_terminal(game):
|
2836
2926
|
game = handle_last_to_play(game)
|
2837
2927
|
game = handle_calc_winners(game)
|
@@ -2846,6 +2936,48 @@ def calc_bonus_status(game, bonus):
|
|
2846
2936
|
return None
|
2847
2937
|
|
2848
2938
|
|
2939
|
+
@dispatch(StateKernel, FrozenBonus)
|
2940
|
+
def calc_bonus_status3(kernel, bonus):
|
2941
|
+
if not bonus:
|
2942
|
+
return None
|
2943
|
+
if bonus.code == "longest-trail":
|
2944
|
+
return get_bonus_status_longest_trail3(kernel, bonus)
|
2945
|
+
return None
|
2946
|
+
|
2947
|
+
|
2948
|
+
@dispatch(StateKernel, FrozenBonus)
|
2949
|
+
def get_bonus_status_longest_trail3(kernel, bonus):
|
2950
|
+
longest_trail = 0
|
2951
|
+
winners = []
|
2952
|
+
player_longest_trail_lens = []
|
2953
|
+
|
2954
|
+
for player_idx in range(kernel.game_config.num_players):
|
2955
|
+
trail_length = get_longest_path_length3(kernel, player_idx)
|
2956
|
+
player_longest_trail_lens.append(trail_length)
|
2957
|
+
if trail_length > longest_trail:
|
2958
|
+
longest_trail = trail_length
|
2959
|
+
winners = [player_idx]
|
2960
|
+
elif trail_length == longest_trail and trail_length > 0:
|
2961
|
+
winners.append(player_idx)
|
2962
|
+
|
2963
|
+
player_statuses = [
|
2964
|
+
BonusPlayerStatus(
|
2965
|
+
player_idx=player_idx,
|
2966
|
+
score=bonus.score if player_idx in winners else 0,
|
2967
|
+
longest_trail=LongestTrailBonusPlayerStatus(
|
2968
|
+
length=player_longest_trail_len
|
2969
|
+
),
|
2970
|
+
)
|
2971
|
+
for player_idx, player_longest_trail_len in enumerate(player_longest_trail_lens)
|
2972
|
+
]
|
2973
|
+
|
2974
|
+
return BonusStatus(
|
2975
|
+
bonus_uuid=bonus.uuid,
|
2976
|
+
winners=winners,
|
2977
|
+
player_statuses=player_statuses,
|
2978
|
+
)
|
2979
|
+
|
2980
|
+
|
2849
2981
|
def get_bonus_status_longest_trail(state, bonus):
|
2850
2982
|
longest_trail = 0
|
2851
2983
|
winners = []
|
@@ -2899,137 +3031,142 @@ def default_handle_scoring(game):
|
|
2899
3031
|
return game.set(player_scores=player_scores)
|
2900
3032
|
|
2901
3033
|
|
2902
|
-
|
3034
|
+
@dispatch(StateKernel, Action2)
|
3035
|
+
def default_handle_action(kernel, action):
|
2903
3036
|
if action.legal_action.discard:
|
2904
|
-
return handle_discard_action(
|
3037
|
+
return handle_discard_action(kernel, action)
|
2905
3038
|
if action.legal_action.keep:
|
2906
|
-
return handle_keep_action(
|
3039
|
+
return handle_keep_action(kernel, action)
|
2907
3040
|
if action.legal_action.move_pieces_to_path:
|
2908
|
-
|
2909
|
-
return handle_after_move_pieces_to_path_action(
|
3041
|
+
kernel = handle_move_pieces_to_path_action(kernel, action)
|
3042
|
+
return handle_after_move_pieces_to_path_action(kernel, action)
|
2910
3043
|
if action.legal_action.faceup_draw:
|
2911
|
-
return handle_faceup_draw_action(
|
3044
|
+
return handle_faceup_draw_action(kernel, action)
|
2912
3045
|
if action.legal_action.draw:
|
2913
|
-
return handle_draw_action(
|
3046
|
+
return handle_draw_action(kernel, action)
|
2914
3047
|
if action.legal_action.draw_discard:
|
2915
|
-
return handle_draw_discard_action(
|
3048
|
+
return handle_draw_discard_action(kernel, action)
|
2916
3049
|
|
2917
|
-
return
|
3050
|
+
return kernel
|
2918
3051
|
|
2919
3052
|
|
2920
|
-
|
3053
|
+
@dispatch(StateKernel, Action2)
|
3054
|
+
def default_after_accept_action(kernel, action):
|
2921
3055
|
# Remove all actions for matching player of action
|
2922
|
-
if not
|
2923
|
-
return
|
3056
|
+
if not kernel or not action or not action.legal_action:
|
3057
|
+
return kernel
|
2924
3058
|
player_idx = action.legal_action.player_idx
|
2925
|
-
if player_idx < 0 or player_idx >= len(
|
2926
|
-
return
|
2927
|
-
|
2928
|
-
|
2929
|
-
]
|
2930
|
-
history = game.history + [action]
|
2931
|
-
return game.set(
|
2932
|
-
legal_actions_3=new_legal_actions,
|
3059
|
+
if player_idx < 0 or player_idx >= len(kernel.players):
|
3060
|
+
return kernel
|
3061
|
+
history = kernel.history + [action]
|
3062
|
+
return kernel.set(
|
2933
3063
|
history=history,
|
2934
3064
|
)
|
2935
3065
|
|
2936
3066
|
|
2937
|
-
|
2938
|
-
|
3067
|
+
@dispatch(StateKernel)
|
3068
|
+
def recycle_decks_if_needed(kernel):
|
3069
|
+
for deck_idx in range(len(kernel.decks)):
|
2939
3070
|
print("recycle_decks_if_needed for deck_idx =", deck_idx)
|
2940
|
-
|
2941
|
-
return
|
3071
|
+
kernel = recycle_if_needed(kernel, deck_idx)
|
3072
|
+
return kernel
|
2942
3073
|
|
2943
3074
|
|
2944
|
-
|
2945
|
-
|
2946
|
-
|
2947
|
-
|
3075
|
+
@dispatch(StateKernel)
|
3076
|
+
def replenish_decks_if_needed(kernel):
|
3077
|
+
for deck_idx in range(len(kernel.decks)):
|
3078
|
+
kernel = replenish_faceup_if_needed(kernel, deck_idx)
|
3079
|
+
return kernel
|
2948
3080
|
|
2949
3081
|
|
2950
|
-
|
2951
|
-
|
3082
|
+
@dispatch(StateKernel, int, int)
|
3083
|
+
def replenish_faceup_spot_if_needed(kernel, deck_idx, spot_idx):
|
3084
|
+
deck = kernel.decks[deck_idx]
|
2952
3085
|
|
2953
3086
|
if deck.faceup_spots[spot_idx] is not None:
|
2954
|
-
return
|
3087
|
+
return kernel
|
2955
3088
|
|
2956
3089
|
if len(deck.facedown_stack) == 0:
|
2957
|
-
return
|
3090
|
+
return kernel
|
2958
3091
|
|
2959
3092
|
deck.faceup_spots[spot_idx] = deck.facedown_stack.pop()
|
2960
3093
|
|
2961
|
-
|
3094
|
+
kernel = ensure_faceup_spots_valid(kernel)
|
2962
3095
|
|
2963
|
-
return
|
2964
|
-
decks=
|
3096
|
+
return kernel.set(
|
3097
|
+
decks=kernel.decks,
|
2965
3098
|
)
|
2966
3099
|
|
2967
3100
|
|
2968
|
-
|
2969
|
-
|
3101
|
+
@dispatch(StateKernel, int)
|
3102
|
+
def replenish_faceup_if_needed(kernel, deck_idx):
|
3103
|
+
deck = kernel.decks[deck_idx]
|
2970
3104
|
for spot_idx in range(len(deck.faceup_spots)):
|
2971
|
-
|
2972
|
-
return
|
3105
|
+
kernel = replenish_faceup_spot_if_needed(kernel, deck_idx, spot_idx)
|
3106
|
+
return kernel
|
2973
3107
|
|
2974
3108
|
|
2975
|
-
|
2976
|
-
|
3109
|
+
@dispatch(StateKernel, int)
|
3110
|
+
def recycle_if_needed(kernel, deck_idx):
|
3111
|
+
deck = kernel.decks[deck_idx]
|
2977
3112
|
if len(deck.facedown_stack) == 0:
|
2978
3113
|
shuffled_discards = list(deck.discard)
|
2979
|
-
|
3114
|
+
kernel.rng.shuffle(shuffled_discards)
|
2980
3115
|
deck = deck.set(
|
2981
3116
|
facedown_stack = shuffled_discards,
|
2982
3117
|
discard = []
|
2983
3118
|
)
|
2984
|
-
|
2985
|
-
return
|
3119
|
+
kernel = set_deck(kernel, deck.idx, deck)
|
3120
|
+
return kernel
|
2986
3121
|
|
2987
3122
|
|
2988
|
-
|
2989
|
-
|
2990
|
-
|
3123
|
+
@dispatch(StateKernel, Action2)
|
3124
|
+
def handle_draw_action(kernel, action):
|
3125
|
+
if not kernel or not action or not action.legal_action or not action.legal_action.draw:
|
3126
|
+
return kernel
|
2991
3127
|
legal_action = action.legal_action
|
2992
3128
|
draw = legal_action.draw
|
2993
|
-
player =
|
2994
|
-
deck =
|
3129
|
+
player = kernel.players[legal_action.player_idx]
|
3130
|
+
deck = kernel.decks[draw.deck_idx]
|
2995
3131
|
|
2996
3132
|
if len(deck.facedown_stack) == 0:
|
2997
|
-
return
|
3133
|
+
return kernel # No cards to draw
|
2998
3134
|
|
2999
3135
|
for _ in range(draw.quantity):
|
3000
3136
|
drawn_card = deck.facedown_stack.pop()
|
3001
3137
|
player.cards.append(drawn_card)
|
3002
|
-
|
3138
|
+
kernel = recycle_if_needed(kernel, draw.deck_idx)
|
3003
3139
|
|
3004
|
-
|
3005
|
-
players=
|
3140
|
+
kernel = kernel.set(
|
3141
|
+
players=kernel.players,
|
3006
3142
|
)
|
3007
3143
|
|
3008
3144
|
# TODO: extract this out to user-defined function/hook
|
3009
3145
|
# if draw.quantity == 1:
|
3010
3146
|
# game = append_follow_up_draw_legal_actions(game, action)
|
3011
3147
|
|
3012
|
-
return
|
3148
|
+
return kernel
|
3013
3149
|
|
3014
3150
|
|
3015
|
-
|
3016
|
-
|
3017
|
-
|
3151
|
+
@dispatch(StateKernel, Action2)
|
3152
|
+
def handle_draw_discard_action(kernel, action):
|
3153
|
+
if not kernel or not action or not action.legal_action or not action.legal_action.draw_discard:
|
3154
|
+
return kernel
|
3018
3155
|
legal_action = action.legal_action
|
3019
3156
|
draw_discard = legal_action.draw_discard
|
3020
|
-
player =
|
3021
|
-
deck =
|
3157
|
+
player = kernel.players[legal_action.player_idx]
|
3158
|
+
deck = kernel.decks[draw_discard.deck_idx]
|
3022
3159
|
|
3023
3160
|
if len(deck.facedown_stack) == 0:
|
3024
|
-
return
|
3161
|
+
return kernel # No cards to draw
|
3025
3162
|
|
3026
3163
|
for _ in range(draw_discard.quantity):
|
3027
3164
|
drawn_card = deck.facedown_stack.pop()
|
3028
3165
|
player.discard_tray.append(drawn_card)
|
3029
3166
|
|
3030
|
-
return
|
3031
|
-
players=
|
3032
|
-
decks=
|
3167
|
+
return kernel.set(
|
3168
|
+
players=kernel.players,
|
3169
|
+
decks=kernel.decks,
|
3033
3170
|
)
|
3034
3171
|
|
3035
3172
|
|
@@ -3076,26 +3213,29 @@ def get_follow_up_draw_legal_actions(game, action):
|
|
3076
3213
|
return to_return
|
3077
3214
|
|
3078
3215
|
|
3079
|
-
|
3080
|
-
|
3216
|
+
@dispatch(StateKernel, int)
|
3217
|
+
def get_num_faceup_wilds(kernel, deck_idx):
|
3218
|
+
deck = kernel.decks[deck_idx]
|
3081
3219
|
non_empty_spots = [spot for spot in deck.faceup_spots if spot]
|
3082
3220
|
if not non_empty_spots:
|
3083
3221
|
return 0
|
3084
|
-
return sum(1 for card_uuid in non_empty_spots if
|
3222
|
+
return sum(1 for card_uuid in non_empty_spots if kernel.carduuid2card[card_uuid].is_wild)
|
3085
3223
|
|
3086
3224
|
|
3087
|
-
|
3088
|
-
|
3225
|
+
@dispatch(StateKernel)
|
3226
|
+
def ensure_faceup_spots_valid(kernel):
|
3227
|
+
for deck in kernel.decks:
|
3089
3228
|
max_iters = 5
|
3090
3229
|
i = 0
|
3091
|
-
while i < max_iters and get_num_faceup_wilds(
|
3092
|
-
|
3230
|
+
while i < max_iters and get_num_faceup_wilds(kernel, deck.idx) >= 3:
|
3231
|
+
kernel = discardfaceup_shuffle_flip(kernel, deck.idx)
|
3093
3232
|
i += 1
|
3094
|
-
return
|
3233
|
+
return kernel
|
3095
3234
|
|
3096
3235
|
|
3097
|
-
|
3098
|
-
|
3236
|
+
@dispatch(StateKernel, int)
|
3237
|
+
def discardfaceup_shuffle_flip(kernel, deck_idx):
|
3238
|
+
deck = kernel.decks[deck_idx]
|
3099
3239
|
num_faceup_spots = len(deck.faceup_spots)
|
3100
3240
|
for faceup_spot in deck.faceup_spots:
|
3101
3241
|
if faceup_spot:
|
@@ -3104,45 +3244,48 @@ def discardfaceup_shuffle_flip(game, deck_idx):
|
|
3104
3244
|
while len(deck.discard) > 0:
|
3105
3245
|
card = deck.discard.pop()
|
3106
3246
|
deck.facedown_stack.append(card)
|
3107
|
-
deck = shuffle(
|
3108
|
-
|
3109
|
-
|
3110
|
-
return
|
3247
|
+
deck = shuffle(kernel.rng, deck)
|
3248
|
+
kernel = set_deck(kernel, deck.idx, deck)
|
3249
|
+
kernel = flip_cards(kernel, deck.idx, num_faceup_spots)
|
3250
|
+
return kernel
|
3111
3251
|
|
3112
3252
|
|
3113
|
-
|
3114
|
-
|
3115
|
-
|
3253
|
+
@dispatch(StateKernel, Action2)
|
3254
|
+
def handle_faceup_draw_action(kernel, action):
|
3255
|
+
if not kernel or not action or not action.legal_action or not action.legal_action.faceup_draw:
|
3256
|
+
return kernel
|
3116
3257
|
legal_action = action.legal_action
|
3117
3258
|
faceup_draw = legal_action.faceup_draw
|
3118
|
-
player =
|
3119
|
-
deck =
|
3259
|
+
player = kernel.players[legal_action.player_idx]
|
3260
|
+
deck = kernel.decks[faceup_draw.deck_idx]
|
3120
3261
|
# find the faceup spot idx with uuid "faceup_draw.card_uuid"
|
3121
3262
|
spot_idx = next((i for i, card_uuid in enumerate(deck.faceup_spots) if card_uuid == faceup_draw.card_uuid), None)
|
3122
3263
|
drawn_card = deck.faceup_spots[spot_idx] if spot_idx is not None else None
|
3123
3264
|
player.cards.append(drawn_card)
|
3124
3265
|
|
3125
3266
|
deck.faceup_spots[spot_idx] = None
|
3126
|
-
|
3127
|
-
|
3267
|
+
kernel = kernel.set(decks=kernel.decks)
|
3268
|
+
kernel = replenish_faceup_spot_if_needed(kernel, faceup_draw.deck_idx, spot_idx)
|
3128
3269
|
|
3129
3270
|
# Prevent an extra draw if last draw was a face-wild-draw
|
3130
3271
|
# if not game.kernel.carduuid2card[drawn_card].is_wild:
|
3131
3272
|
# # TODO: extract this out to user-defined function/hook
|
3132
3273
|
# game = append_follow_up_draw_legal_actions(game, action)
|
3133
3274
|
|
3134
|
-
return
|
3135
|
-
players=
|
3275
|
+
return kernel.set(
|
3276
|
+
players=kernel.players,
|
3136
3277
|
)
|
3137
3278
|
|
3138
3279
|
|
3139
|
-
|
3140
|
-
|
3141
|
-
|
3280
|
+
@dispatch(StateKernel, Action2)
|
3281
|
+
def handle_after_move_pieces_to_path_action(kernel, action):
|
3282
|
+
kernel = handle_move_bonus_cards(kernel, action)
|
3283
|
+
return kernel
|
3142
3284
|
|
3143
3285
|
|
3144
|
-
|
3145
|
-
|
3286
|
+
@dispatch(StateKernel, Action2)
|
3287
|
+
def handle_move_bonus_cards(kernel, action):
|
3288
|
+
return handle_move_longest_path_card(kernel, action)
|
3146
3289
|
|
3147
3290
|
|
3148
3291
|
# Take a random walk on the player's graph. A node can be visiting more than once, but an edge cannot be visited more than once.
|
@@ -3186,12 +3329,53 @@ def random_player_graph_walk(game, player_idx):
|
|
3186
3329
|
return walk([random_start_node_idx], set([]))
|
3187
3330
|
|
3188
3331
|
|
3189
|
-
|
3332
|
+
@dispatch(StateKernel, int)
|
3333
|
+
def random_player_graph_walk3(kernel, player_idx):
|
3334
|
+
player_graph = kernel.player_graphs_3[player_idx]
|
3335
|
+
nodes_indices_with_neighbors = [i for i, neighbors in enumerate(player_graph.neighbors) if neighbors]
|
3336
|
+
|
3337
|
+
if not nodes_indices_with_neighbors:
|
3338
|
+
return None
|
3339
|
+
|
3340
|
+
rng = random.Random()
|
3341
|
+
random_start_node_idx = rng.choice(nodes_indices_with_neighbors)
|
3342
|
+
|
3343
|
+
def choose_next_node(visited_nodes, visited_edges):
|
3344
|
+
current_node_idx = visited_nodes[-1]
|
3345
|
+
neighbors = player_graph.neighbors[current_node_idx]
|
3346
|
+
if not neighbors:
|
3347
|
+
return None
|
3348
|
+
|
3349
|
+
shuffled_neighbors = neighbors.copy()
|
3350
|
+
rng.shuffle(shuffled_neighbors)
|
3351
|
+
|
3352
|
+
for neighbor in shuffled_neighbors:
|
3353
|
+
edge = (min(current_node_idx, neighbor), max(current_node_idx, neighbor))
|
3354
|
+
if edge not in visited_edges:
|
3355
|
+
return neighbor
|
3356
|
+
|
3357
|
+
return None
|
3358
|
+
|
3359
|
+
def walk(visited_nodes, visited_edges):
|
3360
|
+
next_node = choose_next_node(visited_nodes, visited_edges)
|
3361
|
+
if next_node is None:
|
3362
|
+
return (visited_nodes, visited_edges)
|
3363
|
+
next_edge = (min(visited_nodes[-1], next_node), max(visited_nodes[-1], next_node))
|
3364
|
+
return walk(
|
3365
|
+
visited_nodes + [next_node],
|
3366
|
+
set(list(visited_edges) + [next_edge])
|
3367
|
+
)
|
3368
|
+
|
3369
|
+
return walk([random_start_node_idx], set([]))
|
3370
|
+
|
3371
|
+
|
3372
|
+
@dispatch(StateKernel)
|
3373
|
+
def find_player_with_longest_path(kernel):
|
3190
3374
|
longest_path_player_idx = None
|
3191
3375
|
longest_path_length = 0
|
3192
3376
|
|
3193
|
-
for player_idx in range(
|
3194
|
-
path_length = get_longest_path_length(
|
3377
|
+
for player_idx in range(kernel.game_config.num_players):
|
3378
|
+
path_length = get_longest_path_length(kernel, player_idx)
|
3195
3379
|
if path_length > longest_path_length:
|
3196
3380
|
longest_path_length = path_length
|
3197
3381
|
longest_path_player_idx = player_idx
|
@@ -3199,7 +3383,7 @@ def find_player_with_longest_path(state):
|
|
3199
3383
|
if longest_path_player_idx is None:
|
3200
3384
|
return None
|
3201
3385
|
|
3202
|
-
return
|
3386
|
+
return kernel.players[longest_path_player_idx]
|
3203
3387
|
|
3204
3388
|
|
3205
3389
|
@dispatch(State, set)
|
@@ -3220,15 +3404,34 @@ def calc_path_len_from_edges(state, edge_tuples):
|
|
3220
3404
|
return sum(edge_lens)
|
3221
3405
|
|
3222
3406
|
|
3223
|
-
|
3407
|
+
@dispatch(StateKernel, set)
|
3408
|
+
def calc_path_len_from_edges3(kernel, edge_tuples):
|
3409
|
+
if edge_tuples is None:
|
3410
|
+
return 0
|
3411
|
+
edge_lens = []
|
3412
|
+
for edge_tuple in edge_tuples:
|
3413
|
+
edge_uuid = kernel.edgetuple2uuid.get(edge_tuple)
|
3414
|
+
edge_idx = kernel.edgeuuid2idx.get(edge_uuid)
|
3415
|
+
if edge_idx is not None:
|
3416
|
+
edge = kernel.edges[edge_idx]
|
3417
|
+
if edge and edge.paths:
|
3418
|
+
first_path = edge.paths[0]
|
3419
|
+
edge_len = len(first_path.segments)
|
3420
|
+
edge_lens.append(edge_len)
|
3421
|
+
|
3422
|
+
return sum(edge_lens)
|
3423
|
+
|
3424
|
+
|
3425
|
+
@dispatch(StateKernel, int)
|
3426
|
+
def get_longest_path_length3(kernel, player_idx):
|
3224
3427
|
longest_path_length = 0
|
3225
3428
|
num_iters_since_change = 0
|
3226
3429
|
|
3227
3430
|
for _ in range(1000):
|
3228
|
-
walk =
|
3431
|
+
walk = random_player_graph_walk3(kernel, player_idx)
|
3229
3432
|
if not walk:
|
3230
3433
|
return 0
|
3231
|
-
path_len =
|
3434
|
+
path_len = calc_path_len_from_edges3(kernel, walk[1])
|
3232
3435
|
if path_len > longest_path_length:
|
3233
3436
|
longest_path_length = path_len
|
3234
3437
|
num_iters_since_change = 0
|
@@ -3242,25 +3445,49 @@ def get_longest_path_length(game, player_idx):
|
|
3242
3445
|
return longest_path_length
|
3243
3446
|
|
3244
3447
|
|
3245
|
-
|
3246
|
-
|
3448
|
+
@dispatch(StateKernel, int)
|
3449
|
+
def get_longest_path_length(kernel, player_idx):
|
3450
|
+
longest_path_length = 0
|
3451
|
+
num_iters_since_change = 0
|
3452
|
+
|
3453
|
+
for _ in range(1000):
|
3454
|
+
walk = random_player_graph_walk(kernel, player_idx)
|
3455
|
+
if not walk:
|
3456
|
+
return 0
|
3457
|
+
path_len = calc_path_len_from_edges(kernel, walk[1])
|
3458
|
+
if path_len > longest_path_length:
|
3459
|
+
longest_path_length = path_len
|
3460
|
+
num_iters_since_change = 0
|
3461
|
+
else:
|
3462
|
+
num_iters_since_change += 1
|
3463
|
+
# If we haven't found a longer path in 500 iterations, return
|
3464
|
+
if num_iters_since_change > 500:
|
3465
|
+
return longest_path_length
|
3466
|
+
|
3467
|
+
print("longest_path_length: ", longest_path_length)
|
3468
|
+
return longest_path_length
|
3247
3469
|
|
3248
|
-
|
3249
|
-
|
3470
|
+
|
3471
|
+
@dispatch(StateKernel, Action2)
|
3472
|
+
def handle_move_longest_path_card(kernel, action):
|
3473
|
+
player = find_player_with_longest_path(kernel)
|
3474
|
+
|
3475
|
+
if not kernel or not player:
|
3476
|
+
return kernel
|
3250
3477
|
|
3251
3478
|
longest_path_card = None
|
3252
3479
|
|
3253
|
-
if len(
|
3254
|
-
longest_path_deck =
|
3480
|
+
if len(kernel.decks) > 2:
|
3481
|
+
longest_path_deck = kernel.decks[2]
|
3255
3482
|
if longest_path_deck.facedown_stack:
|
3256
3483
|
# Move the longest path card to the player's hand
|
3257
3484
|
longest_path_card = longest_path_deck.facedown_stack.pop()
|
3258
3485
|
else:
|
3259
3486
|
# Search for the longest path card in each player's cards
|
3260
|
-
player_with_card = find_player_with_longest_path_card(
|
3487
|
+
player_with_card = find_player_with_longest_path_card(kernel)
|
3261
3488
|
if player_with_card:
|
3262
3489
|
# Find the index of the card from the player's cards, then pop it
|
3263
|
-
card_idx = next((i for i, card_uuid in enumerate(player_with_card.cards) if
|
3490
|
+
card_idx = next((i for i, card_uuid in enumerate(player_with_card.cards) if kernel.carduuid2card[card_uuid].deck_idx == 2), None)
|
3264
3491
|
if card_idx is not None:
|
3265
3492
|
longest_path_card = player_with_card.cards.pop(card_idx)
|
3266
3493
|
|
@@ -3268,9 +3495,9 @@ def handle_move_longest_path_card(game, action):
|
|
3268
3495
|
if longest_path_card:
|
3269
3496
|
player.cards.append(longest_path_card)
|
3270
3497
|
|
3271
|
-
return
|
3272
|
-
players=
|
3273
|
-
decks=
|
3498
|
+
return kernel.set(
|
3499
|
+
players=kernel.players,
|
3500
|
+
decks=kernel.decks,
|
3274
3501
|
)
|
3275
3502
|
|
3276
3503
|
|
@@ -3281,9 +3508,10 @@ def find_player_with_longest_path_card(game):
|
|
3281
3508
|
return None
|
3282
3509
|
|
3283
3510
|
|
3284
|
-
|
3285
|
-
|
3286
|
-
|
3511
|
+
@dispatch(StateKernel, Action2)
|
3512
|
+
def handle_move_pieces_to_path_action(kernel, action):
|
3513
|
+
if not kernel or not action or not action.legal_action or not action.legal_action.move_pieces_to_path:
|
3514
|
+
return kernel
|
3287
3515
|
|
3288
3516
|
legal_action = action.legal_action
|
3289
3517
|
move_pieces_to_path = legal_action.move_pieces_to_path
|
@@ -3293,15 +3521,15 @@ def handle_move_pieces_to_path_action(game, action):
|
|
3293
3521
|
default = default.set(piece_uuids=override.piece_uuids)
|
3294
3522
|
default = default.set(card_uuids=override.card_uuids)
|
3295
3523
|
|
3296
|
-
player =
|
3524
|
+
player = kernel.players[legal_action.player_idx]
|
3297
3525
|
if not player or not player.pieces:
|
3298
|
-
return
|
3526
|
+
return kernel
|
3299
3527
|
|
3300
3528
|
path_idx = move_pieces_to_path.path_idx
|
3301
|
-
path =
|
3529
|
+
path = kernel.idx2path[path_idx]
|
3302
3530
|
|
3303
3531
|
if path is None or not path.segments:
|
3304
|
-
return
|
3532
|
+
return kernel
|
3305
3533
|
|
3306
3534
|
for piece_uuid, segment in zip(default.piece_uuids, path.segments):
|
3307
3535
|
# Find the piece in the player's pieces
|
@@ -3318,15 +3546,14 @@ def handle_move_pieces_to_path_action(game, action):
|
|
3318
3546
|
# Remove the card from player's cards
|
3319
3547
|
card_uuid = player.cards.pop(card_idx)
|
3320
3548
|
# add to discard
|
3321
|
-
|
3549
|
+
kernel.decks[kernel.carduuid2card[card_uuid].deck_idx].discard.append(card_uuid)
|
3322
3550
|
|
3323
|
-
|
3324
|
-
|
3325
|
-
|
3326
|
-
|
3327
|
-
game = game.set(player_graphs=calc_player_graphs(game)) #
|
3551
|
+
kernel = recycle_decks_if_needed(kernel)
|
3552
|
+
kernel = replenish_decks_if_needed(kernel)
|
3553
|
+
kernel = kernel.set(players=kernel.players)
|
3554
|
+
kernel = kernel.set(idx2path=kernel.idx2path)
|
3328
3555
|
|
3329
|
-
return
|
3556
|
+
return kernel
|
3330
3557
|
|
3331
3558
|
|
3332
3559
|
@dispatch(State, int)
|
@@ -3351,6 +3578,27 @@ def calc_player_graph(state, player_idx):
|
|
3351
3578
|
)
|
3352
3579
|
|
3353
3580
|
|
3581
|
+
@dispatch(list, list, dict, int)
|
3582
|
+
def calc_player_graph3(nodes, edges, pieceuuid2piece, player_idx):
|
3583
|
+
node2neighbors = {node.idx: set() for node in nodes}
|
3584
|
+
|
3585
|
+
for edge in edges:
|
3586
|
+
for path in edge.paths:
|
3587
|
+
for segment in path.segments:
|
3588
|
+
if segment.pieces and segment.pieces[0] and pieceuuid2piece[segment.pieces[0]].player_idx == player_idx:
|
3589
|
+
# print(f"[path_idx {path.idx}] edge.start_point_uuid {edge.start_point_uuid} ({edge.node_1_idx}) connected to edge.end_point_uuid {edge.end_point_uuid} ({edge.node_2_idx}) player_idx: {player_idx}")
|
3590
|
+
node2neighbors[edge.node_1_idx].add(edge.node_2_idx)
|
3591
|
+
node2neighbors[edge.node_2_idx].add(edge.node_1_idx)
|
3592
|
+
|
3593
|
+
return PlayerGraph(
|
3594
|
+
player_idx=player_idx,
|
3595
|
+
neighbors=[
|
3596
|
+
list(node2neighbors.get(node_idx, set()))
|
3597
|
+
for node_idx in range(len(nodes))
|
3598
|
+
]
|
3599
|
+
)
|
3600
|
+
|
3601
|
+
|
3354
3602
|
def calc_player_graphs(state):
|
3355
3603
|
game_config = state.kernel.game_config
|
3356
3604
|
return [
|
@@ -3359,22 +3607,31 @@ def calc_player_graphs(state):
|
|
3359
3607
|
]
|
3360
3608
|
|
3361
3609
|
|
3610
|
+
@dispatch(list, list, dict, GameConfig)
|
3611
|
+
def calc_player_graphs3(nodes, edges, pieceuuid2piece, game_config):
|
3612
|
+
return [
|
3613
|
+
calc_player_graph3(nodes, edges, pieceuuid2piece, player_idx)
|
3614
|
+
for player_idx in range(game_config.num_players)
|
3615
|
+
]
|
3616
|
+
|
3617
|
+
|
3362
3618
|
# Does the opposite of handle_discard_action, i.e., it keeps the cards in the discard tray (the other cards are discarded)
|
3363
|
-
|
3364
|
-
|
3365
|
-
|
3619
|
+
@dispatch(StateKernel, Action2)
|
3620
|
+
def handle_keep_action(kernel, action):
|
3621
|
+
if not kernel or not action or not action.legal_action.keep:
|
3622
|
+
return kernel
|
3366
3623
|
|
3367
3624
|
deck_idx = action.legal_action.keep.deck_idx
|
3368
|
-
if deck_idx < 0 or deck_idx >= len(
|
3369
|
-
return
|
3625
|
+
if deck_idx < 0 or deck_idx >= len(kernel.decks):
|
3626
|
+
return kernel
|
3370
3627
|
|
3371
|
-
deck =
|
3628
|
+
deck = kernel.decks[deck_idx]
|
3372
3629
|
if not deck:
|
3373
|
-
return
|
3630
|
+
return kernel
|
3374
3631
|
|
3375
|
-
player =
|
3632
|
+
player = kernel.players[action.legal_action.player_idx]
|
3376
3633
|
if not player:
|
3377
|
-
return
|
3634
|
+
return kernel
|
3378
3635
|
|
3379
3636
|
# Keep the specified cards in the discard tray
|
3380
3637
|
kept_cards = [card_uuid for card_uuid in player.discard_tray if card_uuid in action.keep.card_uuids]
|
@@ -3388,32 +3645,33 @@ def handle_keep_action(game, action):
|
|
3388
3645
|
player.cards.extend([c for c in kept_cards if c is not None])
|
3389
3646
|
|
3390
3647
|
player.discard_tray.clear()
|
3391
|
-
return
|
3648
|
+
return kernel.set(decks=kernel.decks, players=kernel.players)
|
3392
3649
|
|
3393
3650
|
|
3394
|
-
|
3651
|
+
@dispatch(StateKernel, Action2)
|
3652
|
+
def handle_discard_action(kernel, action):
|
3395
3653
|
print("****************************** handle_discard_action 1", action)
|
3396
|
-
if not
|
3397
|
-
return
|
3654
|
+
if not kernel or not action or not action.legal_action.discard:
|
3655
|
+
return kernel
|
3398
3656
|
|
3399
3657
|
print("****************************** handle_discard_action 2", action)
|
3400
3658
|
|
3401
3659
|
deck_idx = action.legal_action.discard.deck_idx
|
3402
|
-
if deck_idx < 0 or deck_idx >= len(
|
3403
|
-
return
|
3660
|
+
if deck_idx < 0 or deck_idx >= len(kernel.decks):
|
3661
|
+
return kernel
|
3404
3662
|
|
3405
3663
|
print("****************************** handle_discard_action 3", deck_idx)
|
3406
3664
|
|
3407
|
-
deck =
|
3665
|
+
deck = kernel.decks[deck_idx]
|
3408
3666
|
print("****************************** handle_discard_action 3.5", deck)
|
3409
3667
|
if not deck:
|
3410
|
-
return
|
3668
|
+
return kernel
|
3411
3669
|
|
3412
3670
|
print("****************************** handle_discard_action 4")
|
3413
3671
|
|
3414
|
-
player =
|
3672
|
+
player = kernel.players[action.legal_action.player_idx]
|
3415
3673
|
if not player:
|
3416
|
-
return
|
3674
|
+
return kernel
|
3417
3675
|
|
3418
3676
|
# Keep the specified cards in the discard tray
|
3419
3677
|
non_kept_cards = [card_uuid for card_uuid in player.discard_tray if card_uuid in action.discard.card_uuids]
|
@@ -3431,22 +3689,24 @@ def handle_discard_action(game, action):
|
|
3431
3689
|
player.discard_tray.clear()
|
3432
3690
|
print("****************************** handle_discard_action 10 kept_cards: ", kept_cards)
|
3433
3691
|
|
3434
|
-
return
|
3692
|
+
return kernel.set(decks=kernel.decks, players=kernel.players)
|
3435
3693
|
|
3436
3694
|
|
3437
|
-
|
3438
|
-
|
3439
|
-
|
3695
|
+
@dispatch(StateKernel)
|
3696
|
+
def shuffle_all_decks(kernel):
|
3697
|
+
if not kernel or not kernel.decks:
|
3698
|
+
return kernel
|
3440
3699
|
|
3441
|
-
for i in range(len(
|
3442
|
-
|
3700
|
+
for i in range(len(kernel.decks)):
|
3701
|
+
kernel = shuffle_deck(kernel, i)
|
3443
3702
|
|
3444
|
-
return
|
3703
|
+
return kernel
|
3445
3704
|
|
3446
3705
|
|
3447
|
-
|
3448
|
-
|
3449
|
-
|
3706
|
+
@dispatch(StateKernel, int, Deck)
|
3707
|
+
def set_deck(kernel, deck_idx, deck):
|
3708
|
+
new_decks = kernel.decks[:deck_idx] + [deck] + kernel.decks[deck_idx + 1:]
|
3709
|
+
return kernel.set(decks=new_decks)
|
3450
3710
|
|
3451
3711
|
|
3452
3712
|
def shuffle(rng, deck):
|
@@ -3455,37 +3715,40 @@ def shuffle(rng, deck):
|
|
3455
3715
|
return deck.set(facedown_stack=shuffled_cards)
|
3456
3716
|
|
3457
3717
|
|
3458
|
-
|
3459
|
-
|
3460
|
-
|
3718
|
+
@dispatch(StateKernel, int)
|
3719
|
+
def shuffle_deck(kernel, deck_idx):
|
3720
|
+
if not kernel or not kernel.decks or deck_idx < 0 or deck_idx >= len(kernel.decks):
|
3721
|
+
return kernel
|
3461
3722
|
|
3462
|
-
deck =
|
3723
|
+
deck = kernel.decks[deck_idx]
|
3463
3724
|
if not deck or not deck.facedown_stack:
|
3464
|
-
return
|
3725
|
+
return kernel
|
3465
3726
|
|
3466
|
-
shuffled_deck = shuffle(
|
3467
|
-
|
3468
|
-
return
|
3727
|
+
shuffled_deck = shuffle(kernel.rng, deck)
|
3728
|
+
kernel = set_deck(kernel, deck_idx, shuffled_deck)
|
3729
|
+
return kernel
|
3469
3730
|
|
3470
3731
|
|
3471
|
-
|
3472
|
-
|
3473
|
-
|
3732
|
+
@dispatch(StateKernel)
|
3733
|
+
def shuffle_player_order(kernel):
|
3734
|
+
if not kernel or not kernel.player_idxs:
|
3735
|
+
return kernel
|
3474
3736
|
|
3475
|
-
rng =
|
3476
|
-
shuffled_idxs = list(
|
3737
|
+
rng = kernel.rng
|
3738
|
+
shuffled_idxs = list(kernel.player_idxs)
|
3477
3739
|
rng.shuffle(shuffled_idxs)
|
3478
3740
|
|
3479
|
-
return
|
3741
|
+
return kernel.set(player_idxs=shuffled_idxs)
|
3480
3742
|
|
3481
3743
|
|
3482
|
-
|
3483
|
-
|
3484
|
-
|
3744
|
+
@dispatch(StateKernel, int, int)
|
3745
|
+
def flip_cards(kernel, deck_idx, num_cards):
|
3746
|
+
if not kernel or deck_idx < 0 or deck_idx >= len(kernel.decks):
|
3747
|
+
return kernel
|
3485
3748
|
|
3486
|
-
deck =
|
3749
|
+
deck = kernel.decks[deck_idx]
|
3487
3750
|
if not deck or not deck.facedown_stack:
|
3488
|
-
return
|
3751
|
+
return kernel
|
3489
3752
|
|
3490
3753
|
# Flip the top num_cards from the facedown_stack to the faceup_spots
|
3491
3754
|
for _ in range(num_cards):
|
@@ -3493,52 +3756,55 @@ def flip_cards(game, deck_idx, num_cards):
|
|
3493
3756
|
card = deck.facedown_stack.pop()
|
3494
3757
|
deck.faceup_spots.append(card)
|
3495
3758
|
|
3496
|
-
return
|
3759
|
+
return kernel.set(decks=kernel.decks)
|
3497
3760
|
|
3498
3761
|
|
3499
|
-
|
3500
|
-
|
3501
|
-
|
3762
|
+
@dispatch(StateKernel)
|
3763
|
+
def distribute_all_piles(kernel):
|
3764
|
+
if not kernel or not kernel.piles:
|
3765
|
+
return kernel
|
3502
3766
|
|
3503
|
-
for pile in
|
3767
|
+
for pile in kernel.piles:
|
3504
3768
|
player_idx = pile.player_idx
|
3505
|
-
if player_idx < 0 or player_idx >= len(
|
3769
|
+
if player_idx < 0 or player_idx >= len(kernel.players):
|
3506
3770
|
continue
|
3507
3771
|
|
3508
|
-
player =
|
3772
|
+
player = kernel.players[player_idx]
|
3509
3773
|
player.pieces.extend(pile.pieces)
|
3510
3774
|
pile.pieces.clear() # Clear the pile after distribution
|
3511
3775
|
|
3512
|
-
return
|
3776
|
+
return kernel.set(players=kernel.players, piles=kernel.piles)
|
3513
3777
|
|
3514
3778
|
|
3515
|
-
|
3516
|
-
|
3517
|
-
|
3779
|
+
@dispatch(StateKernel, int, int)
|
3780
|
+
def deal_cards_to_each_player_discard_tray(kernel, deck_idx, num_cards):
|
3781
|
+
if not kernel or deck_idx < 0 or deck_idx >= len(kernel.decks):
|
3782
|
+
return kernel
|
3518
3783
|
|
3519
|
-
deck =
|
3784
|
+
deck = kernel.decks[deck_idx]
|
3520
3785
|
if not deck or not deck.facedown_stack:
|
3521
|
-
return
|
3786
|
+
return kernel
|
3522
3787
|
|
3523
|
-
for player in
|
3788
|
+
for player in kernel.players:
|
3524
3789
|
# Deal cards to the player's discard tray
|
3525
3790
|
for _ in range(num_cards):
|
3526
3791
|
if deck.facedown_stack:
|
3527
3792
|
card = deck.facedown_stack.pop()
|
3528
3793
|
player.discard_tray.append(card)
|
3529
3794
|
|
3530
|
-
return
|
3795
|
+
return kernel.set(players=kernel.players, decks=kernel.decks)
|
3531
3796
|
|
3532
3797
|
|
3533
|
-
|
3534
|
-
|
3535
|
-
|
3798
|
+
@dispatch(StateKernel, int, int)
|
3799
|
+
def deal_cards_to_each_player(kernel, deck_idx, num_cards):
|
3800
|
+
if not kernel or deck_idx < 0 or deck_idx >= len(kernel.decks):
|
3801
|
+
return kernel
|
3536
3802
|
|
3537
|
-
deck =
|
3803
|
+
deck = kernel.decks[deck_idx]
|
3538
3804
|
if not deck or not deck.facedown_stack:
|
3539
|
-
return
|
3805
|
+
return kernel
|
3540
3806
|
|
3541
|
-
for player in
|
3807
|
+
for player in kernel.players:
|
3542
3808
|
player_hand = player.cards
|
3543
3809
|
# Deal cards to the player's hand
|
3544
3810
|
for _ in range(num_cards):
|
@@ -3546,7 +3812,7 @@ def deal_cards_to_each_player(game, deck_idx, num_cards):
|
|
3546
3812
|
card = deck.facedown_stack.pop()
|
3547
3813
|
player_hand.append(card)
|
3548
3814
|
|
3549
|
-
return
|
3815
|
+
return kernel.set(players=kernel.players, decks=kernel.decks)
|
3550
3816
|
|
3551
3817
|
|
3552
3818
|
def default_accept_action(game, action):
|
@@ -3977,6 +4243,37 @@ def run_state_hook(state, hook, log=False):
|
|
3977
4243
|
raise Exception(msg) from e
|
3978
4244
|
|
3979
4245
|
|
4246
|
+
def run_kernel_hook(kernel, hook, log=False):
|
4247
|
+
|
4248
|
+
namespace = HOOK_NAMESPACE.copy()
|
4249
|
+
|
4250
|
+
try:
|
4251
|
+
# Execute the code string
|
4252
|
+
exec(hook.code, namespace)
|
4253
|
+
|
4254
|
+
# Retrieve the handler function
|
4255
|
+
handler_func = namespace.get('handler')
|
4256
|
+
|
4257
|
+
if handler_func is None or not callable(handler_func):
|
4258
|
+
raise ValueError("No callable function named 'handler' found in the code")
|
4259
|
+
|
4260
|
+
# Call the handler function
|
4261
|
+
result = handler_func(kernel)
|
4262
|
+
# if log:
|
4263
|
+
# print(f"****************************** Running initialization hook 3: {hook.uuid} {result.player_idxs}")
|
4264
|
+
# print(f"****************************** Result of handler(5, 3): {result}")
|
4265
|
+
return result
|
4266
|
+
|
4267
|
+
except SyntaxError as e:
|
4268
|
+
msg = f"Syntax error in initialization hook {hook.uuid}: {str(e)}"
|
4269
|
+
logging.error(msg, exc_info=True)
|
4270
|
+
raise SyntaxError(msg) from e
|
4271
|
+
except Exception as e:
|
4272
|
+
msg = f"Error in initialization hook {hook.uuid}: {str(e)}"
|
4273
|
+
logging.error(msg, exc_info=True)
|
4274
|
+
raise Exception(msg) from e
|
4275
|
+
|
4276
|
+
|
3980
4277
|
# Implementing the following Julia function:
|
3981
4278
|
# function getfaceupspots(f, unit_deck, unit_deck_idx)
|
3982
4279
|
# num_faceup_spots = getsettingvalue(f, :num_faceup_spots)
|
@@ -4103,28 +4400,20 @@ def getnextstate2(s, a, log=False):
|
|
4103
4400
|
is_legal, reason = isactionlegal2(s, a)
|
4104
4401
|
if not is_legal:
|
4105
4402
|
raise ValueError(f"Action is not legal: {a}. Reason: {reason}")
|
4106
|
-
|
4107
|
-
|
4108
|
-
|
4109
|
-
|
4110
|
-
|
4111
|
-
|
4112
|
-
|
4113
|
-
|
4114
|
-
|
4115
|
-
decks=s.decks,
|
4116
|
-
piles=s.piles,
|
4117
|
-
players=s.players,
|
4118
|
-
player_idxs=s.player_idxs,
|
4119
|
-
history=s.history,
|
4120
|
-
player_scores=s.player_scores,
|
4121
|
-
starting_decks=s.kernel.starting_decks,
|
4122
|
-
starting_piles=s.kernel.starting_piles,
|
4123
|
-
goals=s.kernel.goals,
|
4403
|
+
|
4404
|
+
kernel = s.kernel
|
4405
|
+
kernel = run_state_action_hooks(kernel, a, AFTER_ACCEPT_ACTION_HOOKS, log)
|
4406
|
+
kernel = run_state_action_hooks(kernel, a, HANDLE_ACTION_HOOKS, log)
|
4407
|
+
|
4408
|
+
state = State(
|
4409
|
+
kernel=kernel,
|
4410
|
+
legal_actions_3=calc_legal_actions3(kernel),
|
4411
|
+
bonus_statuses_3=calc_bonus_statuses3(kernel),
|
4124
4412
|
)
|
4125
|
-
|
4413
|
+
state = state.set(player_scores_3=calc_player_scores3(state))
|
4414
|
+
state = state.set(winners=calc_winners_3(state))
|
4126
4415
|
|
4127
|
-
return
|
4416
|
+
return state
|
4128
4417
|
|
4129
4418
|
|
4130
4419
|
def getpublicplayerscore(s, player_score):
|
@@ -4270,6 +4559,7 @@ def imagine_state(public_state, private_state):
|
|
4270
4559
|
player_idxs=public_state.player_idxs,
|
4271
4560
|
piles=public_state.piles,
|
4272
4561
|
edges=public_state.edges,
|
4562
|
+
nodes=public_state.nodes,
|
4273
4563
|
decks=imagine_decks(public_state, private_state),
|
4274
4564
|
players=imagine_players(public_state, private_state),
|
4275
4565
|
history=imagine_history(public_state, private_state),
|
@@ -4290,22 +4580,22 @@ def getpublicstate(s):
|
|
4290
4580
|
allotted_times=get_max_allotted_times(s),
|
4291
4581
|
all_pieces=list(s.kernel.pieceuuid2piece.values()),
|
4292
4582
|
to_play_2=getpublictoplay(s),
|
4293
|
-
bonus_statuses=s.
|
4583
|
+
bonus_statuses=s.bonus_statuses_3,
|
4294
4584
|
starting_decks=s.kernel.starting_decks,
|
4295
4585
|
starting_piles=s.kernel.starting_piles,
|
4296
4586
|
history=get_public_history(s),
|
4297
4587
|
player_scores=get_public_player_scores(s),
|
4298
|
-
player_graphs=s.
|
4588
|
+
player_graphs=s.kernel.player_graphs_3,
|
4299
4589
|
goals=s.kernel.goals,
|
4300
|
-
nodes=s.nodes,
|
4301
|
-
edges=s.edges,
|
4302
|
-
regions=s.regions,
|
4590
|
+
nodes=s.kernel.nodes,
|
4591
|
+
edges=s.kernel.edges,
|
4592
|
+
regions=s.kernel.regions,
|
4303
4593
|
decks=[getpublicdeck(s, deck) for deck in s.decks],
|
4304
|
-
piles=s.piles,
|
4305
|
-
player_idxs=s.player_idxs,
|
4594
|
+
piles=s.kernel.piles,
|
4595
|
+
player_idxs=s.kernel.player_idxs,
|
4306
4596
|
players=[getpublicplayer(s, p) for p in s.players],
|
4307
|
-
last_to_play=s.last_to_play,
|
4308
|
-
winners=s.winners,
|
4597
|
+
last_to_play=s.kernel.last_to_play,
|
4598
|
+
winners=s.kernel.winners,
|
4309
4599
|
terminal=isterminal(s),
|
4310
4600
|
)
|
4311
4601
|
|
@@ -4473,6 +4763,7 @@ def get_legal_actions(s, player_idx):
|
|
4473
4763
|
return [a for a in s.legal_actions_3 if a.player_idx == player_idx]
|
4474
4764
|
|
4475
4765
|
|
4766
|
+
@dispatch(State, int)
|
4476
4767
|
def get_goal_completions(s, player_idx):
|
4477
4768
|
# print("len(get_goals(s, player_idx)): ", len(get_goals(s, player_idx)))
|
4478
4769
|
# print("len(s.history): ", len(s.history))
|
@@ -4486,10 +4777,24 @@ def get_goal_completions(s, player_idx):
|
|
4486
4777
|
]
|
4487
4778
|
|
4488
4779
|
|
4489
|
-
@dispatch(
|
4490
|
-
def
|
4491
|
-
|
4492
|
-
|
4780
|
+
@dispatch(StateKernel, int)
|
4781
|
+
def get_goal_completions3(kernel, player_idx):
|
4782
|
+
# print("len(get_goals(s, player_idx)): ", len(get_goals(s, player_idx)))
|
4783
|
+
# print("len(s.history): ", len(s.history))
|
4784
|
+
# print("player.cards: ", len(s.players[player_idx].cards))
|
4785
|
+
return [
|
4786
|
+
GoalCompletion(
|
4787
|
+
goal_uuid=goal.uuid,
|
4788
|
+
complete=is_goal_complete(kernel, goal, player_idx),
|
4789
|
+
)
|
4790
|
+
for goal in get_goals3(kernel, player_idx)
|
4791
|
+
]
|
4792
|
+
|
4793
|
+
|
4794
|
+
@dispatch(StateKernel, FrozenGoal, int)
|
4795
|
+
def is_goal_complete(kernel, goal, player_idx):
|
4796
|
+
graph = kernel.player_graphs_3[player_idx].neighbors
|
4797
|
+
node_idxs = [kernel.nodeuuid2idx[node_uuid] for node_uuid in goal.node_uuids]
|
4493
4798
|
return are_nodes_connected(
|
4494
4799
|
graph,
|
4495
4800
|
node_idxs,
|
@@ -4525,11 +4830,21 @@ def get_player_graph(s, player_idx):
|
|
4525
4830
|
return nodes
|
4526
4831
|
|
4527
4832
|
|
4528
|
-
@dispatch(
|
4529
|
-
def get_goals(
|
4530
|
-
player =
|
4531
|
-
goaluuid2goal = {goal.uuid: goal for goal in
|
4532
|
-
goal_uuids = [
|
4833
|
+
@dispatch(StateKernel, int)
|
4834
|
+
def get_goals(kernel, player_idx):
|
4835
|
+
player = kernel.players[player_idx]
|
4836
|
+
goaluuid2goal = {goal.uuid: goal for goal in kernel.goals}
|
4837
|
+
goal_uuids = [kernel.carduuid2card[card_uuid].goal_uuid for card_uuid in player.cards if kernel.carduuid2card[card_uuid].goal_uuid]
|
4838
|
+
return [
|
4839
|
+
goaluuid2goal[goal_uuid] for goal_uuid in goal_uuids if goal_uuid in goaluuid2goal
|
4840
|
+
]
|
4841
|
+
|
4842
|
+
|
4843
|
+
@dispatch(StateKernel, int)
|
4844
|
+
def get_goals3(kernel, player_idx):
|
4845
|
+
player = kernel.players[player_idx]
|
4846
|
+
goaluuid2goal = {goal.uuid: goal for goal in kernel.goals}
|
4847
|
+
goal_uuids = [kernel.carduuid2card[card_uuid].goal_uuid for card_uuid in player.cards if kernel.carduuid2card[card_uuid].goal_uuid]
|
4533
4848
|
return [
|
4534
4849
|
goaluuid2goal[goal_uuid] for goal_uuid in goal_uuids if goal_uuid in goaluuid2goal
|
4535
4850
|
]
|
@@ -5188,23 +5503,23 @@ def getqproxy0(ps, a, td):
|
|
5188
5503
|
return qproxyrecurse() if td > 0 else qproxybase()
|
5189
5504
|
|
5190
5505
|
|
5191
|
-
INIT_HOOK_1 = """def handler(
|
5192
|
-
return shuffle_all_decks(
|
5506
|
+
INIT_HOOK_1 = """def handler(kernel):
|
5507
|
+
return shuffle_all_decks(kernel)
|
5193
5508
|
"""
|
5194
|
-
INIT_HOOK_2 = """def handler(
|
5195
|
-
return deal_cards_to_each_player(
|
5509
|
+
INIT_HOOK_2 = """def handler(kernel):
|
5510
|
+
return deal_cards_to_each_player(kernel, 0, 4)
|
5196
5511
|
"""
|
5197
|
-
INIT_HOOK_3 = """def handler(
|
5198
|
-
return deal_cards_to_each_player_discard_tray(
|
5512
|
+
INIT_HOOK_3 = """def handler(kernel):
|
5513
|
+
return deal_cards_to_each_player_discard_tray(kernel, 1, 3)
|
5199
5514
|
"""
|
5200
|
-
INIT_HOOK_4 = """def handler(
|
5201
|
-
return distribute_all_piles(
|
5515
|
+
INIT_HOOK_4 = """def handler(kernel):
|
5516
|
+
return distribute_all_piles(kernel)
|
5202
5517
|
"""
|
5203
|
-
INIT_HOOK_5 = """def handler(
|
5204
|
-
return flip_cards(
|
5518
|
+
INIT_HOOK_5 = """def handler(kernel):
|
5519
|
+
return flip_cards(kernel, 0, 5)
|
5205
5520
|
"""
|
5206
|
-
INIT_HOOK_7 = """def handler(
|
5207
|
-
return shuffle_player_order(
|
5521
|
+
INIT_HOOK_7 = """def handler(kernel):
|
5522
|
+
return shuffle_player_order(kernel)
|
5208
5523
|
"""
|
5209
5524
|
|
5210
5525
|
INITIALIZATION_HOOKS = [
|
@@ -5246,9 +5561,10 @@ INITIALIZATION_HOOKS = [
|
|
5246
5561
|
),
|
5247
5562
|
]
|
5248
5563
|
|
5564
|
+
|
5249
5565
|
HANDLE_ACTION_HOOK_1 = """
|
5250
|
-
def handler(
|
5251
|
-
return default_handle_action(
|
5566
|
+
def handler(kernel, action):
|
5567
|
+
return default_handle_action(kernel, action)
|
5252
5568
|
"""
|
5253
5569
|
|
5254
5570
|
HANDLE_ACTION_HOOKS = [
|
@@ -5261,8 +5577,8 @@ HANDLE_ACTION_HOOKS = [
|
|
5261
5577
|
]
|
5262
5578
|
|
5263
5579
|
AFTER_ACCEPT_ACTION_HOOK_1 = """
|
5264
|
-
def handler(
|
5265
|
-
return default_after_accept_action(
|
5580
|
+
def handler(kernel, action):
|
5581
|
+
return default_after_accept_action(kernel, action)
|
5266
5582
|
"""
|
5267
5583
|
|
5268
5584
|
AFTER_ACCEPT_ACTION_HOOKS = [
|