@@ -194,6 +194,41 @@ class GameNodes:
194194 yield from dfs(Node.wrap(self .game.deref().GetRoot()))
195195
196196
197+ @cython.cclass
198+ class GameNonterminalNodes :
199+ """ Represents the set of nodes in a game."""
200+ game = cython.declare(c_Game)
201+
202+ def __init__ (self , *args , **kwargs ) -> None:
203+ raise ValueError("Cannot create GameNonterminalNodes outside a Game.")
204+
205+ @staticmethod
206+ @cython.cfunc
207+ def wrap(game: c_Game ) -> GameNonterminalNodes:
208+ obj: GameNonterminalNodes = GameNonterminalNodes.__new__ (GameNonterminalNodes)
209+ obj.game = game
210+ return obj
211+
212+ def __repr__(self ) -> str:
213+ return f"GameNonterminalNodes(game = {Game.wrap(self .game)})"
214+
215+ def __len__(self ) -> int:
216+ """The number of non-terminal nodes in the game."""
217+ if not self.game.deref().IsTree():
218+ return 0
219+ return self .game.deref().NumNonterminalNodes()
220+
221+ def __iter__ (self ) -> typing.Iterator[Node]:
222+ def dfs(node ):
223+ if not node.is_terminal:
224+ yield node
225+ for child in node.children:
226+ yield from dfs(child)
227+ if not self .game.deref().IsTree():
228+ return
229+ yield from dfs(Node.wrap(self .game.deref().GetRoot()))
230+
231+
197232@cython.cclass
198233class GameOutcomes :
199234 """ Represents the set of outcomes in a game."""
@@ -713,6 +748,15 @@ class Game:
713748 """
714749 return GameNodes.wrap(self.game )
715750
751+ @property
752+ def _nonterminal_nodes(self ) -> GameNonterminalNodes:
753+ """The set of non-terminal nodes in the game.
754+
755+ Iteration over this property yields the non-terminal nodes in the order of depth-first
756+ search.
757+ """
758+ return GameNonterminalNodes.wrap(self.game )
759+
716760 @property
717761 def contingencies(self ) -> pygambit.gameiter.Contingencies:
718762 """An iterator over the contingencies in the game."""
0 commit comments