Skip to content

Commit 6e2c4fd

Browse files
committed
Set up boilerplate framework for adding subgames as type
This adds to C++ and Python the generic "boilerplate" code that makes the new planned explicit representation of subgames `GameSubgameRep` a type of `GameObject` (with its invalidation mechanism), and the Python wrapper class `Subgame`. A stub entry into the Python API index has also been added. Now all that is left to do is to actually implement tests and functionality!!!!
1 parent f3217a6 commit 6e2c4fd

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

doc/pygambit.api.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Representation of games
1919
Node
2020
Infoset
2121
Action
22+
Subgame
2223
Strategy
2324

2425

@@ -151,7 +152,6 @@ Information about the game
151152
Node.plays
152153

153154
.. autosummary::
154-
155155
:toctree: api/
156156

157157
Infoset.label
@@ -164,7 +164,6 @@ Information about the game
164164
Infoset.plays
165165

166166
.. autosummary::
167-
168167
:toctree: api/
169168

170169
Action.label
@@ -174,7 +173,12 @@ Information about the game
174173
Action.plays
175174

176175
.. autosummary::
176+
:toctree: api/
177177

178+
Subgame.game
179+
Subgame.root
180+
181+
.. autosummary::
178182
:toctree: api/
179183

180184
Strategy.label

src/games/game.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ using GamePlayer = GameObjectPtr<GamePlayerRep>;
5757
class GameNodeRep;
5858
using GameNode = GameObjectPtr<GameNodeRep>;
5959

60+
class GameSubgameRep;
61+
using GameSubgame = GameObjectPtr<GameSubgameRep>;
62+
6063
class GameRep;
6164
using Game = std::shared_ptr<GameRep>;
6265

@@ -594,6 +597,26 @@ inline GameNodeRep::Actions::iterator::iterator(GameInfosetRep::Actions::iterato
594597

595598
inline GameNode GameNodeRep::Actions::iterator::GetOwner() const { return m_child_it.GetOwner(); }
596599

600+
class GameSubgameRep : public std::enable_shared_from_this<GameSubgameRep> {
601+
bool m_valid{true};
602+
GameRep *m_game;
603+
GameNodeRep *m_root;
604+
605+
public:
606+
GameSubgameRep(GameRep *p_game, GameNodeRep *p_root) : m_game(p_game), m_root(p_root) {}
607+
~GameSubgameRep() = default;
608+
609+
bool IsValid() const { return m_valid; }
610+
void Invalidate() { m_valid = false; }
611+
612+
GameNode GetRoot() const { return m_root->shared_from_this(); }
613+
Game GetGame() const;
614+
615+
// Functions to implement suitably:
616+
// GetParent()
617+
// GetChildren()
618+
};
619+
597620
/// This is the class for representing an arbitrary finite game.
598621
class GameRep : public std::enable_shared_from_this<GameRep> {
599622
friend class GameOutcomeRep;
@@ -1001,6 +1024,8 @@ inline GamePlayerRep::Strategies GamePlayerRep::GetStrategies() const
10011024

10021025
inline Game GameNodeRep::GetGame() const { return m_game->shared_from_this(); }
10031026

1027+
inline Game GameSubgameRep::GetGame() const { return m_game->shared_from_this(); }
1028+
10041029
//=======================================================================
10051030

10061031
/// Factory function to create new game tree

src/pygambit/gambit.pxd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ cdef extern from "games/game.h":
5555
cdef cppclass c_GamePlayerRep "GamePlayerRep"
5656
cdef cppclass c_GameOutcomeRep "GameOutcomeRep"
5757
cdef cppclass c_GameNodeRep "GameNodeRep"
58+
cdef cppclass c_GameSubgameRep "GameSubgameRep"
5859

5960
cdef cppclass c_Game "Game":
6061
c_GameRep *deref "operator->"() except +RuntimeError
@@ -72,6 +73,10 @@ cdef extern from "games/game.h":
7273
bool operator !=(c_GameNode) except +
7374
c_GameNodeRep *deref "get"() except +RuntimeError
7475

76+
cdef cppclass c_GameSubgame "GameObjectPtr<GameSubgameRep>":
77+
bool operator !=(c_GameSubgame) except +
78+
c_GameSubgameRep *deref "get"() except +RuntimeError
79+
7580
cdef cppclass c_GameAction "GameObjectPtr<GameActionRep>":
7681
bool operator !() except +
7782
bool operator !=(c_GameAction) except +
@@ -221,6 +226,12 @@ cdef extern from "games/game.h":
221226
bint IsStrategyReachable() except +
222227
c_GameAction GetPriorAction() except +
223228

229+
cdef cppclass c_GameSubgameRep "GameSubgameRep":
230+
c_Game GetGame() except +
231+
c_GameNode GetRoot() except +
232+
# GetParent()
233+
# GetChildren()
234+
224235
cdef cppclass c_GameRep "GameRep":
225236
cppclass Players:
226237
cppclass iterator:

src/pygambit/node.pxi

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,40 @@ class Node:
240240
"""Returns a list of all terminal `Node` objects consistent with it.
241241
"""
242242
return [Node.wrap(n) for n in self.node.deref().GetGame().deref().GetPlays(self.node)]
243+
244+
245+
@cython.cclass
246+
class Subgame:
247+
"""A subgame in a ``Game``."""
248+
subgame = cython.declare(c_GameSubgame)
249+
250+
def __init__(self, *args, **kwargs) -> None:
251+
raise ValueError("Cannot create a Subgame outside a Game.")
252+
253+
@staticmethod
254+
@cython.cfunc
255+
def wrap(subgame: c_GameSubgame) -> Subgame:
256+
obj: Subgame = Subgame.__new__(Subgame)
257+
obj.subgame = subgame
258+
return obj
259+
260+
# needs a __repr__
261+
262+
def __eq__(self, other: typing.Any) -> bool:
263+
return (
264+
isinstance(other, Subgame) and
265+
self.subgame.deref() == cython.cast(Subgame, other).subgame.deref()
266+
)
267+
268+
def __hash__(self) -> long:
269+
return cython.cast(long, self.subgame.deref())
270+
271+
@property
272+
def game(self) -> Game:
273+
"""Gets the ``Game`` to which the subgame belongs."""
274+
return Game.wrap(self.subgame.deref().GetGame())
275+
276+
@property
277+
def root(self) -> Node:
278+
"""The root node of the subgame."""
279+
return Node.wrap(self.subgame.deref().GetRoot())

0 commit comments

Comments
 (0)