Skip to content

Commit 79ada6e

Browse files
rahulsavanitturocy
authored andcommitted
Tests for the creation of the reduced strategic form from an extensive form game
1 parent 918cf55 commit 79ada6e

File tree

9 files changed

+469
-18
lines changed

9 files changed

+469
-18
lines changed

ChangeLog

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
been removed as planned. (#357)
1111

1212
### Added
13-
- Implement `GetPlays()` (C++) and `get_plays` (Python) to compute the set of terminal nodes
14-
consistent with a node, information set, or action (#517)
13+
- Implement `GetPlays()` (C++) and `get_plays` (Python) to compute the set of terminal nodes consistent
14+
with a node, information set, or action (#517)
1515
- Implement `GameStrategyRep::GetAction` (C++) and `Strategy.action` (Python) retrieving the action
16-
prescribed by a strategy at an information set
16+
prescribed by a strategy at an information set
17+
- Tests for creation of the reduced strategic form from an extensive-form game (currently only
18+
for games with perfect recall)
1719

1820

1921
## [16.3.1] - unreleased

tests/games.py

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
"""A utility module to create/load games for the test suite."""
2+
23
import pathlib
34

5+
import numpy as np
6+
47
import pygambit as gbt
58

69

710
def read_from_file(fn: str) -> gbt.Game:
811
if fn.endswith(".efg"):
9-
return gbt.read_efg(pathlib.Path("tests/test_games")/fn)
12+
return gbt.read_efg(pathlib.Path("tests/test_games") / fn)
1013
elif fn.endswith(".nfg"):
11-
return gbt.read_nfg(pathlib.Path("tests/test_games")/fn)
14+
return gbt.read_nfg(pathlib.Path("tests/test_games") / fn)
1215
else:
1316
raise ValueError(f"Unknown file extension in {fn}")
1417

1518

1619
################################################################################################
1720
# Normal-form (aka strategic-form) games (nfg)
1821

22+
1923
def create_2x2_zero_nfg() -> gbt.Game:
2024
"""
2125
Returns
@@ -73,6 +77,7 @@ def create_coord_4x4_nfg(outcome_version: bool = False) -> gbt.Game:
7377
################################################################################################
7478
# Extensive-form games (efg)
7579

80+
7681
def create_mixed_behav_game_efg() -> gbt.Game:
7782
"""
7883
Returns
@@ -89,7 +94,8 @@ def create_myerson_2_card_poker_efg() -> gbt.Game:
8994
Returns
9095
-------
9196
Game
92-
Myerson 2-card poker: Two-player extensive poker game with a chance move with two moves,
97+
Simplied "stripped down" version of Myerson 2-card poker:
98+
Two-player extensive poker game with a chance move with two moves,
9399
then player 1 can raise or fold; after raising player 2 is in an infoset with two nodes
94100
and can choose to meet or pass
95101
"""
@@ -124,3 +130,112 @@ def create_selten_horse_game_efg() -> gbt.Game:
124130
5-player Selten's Horse Game
125131
"""
126132
return read_from_file("e01.efg")
133+
134+
135+
def create_reduction_generic_payoffs_efg() -> gbt.Game:
136+
# tree with only root
137+
g = gbt.Game.new_tree(
138+
players=["1", "2"], title="2 player reduction generic payoffs"
139+
)
140+
141+
# add four children
142+
g.append_move(g.root, "2", ["a", "b", "c", "d"])
143+
144+
# add L and R after a
145+
g.append_move(g.root.children[0], "1", ["L", "R"])
146+
147+
# add C and D to single infoset after b and c
148+
nodes = [g.root.children[1], g.root.children[2]]
149+
g.append_move(nodes, "1", ["C", "D"])
150+
151+
# add s and t from single infoset after rightmost C and D
152+
g.append_move(g.root.children[2].children, "2", ["s", "t"])
153+
154+
# add p and q
155+
g.append_move(g.root.children[0].children[1], "2", ["p", "q"])
156+
157+
# add U and V in a single infoset after p and q
158+
g.append_move(g.root.children[0].children[1].children, "1", ["U", "V"])
159+
160+
# Set outcomes
161+
162+
g.set_outcome(g.root.children[0].children[0], g.add_outcome([1, -1], label="aL"))
163+
g.set_outcome(
164+
g.root.children[0].children[1].children[0].children[0],
165+
g.add_outcome([2, -2], label="aRpU"),
166+
)
167+
g.set_outcome(
168+
g.root.children[0].children[1].children[0].children[1],
169+
g.add_outcome([3, -3], label="aRpV"),
170+
)
171+
g.set_outcome(
172+
g.root.children[0].children[1].children[1].children[0],
173+
g.add_outcome([4, -4], label="aRqU"),
174+
)
175+
g.set_outcome(
176+
g.root.children[0].children[1].children[1].children[1],
177+
g.add_outcome([5, -5], label="aRqV"),
178+
)
179+
180+
g.set_outcome(g.root.children[1].children[0], g.add_outcome([6, -6], label="bC"))
181+
g.set_outcome(g.root.children[1].children[1], g.add_outcome([7, -7], label="bD"))
182+
183+
g.set_outcome(
184+
g.root.children[2].children[0].children[0], g.add_outcome([8, -8], label="cCs")
185+
)
186+
g.set_outcome(
187+
g.root.children[2].children[0].children[1], g.add_outcome([9, -9], label="cCt")
188+
)
189+
g.set_outcome(
190+
g.root.children[2].children[1].children[0],
191+
g.add_outcome([10, -10], label="cDs"),
192+
)
193+
g.set_outcome(
194+
g.root.children[2].children[1].children[1],
195+
g.add_outcome([11, -11], label="cDt"),
196+
)
197+
198+
g.set_outcome(g.root.children[3], g.add_outcome([12, -12], label="d"))
199+
200+
return g
201+
202+
203+
def create_reduction_one_player_generic_payoffs_efg() -> gbt.Game:
204+
g = gbt.Game.new_tree(players=["1"], title="One player reduction generic payoffs")
205+
g.append_move(g.root, "1", ["a", "b", "c", "d"])
206+
g.append_move(g.root.children[0], "1", ["e", "f"])
207+
g.set_outcome(g.root.children[0].children[0], g.add_outcome([1]))
208+
g.set_outcome(g.root.children[0].children[1], g.add_outcome([2]))
209+
g.set_outcome(g.root.children[1], g.add_outcome([3]))
210+
g.set_outcome(g.root.children[2], g.add_outcome([4]))
211+
g.set_outcome(g.root.children[3], g.add_outcome([5]))
212+
return g
213+
214+
215+
def create_reduction_both_players_payoff_ties_efg() -> gbt.Game:
216+
g = gbt.Game.new_tree(players=["1", "2"], title="From GTE survey")
217+
g.append_move(g.root, "1", ["A", "B", "C", "D"])
218+
g.append_move(g.root.children[0], "2", ["a", "b"])
219+
g.append_move(g.root.children[1], "2", ["c", "d"])
220+
g.append_move(g.root.children[2], "2", ["e", "f"])
221+
g.append_move(g.root.children[0].children[1], "2", ["g", "h"])
222+
g.append_move(g.root.children[2].children, "1", ["E", "F"])
223+
224+
g.set_outcome(g.root.children[0].children[0], g.add_outcome([2, 8]))
225+
g.set_outcome(g.root.children[0].children[1].children[0], g.add_outcome([0, 1]))
226+
g.set_outcome(g.root.children[0].children[1].children[1], g.add_outcome([5, 2]))
227+
g.set_outcome(g.root.children[1].children[0], g.add_outcome([7, 6]))
228+
g.set_outcome(g.root.children[1].children[1], g.add_outcome([4, 2]))
229+
g.set_outcome(g.root.children[2].children[0].children[0], g.add_outcome([3, 7]))
230+
g.set_outcome(g.root.children[2].children[0].children[1], g.add_outcome([8, 3]))
231+
g.set_outcome(g.root.children[2].children[1].children[0], g.add_outcome([7, 8]))
232+
g.set_outcome(g.root.children[2].children[1].children[1], g.add_outcome([2, 2]))
233+
g.set_outcome(g.root.children[3], g.add_outcome([6, 4]))
234+
return g
235+
236+
237+
def make_rational(input: str):
238+
return gbt.Rational(input)
239+
240+
241+
vectorized_make_rational = np.vectorize(make_rational)

0 commit comments

Comments
 (0)