@@ -19,7 +19,7 @@ def read_from_file(fn: str) -> gbt.Game:
1919
2020
2121def create_efg_corresponding_to_bimatrix_game (
22- A : np .ndarray , B : np .ndarray , title : str
22+ A : np .ndarray , B : np .ndarray , title : str
2323) -> gbt .Game :
2424 """
2525 There is no direct pygambit method to create an EFG from a stategic-form game.
@@ -42,19 +42,29 @@ def create_efg_corresponding_to_bimatrix_game(
4242# Extensive-form games (efg)
4343
4444
45- def create_2x2_zero_sum_efg (missing_term_outcome : bool = False ) -> gbt .Game :
45+ def create_2x2_zero_sum_efg (variant : None | str = None ) -> gbt .Game :
4646 """
4747 EFG corresponding to 2x2 zero-sum game (I,-I).
48- If missing_term_outcome, the terminal node after action 0 then 1 does not have an outcome.
48+
49+ If variant is:
50+ - "missing term outcome", terminal node after action 0 then 1 does not have an outcome.
51+ - "with neutral outcome", there is a (0,0) payoff outcomes at a non-terminal node.
4952 """
5053 title = "EFG for 2x2 zero-sum game (I,-I)"
51- if missing_term_outcome :
52- title += " with missing terminal outcome"
54+
55+ if variant :
56+ title += " " + variant
57+
5358 A = np .eye (2 )
5459 B = - A
5560 g = create_efg_corresponding_to_bimatrix_game (A , B , title )
56- if missing_term_outcome :
61+
62+ if variant == "missing term outcome" :
5763 g .delete_outcome (g .root .children [0 ].children [1 ].outcome )
64+ elif variant == "with neutral outcome" :
65+ neutral = g .add_outcome ([0 , 0 ], label = "neutral" )
66+ g .set_outcome (g .root .children [0 ], neutral )
67+
5868 return g
5969
6070
@@ -91,8 +101,9 @@ def create_stripped_down_poker_efg(nonterm_outcomes: bool = False) -> gbt.Game:
91101 return read_from_file ("stripped_down_poker.efg" )
92102
93103 g = gbt .Game .new_tree (
94- players = ["Alice" , "Bob" ], title = "Stripped-Down Poker: a simple game of one-card\
95- poker from Reiley et al (2008)."
104+ players = ["Alice" , "Bob" ],
105+ title = "Stripped-Down Poker: a simple game of one-card\
106+ poker from Reiley et al (2008)." ,
96107 )
97108 deals = ["King" , "Queen" ]
98109 g .append_move (g .root , g .players .chance , deals )
@@ -107,21 +118,15 @@ def create_stripped_down_poker_efg(nonterm_outcomes: bool = False) -> gbt.Game:
107118 bob_calls_and_loses_outcome = g .add_outcome ([4 , - 1 ], label = "Bob Calls and Loses" )
108119
109120 for node in g .root .children :
110- g .append_move (
111- node ,
112- player = "Alice" ,
113- actions = ["Bet" , "Fold" ]
114- )
121+ g .append_move (node , player = "Alice" , actions = ["Bet" , "Fold" ])
115122 g .set_outcome (node .children ["Fold" ], alice_folds_outcome )
116123 g .set_outcome (node .children ["Bet" ], alice_bets_outcome )
117124
118- alice_bets_nodes = [g .root .children ["King" ].children ["Bet" ],
119- g .root .children ["Queen" ].children ["Bet" ]]
120- g .append_move (
121- alice_bets_nodes ,
122- player = "Bob" ,
123- actions = ["Call" , "Fold" ]
124- )
125+ alice_bets_nodes = [
126+ g .root .children ["King" ].children ["Bet" ],
127+ g .root .children ["Queen" ].children ["Bet" ],
128+ ]
129+ g .append_move (alice_bets_nodes , player = "Bob" , actions = ["Call" , "Fold" ])
125130 for node in alice_bets_nodes :
126131 g .set_outcome (node .children ["Fold" ], bob_folds_outcome )
127132
@@ -136,9 +141,7 @@ def _create_kuhn_poker_efg_without_outcomes():
136141 """
137142 Used in create_kuhn_poker_efg()
138143 """
139- g = gbt .Game .new_tree (
140- players = ["Alice" , "Bob" ], title = "Three-card poker (J, Q, K), two-player"
141- )
144+ g = gbt .Game .new_tree (players = ["Alice" , "Bob" ], title = "Three-card poker (J, Q, K), two-player" )
142145 cards = ["J" , "Q" , "K" ]
143146 deals = ["JQ" , "JK" , "QJ" , "QK" , "KJ" , "KQ" ]
144147
@@ -147,25 +150,29 @@ def deals_by_infoset(player, card):
147150 return [d for d in deals if d [player_idx ] == card ]
148151
149152 g .append_move (g .root , g .players .chance , deals )
150- g .set_chance_probs (g .root .infoset , [gbt .Rational (1 , 6 )]* 6 )
153+ g .set_chance_probs (g .root .infoset , [gbt .Rational (1 , 6 )] * 6 )
151154 for alice_card in cards :
152155 # Alice's first move
153156 term_nodes = [g .root .children [d ] for d in deals_by_infoset ("Alice" , alice_card )]
154157 g .append_move (term_nodes , "Alice" , ["Check" , "Bet" ])
155158 for bob_card in cards :
156159 # Bob's move after Alice checks
157- term_nodes = [g .root .children [d ].children ["Check" ]
158- for d in deals_by_infoset ("Bob" , bob_card )]
160+ term_nodes = [
161+ g .root .children [d ].children ["Check" ] for d in deals_by_infoset ("Bob" , bob_card )
162+ ]
159163 g .append_move (term_nodes , "Bob" , ["Check" , "Bet" ])
160164 for alice_card in cards :
161165 # Alice's move if Bob's second action is bet
162- term_nodes = [g .root .children [d ].children ["Check" ].children ["Bet" ]
163- for d in deals_by_infoset ("Alice" , alice_card )]
166+ term_nodes = [
167+ g .root .children [d ].children ["Check" ].children ["Bet" ]
168+ for d in deals_by_infoset ("Alice" , alice_card )
169+ ]
164170 g .append_move (term_nodes , "Alice" , ["Fold" , "Call" ])
165171 for bob_card in cards :
166172 # Bob's move after Alice bets initially
167- term_nodes = [g .root .children [d ].children ["Bet" ]
168- for d in deals_by_infoset ("Bob" , bob_card )]
173+ term_nodes = [
174+ g .root .children [d ].children ["Bet" ] for d in deals_by_infoset ("Bob" , bob_card )
175+ ]
169176 g .append_move (term_nodes , "Bob" , ["Fold" , "Call" ])
170177 return g
171178
@@ -189,7 +196,6 @@ def _create_kuhn_poker_efg_only_term_outcomes() -> gbt.Game:
189196 g = _create_kuhn_poker_efg_without_outcomes ()
190197
191198 def calculate_payoffs (term_node ):
192-
193199 def get_path (node ):
194200 path = []
195201 while node .parent :
@@ -231,10 +237,12 @@ def bet(player, payoffs, pot):
231237 return tuple (payoffs .values ())
232238
233239 # create 4 possible outcomes just once
234- payoffs_to_outcomes = {(1 , - 1 ): g .add_outcome ([1 , - 1 ], label = "Alice wins 1" ),
235- (2 , - 2 ): g .add_outcome ([2 , - 2 ], label = "Alice wins 2" ),
236- (- 1 , 1 ): g .add_outcome ([- 1 , 1 ], label = "Bob wins 1" ),
237- (- 2 , 2 ): g .add_outcome ([- 2 , 2 ], label = "Bob wins 2" )}
240+ payoffs_to_outcomes = {
241+ (1 , - 1 ): g .add_outcome ([1 , - 1 ], label = "Alice wins 1" ),
242+ (2 , - 2 ): g .add_outcome ([2 , - 2 ], label = "Alice wins 2" ),
243+ (- 1 , 1 ): g .add_outcome ([- 1 , 1 ], label = "Bob wins 1" ),
244+ (- 2 , 2 ): g .add_outcome ([- 2 , 2 ], label = "Bob wins 2" ),
245+ }
238246
239247 for term_node in [n for n in g .nodes if n .is_terminal ]:
240248 outcome = payoffs_to_outcomes [calculate_payoffs (term_node )]
@@ -280,7 +288,6 @@ def _create_kuhn_poker_efg_nonterm_outcomes() -> gbt.Game:
280288 outcomes_dict [tmp ] = g .add_outcome (payoffs , label = tmp )
281289
282290 def add_outcomes (term_node ):
283-
284291 def get_path (node ):
285292 path = []
286293 while node .parent :
@@ -388,9 +395,7 @@ def create_one_shot_trust_efg(unique_NE_variant: bool = False) -> gbt.Game:
388395 )
389396 g .append_move (g .root , "Buyer" , ["Trust" , "Not trust" ])
390397 g .append_move (g .root .children [0 ], "Seller" , ["Honor" , "Abuse" ])
391- g .set_outcome (
392- g .root .children [0 ].children [0 ], g .add_outcome ([1 , 1 ], label = "Trustworthy" )
393- )
398+ g .set_outcome (g .root .children [0 ].children [0 ], g .add_outcome ([1 , 1 ], label = "Trustworthy" ))
394399 if unique_NE_variant :
395400 g .set_outcome (
396401 g .root .children [0 ].children [1 ], g .add_outcome (["1/2" , 2 ], label = "Untrustworthy" )
@@ -489,9 +494,7 @@ def __init__(self, params):
489494 self .m1 = params ["m1" ]
490495
491496 def gbt_game (self ):
492- g = gbt .Game .new_tree (
493- players = ["1" , "2" ], title = f"Centipede Game with { self .N } rounds"
494- )
497+ g = gbt .Game .new_tree (players = ["1" , "2" ], title = f"Centipede Game with { self .N } rounds" )
495498 current_node = g .root
496499 current_player = "1"
497500 for t in range (self .N ):
@@ -510,7 +513,6 @@ def gbt_game(self):
510513 return g
511514
512515 def reduced_strategies (self ):
513-
514516 if self .N % 2 == 0 :
515517 n_moves = [int (self .N / 2 )] * 2
516518 else :
@@ -594,7 +596,6 @@ def __init__(self, n_players, params):
594596 self .n_players = n_players
595597
596598 def get_n_infosets (self , level ):
597-
598599 if self .n_players == 1 :
599600 return {1 : 2 ** (level - 1 )}
600601
@@ -649,16 +650,13 @@ def gbt_game(self):
649650
650651 def reduced_strategic_form (self ):
651652 # special case for 1 player
652- dims = (
653- (self .size_of_rsf [0 ], 1 ) if len (self .size_of_rsf ) == 1 else self .size_of_rsf
654- )
653+ dims = (self .size_of_rsf [0 ], 1 ) if len (self .size_of_rsf ) == 1 else self .size_of_rsf
655654
656655 zeros = np .zeros (dims , dtype = int )
657656 return [zeros ] * len (self .players )
658657
659658
660659class BinEfgOnePlayerIR (BinaryTreeGames ):
661-
662660 def __init__ (self , params ):
663661 super ().__init__ (n_players = 1 , params = params )
664662
@@ -667,26 +665,21 @@ def _redu_strats(self, player, level):
667665 return self ._redu_strategies_level_1 (player )
668666 else :
669667 tmp = self ._redu_strats (1 , level - 1 )
670- tmp = [
671- t [1 :] for t in tmp
672- ] # remove first action (1 from 1st half; 2 from 2nd half)
668+ tmp = [t [1 :] for t in tmp ] # remove first action (1 from 1st half; 2 from 2nd half)
673669 n_half = int (len (tmp ) / 2 )
674670 first_half = tmp [:n_half ]
675671 second_half = tmp [n_half :]
676- n_stars = (
677- self .get_n_infosets (level )[1 ] - self .get_n_infosets (level - 1 )[1 ] - 1
678- )
672+ n_stars = self .get_n_infosets (level )[1 ] - self .get_n_infosets (level - 1 )[1 ] - 1
679673 stars = "*" * n_stars
680674 return (
681- ["11" + t + stars for t in first_half ]
682- + ["12" + t + stars for t in second_half ]
683- + ["21" + stars + t for t in first_half ]
684- + ["22" + stars + t for t in second_half ]
675+ ["11" + t + stars for t in first_half ]
676+ + ["12" + t + stars for t in second_half ]
677+ + ["21" + stars + t for t in first_half ]
678+ + ["22" + stars + t for t in second_half ]
685679 )
686680
687681
688682class BinEfgTwoOrThreePlayers (BinaryTreeGames ):
689-
690683 def _redu_strats (self , player , level ):
691684 if level == 1 :
692685 return self ._redu_strategies_level_1 (player )
@@ -698,11 +691,9 @@ def _redu_strats(self, player, level):
698691 n_stars = tmp1 [player ] - tmp2 [last_player ] - 1
699692 stars = "*" * n_stars
700693 return [
701- "1" + t + stars
702- for t in self ._redu_strats (player = last_player , level = level - 1 )
694+ "1" + t + stars for t in self ._redu_strats (player = last_player , level = level - 1 )
703695 ] + [
704- "2" + stars + t
705- for t in self ._redu_strats (player = last_player , level = level - 1 )
696+ "2" + stars + t for t in self ._redu_strats (player = last_player , level = level - 1 )
706697 ]
707698 elif player == 2 :
708699 tmp = self ._redu_strats (player = 1 , level = level - 1 )
0 commit comments