Skip to content

Commit 97e7df7

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 43ba14c commit 97e7df7

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

@@ -152,7 +153,6 @@ Information about the game
152153
Node.own_prior_action
153154

154155
.. autosummary::
155-
156156
:toctree: api/
157157

158158
Infoset.label
@@ -167,7 +167,6 @@ Information about the game
167167
Infoset.own_prior_actions
168168

169169
.. autosummary::
170-
171170
:toctree: api/
172171

173172
Action.label
@@ -177,7 +176,12 @@ Information about the game
177176
Action.plays
178177

179178
.. autosummary::
179+
:toctree: api/
180180

181+
Subgame.game
182+
Subgame.root
183+
184+
.. autosummary::
181185
:toctree: api/
182186

183187
Strategy.label

src/games/game.h

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

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

@@ -593,6 +596,26 @@ inline GameNodeRep::Actions::iterator::iterator(GameInfosetRep::Actions::iterato
593596

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

599+
class GameSubgameRep : public std::enable_shared_from_this<GameSubgameRep> {
600+
bool m_valid{true};
601+
GameRep *m_game;
602+
GameNodeRep *m_root;
603+
604+
public:
605+
GameSubgameRep(GameRep *p_game, GameNodeRep *p_root) : m_game(p_game), m_root(p_root) {}
606+
~GameSubgameRep() = default;
607+
608+
bool IsValid() const { return m_valid; }
609+
void Invalidate() { m_valid = false; }
610+
611+
GameNode GetRoot() const { return m_root->shared_from_this(); }
612+
Game GetGame() const;
613+
614+
// Functions to implement suitably:
615+
// GetParent()
616+
// GetChildren()
617+
};
618+
596619
inline void ValidateDistribution(const Array<Number> &p_probs, const bool p_normalized = true)
597620
{
598621
if (std::any_of(p_probs.begin(), p_probs.end(),
@@ -1246,6 +1269,8 @@ inline GamePlayerRep::Infosets GamePlayerRep::GetInfosets() const
12461269
return Infosets(std::const_pointer_cast<GamePlayerRep>(shared_from_this()), &m_infosets);
12471270
}
12481271

1272+
inline Game GameSubgameRep::GetGame() const { return m_game->shared_from_this(); }
1273+
12491274
//=======================================================================
12501275

12511276
/// 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
@@ -50,6 +50,7 @@ cdef extern from "games/game.h":
5050
cdef cppclass c_GamePlayerRep "GamePlayerRep"
5151
cdef cppclass c_GameOutcomeRep "GameOutcomeRep"
5252
cdef cppclass c_GameNodeRep "GameNodeRep"
53+
cdef cppclass c_GameSubgameRep "GameSubgameRep"
5354

5455
cdef cppclass c_Game "Game":
5556
c_GameRep *deref "operator->"() except +RuntimeError
@@ -67,6 +68,10 @@ cdef extern from "games/game.h":
6768
bool operator !=(c_GameNode) except +
6869
c_GameNodeRep *deref "get"() except +RuntimeError
6970

71+
cdef cppclass c_GameSubgame "GameObjectPtr<GameSubgameRep>":
72+
bool operator !=(c_GameSubgame) except +
73+
c_GameSubgameRep *deref "get"() except +RuntimeError
74+
7075
cdef cppclass c_GameAction "GameObjectPtr<GameActionRep>":
7176
bool operator !() except +
7277
bool operator !=(c_GameAction) except +
@@ -218,6 +223,12 @@ cdef extern from "games/game.h":
218223
c_GameAction GetPriorAction() except +
219224
c_GameAction GetOwnPriorAction() except +
220225

226+
cdef cppclass c_GameSubgameRep "GameSubgameRep":
227+
c_Game GetGame() except +
228+
c_GameNode GetRoot() except +
229+
# GetParent()
230+
# GetChildren()
231+
221232
cdef cppclass c_GameRep "GameRep":
222233
cppclass Players:
223234
cppclass iterator:

src/pygambit/node.pxi

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,40 @@ class Node:
259259
"""Returns a list of all terminal `Node` objects consistent with it.
260260
"""
261261
return [Node.wrap(n) for n in self.node.deref().GetGame().deref().GetPlays(self.node)]
262+
263+
264+
@cython.cclass
265+
class Subgame:
266+
"""A subgame in a ``Game``."""
267+
subgame = cython.declare(c_GameSubgame)
268+
269+
def __init__(self, *args, **kwargs) -> None:
270+
raise ValueError("Cannot create a Subgame outside a Game.")
271+
272+
@staticmethod
273+
@cython.cfunc
274+
def wrap(subgame: c_GameSubgame) -> Subgame:
275+
obj: Subgame = Subgame.__new__(Subgame)
276+
obj.subgame = subgame
277+
return obj
278+
279+
# needs a __repr__
280+
281+
def __eq__(self, other: typing.Any) -> bool:
282+
return (
283+
isinstance(other, Subgame) and
284+
self.subgame.deref() == cython.cast(Subgame, other).subgame.deref()
285+
)
286+
287+
def __hash__(self) -> long:
288+
return cython.cast(long, self.subgame.deref())
289+
290+
@property
291+
def game(self) -> Game:
292+
"""Gets the ``Game`` to which the subgame belongs."""
293+
return Game.wrap(self.subgame.deref().GetGame())
294+
295+
@property
296+
def root(self) -> Node:
297+
"""The root node of the subgame."""
298+
return Node.wrap(self.subgame.deref().GetRoot())

0 commit comments

Comments
 (0)