@@ -597,6 +597,8 @@ inline GameNodeRep::Actions::iterator::iterator(GameInfosetRep::Actions::iterato
597597
598598inline GameNode GameNodeRep::Actions::iterator::GetOwner () const { return m_child_it.GetOwner (); }
599599
600+ enum class TraversalOrder { Preorder, Postorder };
601+
600602// / This is the class for representing an arbitrary finite game.
601603class GameRep : public std ::enable_shared_from_this<GameRep> {
602604 friend class GameOutcomeRep ;
@@ -627,85 +629,147 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
627629
628630 class Nodes {
629631 Game m_owner{nullptr };
632+ TraversalOrder m_order{TraversalOrder::Preorder};
630633
631634 public:
632635 class iterator {
633636 friend class Nodes ;
634- using ChildIterator = ElementCollection<GameNode, GameNodeRep>::iterator;
635637
636- Game m_owner{nullptr };
637- GameNode m_current_node{nullptr };
638- std::stack<std::pair<ChildIterator, ChildIterator>> m_stack{};
638+ using ChildIterator = ElementCollection<GameNode, GameNodeRep>::iterator;
639639
640- iterator (const Game &game) : m_owner(game) {}
640+ struct Frame {
641+ GameNode m_node;
642+ ChildIterator m_current, m_end;
643+ bool m_expanded = false ;
644+ };
641645
642- public:
643- using iterator_category = std::forward_iterator_tag;
644- using value_type = GameNode;
645- using pointer = value_type *;
646-
647- iterator () = default ;
646+ Game m_owner{nullptr };
647+ TraversalOrder m_order{TraversalOrder::Preorder};
648+ std::stack<Frame> m_stack{};
649+ GameNode m_current{nullptr };
648650
649- iterator (const Game &game , const GameNode &start_node )
650- : m_owner(game ), m_current_node(start_node )
651+ iterator (const Game &p_game , const GameNode &p_start, const TraversalOrder p_order )
652+ : m_owner(p_game ), m_order(p_order )
651653 {
652- if (!start_node ) {
654+ if (!p_start ) {
653655 return ;
654656 }
655- if (start_node ->GetGame () != m_owner ) {
657+ if (p_start ->GetGame () != p_game ) {
656658 throw MismatchException ();
657659 }
660+ m_stack.push (make_frame (p_start));
661+ if (m_order == TraversalOrder::Preorder) {
662+ m_current = p_start;
663+ }
664+ else {
665+ descend_postorder ();
666+ m_current = m_stack.empty () ? nullptr : m_stack.top ().m_node ;
667+ }
668+ if (!m_current) {
669+ m_owner = nullptr ;
670+ }
658671 }
659672
660- value_type operator *() const
673+ static Frame make_frame ( const GameNode &p_node)
661674 {
662- if (!m_current_node ) {
663- throw std::runtime_error ( " Cannot dereference an end iterator " ) ;
675+ if (p_node-> IsTerminal () ) {
676+ return Frame{p_node, {}, {}, true } ;
664677 }
665- return m_current_node;
678+ const auto children = p_node->GetChildren ();
679+ return Frame{p_node, children.begin (), children.end (), false };
666680 }
667681
668- iterator & operator ++ ()
682+ void descend_postorder ()
669683 {
670- if (!m_current_node) {
671- throw std::out_of_range (" Cannot increment an end iterator" );
684+ while (!m_stack.empty ()) {
685+ auto &f = m_stack.top ();
686+ if (f.m_expanded || f.m_current == f.m_end ) {
687+ return ;
688+ }
689+ f.m_expanded = true ;
690+ const GameNode child = *f.m_current ;
691+ ++f.m_current ;
692+ m_stack.push (make_frame (child));
672693 }
694+ }
673695
674- if (!m_current_node->IsTerminal ()) {
675- auto children = m_current_node->GetChildren ();
676- m_stack.emplace (children.begin (), children.end ());
696+ GameNode advance_preorder ()
697+ {
698+ if (auto &top = m_stack.top (); !top.m_node ->IsTerminal ()) {
699+ const auto children = top.m_node ->GetChildren ();
700+ top.m_current = children.begin ();
701+ top.m_end = children.end ();
677702 }
678-
679703 while (!m_stack.empty ()) {
680- auto &[current_it, end_it] = m_stack.top ();
681-
682- if (current_it != end_it) {
683- m_current_node = *current_it;
684- ++current_it;
685- return *this ;
704+ if (auto &f = m_stack.top (); f.m_current != f.m_end ) {
705+ GameNode const next = *f.m_current ;
706+ ++f.m_current ;
707+ m_stack.push (make_frame (next));
708+ return next;
686709 }
687710 m_stack.pop ();
688711 }
712+ return nullptr ;
713+ }
689714
690- m_current_node = nullptr ;
715+ GameNode advance_postorder ()
716+ {
717+ m_stack.pop ();
718+ if (m_stack.empty ()) {
719+ return nullptr ;
720+ }
721+ descend_postorder ();
722+ return m_stack.empty () ? nullptr : m_stack.top ().m_node ;
723+ }
724+
725+ public:
726+ using iterator_category = std::input_iterator_tag;
727+ using value_type = GameNode;
728+
729+ iterator () = default ;
730+ iterator (const iterator &) = default ;
731+ iterator &operator =(const iterator &) = default ;
732+
733+ value_type operator *() const
734+ {
735+ if (!m_current) {
736+ throw std::runtime_error (" Dereferencing end iterator" );
737+ }
738+ return m_current;
739+ }
740+
741+ iterator &operator ++()
742+ {
743+ if (!m_current) {
744+ return *this ;
745+ }
746+ const GameNode next =
747+ (m_order == TraversalOrder::Preorder) ? advance_preorder () : advance_postorder ();
748+ m_current = next;
749+ if (!m_current) {
750+ m_owner = nullptr ;
751+ }
691752 return *this ;
692753 }
693754
694- bool operator ==(const iterator &other ) const
755+ bool operator ==(const iterator &p_other ) const
695756 {
696- return m_owner == other .m_owner && m_current_node == other. m_current_node ;
757+ return m_owner == p_other .m_owner && m_current == p_other. m_current ;
697758 }
698- bool operator !=(const iterator &other ) const { return !(*this == other ); }
759+ bool operator !=(const iterator &p_other ) const { return !(*this == p_other ); }
699760 };
700761
701762 Nodes () = default ;
702- explicit Nodes (const Game &p_owner) : m_owner(p_owner) {}
763+ Nodes (const Game &p_owner, const TraversalOrder p_order = TraversalOrder::Preorder)
764+ : m_owner(p_owner), m_order(p_order)
765+ {
766+ }
703767
704768 iterator begin () const
705769 {
706- return (m_owner) ? iterator{m_owner, m_owner->GetRoot ()} : iterator{};
770+ return (m_owner) ? iterator{m_owner, m_owner->GetRoot (), m_order } : iterator{};
707771 }
708- iterator end () const { return (m_owner) ? iterator{m_owner} : iterator{}; }
772+ static iterator end () { return iterator{}; }
709773 };
710774
711775 // / @name Lifecycle
@@ -937,7 +1001,7 @@ class GameRep : public std::enable_shared_from_this<GameRep> {
9371001 // / Returns the root node of the game
9381002 virtual GameNode GetRoot () const = 0;
9391003 // / Returns a range that can be used to iterate over the nodes of the game
940- Nodes GetNodes () const { return Nodes ( std::const_pointer_cast<GameRep>(shared_from_this ())) ; }
1004+ Nodes GetNodes () const { return { std::const_pointer_cast<GameRep>(shared_from_this ())} ; }
9411005 // / Returns the number of nodes in the game
9421006 virtual size_t NumNodes () const = 0;
9431007 // / Returns the number of non-terminal nodes in the game
0 commit comments