diff --git a/src/games/game.h b/src/games/game.h index cffffebb74..aba2722b21 100644 --- a/src/games/game.h +++ b/src/games/game.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -663,6 +662,8 @@ class GamePlayerRep : public std::enable_shared_from_this { //@} }; +enum class TraversalOrder { Preorder, Postorder }; + /// A node in an extensive game class GameNodeRep : public std::enable_shared_from_this { friend class GameTreeRep; @@ -888,8 +889,6 @@ class GameSubgameRep : public std::enable_shared_from_this { InfosetCollection GetSubgameDifference() const; }; -enum class TraversalOrder { Preorder, Postorder }; - class CartesianProductSpace { public: std::vector m_radices; @@ -1088,49 +1087,69 @@ class GameRep : public std::enable_shared_from_this { class iterator { friend class Nodes; - struct NodeHandler { - std::queue m_queue; - - static DFSCallbackResult OnEnter(const GameNode &, int) - { - return DFSCallbackResult::Continue; - } - static DFSCallbackResult OnAction(const GameNode &, const GameNode &, int) - { - return DFSCallbackResult::Continue; - } - static DFSCallbackResult OnExit(const GameNode &, int) - { - return DFSCallbackResult::Continue; - } - void OnVisit(const GameNode &p_node, int) { m_queue.push(p_node); } + using ChildIterator = ElementCollection::iterator; + + // One frame per node currently open on the path from the root; this mirrors + // WalkDFS's own stack, but is kept alive across calls to advance() (instead of + // living inside a single call to WalkDFS) so the walk can pause after each node + // and resume from exactly where it left off, rather than visiting the whole tree + // up front. + struct Frame { + GameNode m_node; + ChildIterator m_current; + ChildIterator m_end; + bool m_entered{false}; }; Game m_owner{nullptr}; - std::shared_ptr m_handler; + TraversalOrder m_order{TraversalOrder::Preorder}; + std::stack m_stack; GameNode m_current{nullptr}; - iterator(const Game &p_game, TraversalOrder p_order) - : m_owner(p_game), m_handler(std::make_shared()) + iterator(const Game &p_game, TraversalOrder p_order) : m_owner(p_game), m_order(p_order) { if (!p_game) { m_owner = nullptr; return; } - WalkDFS(p_game, p_game->GetRoot(), p_order, *m_handler); + m_stack.push(Frame{p_game->GetRoot(), {}, {}, false}); advance(); } void advance() { - if (!m_handler || m_handler->m_queue.empty()) { - m_current = nullptr; - m_owner = nullptr; - } - else { - m_current = m_handler->m_queue.front(); - m_handler->m_queue.pop(); + while (!m_stack.empty()) { + Frame &f = m_stack.top(); + + if (!f.m_entered) { + f.m_entered = true; + if (!f.m_node->IsTerminal()) { + auto children = f.m_node->GetChildren(); + f.m_current = children.begin(); + f.m_end = children.end(); + } + if (m_order == TraversalOrder::Preorder) { + m_current = f.m_node; + return; + } + } + + if (!f.m_node->IsTerminal() && f.m_current != f.m_end) { + GameNode const child = *f.m_current; + ++f.m_current; + m_stack.push(Frame{child, {}, {}, false}); + continue; + } + + GameNode const finished = f.m_node; + m_stack.pop(); + if (m_order == TraversalOrder::Postorder) { + m_current = finished; + return; + } } + m_current = nullptr; + m_owner = nullptr; } public: