@@ -388,6 +388,18 @@ bool GameNodeRep::IsSubgameRoot() const
388388 return true ;
389389}
390390
391+ bool GameNodeRep::IsStrategyReachable () const
392+ {
393+ auto tree_game = static_cast <GameTreeRep *>(m_game);
394+
395+ if (!tree_game->m_unreachableNodes ) {
396+ tree_game->BuildInfosetParents ();
397+ }
398+
399+ // A node is reachable if it is NOT in the set of unreachable nodes.
400+ return !contains (*tree_game->m_unreachableNodes , const_cast <GameNodeRep *>(this ));
401+ }
402+
391403void GameTreeRep::DeleteParent (GameNode p_node)
392404{
393405 if (p_node->m_game != this ) {
@@ -800,6 +812,7 @@ void GameTreeRep::ClearComputedValues() const
800812 }
801813 const_cast <GameTreeRep *>(this )->m_nodePlays .clear ();
802814 const_cast <GameTreeRep *>(this )->m_infosetParents .clear ();
815+ const_cast <GameTreeRep *>(this )->m_unreachableNodes = nullptr ;
803816 m_computedValues = false ;
804817}
805818
@@ -842,6 +855,9 @@ std::vector<GameNodeRep *> GameTreeRep::BuildConsistentPlaysRecursiveImpl(GameNo
842855
843856void GameTreeRep::BuildInfosetParents ()
844857{
858+ m_infosetParents.clear ();
859+ m_unreachableNodes = std::make_unique<std::set<GameNodeRep *>>();
860+
845861 if (m_root->IsTerminal ()) {
846862 m_infosetParents[m_root->m_infoset ].insert (nullptr );
847863 return ;
@@ -893,7 +909,6 @@ void GameTreeRep::BuildInfosetParents()
893909 }
894910
895911 prior_actions.at (node->m_infoset ->m_player ->shared_from_this ()).top () = action;
896-
897912 if (!child->IsTerminal ()) {
898913 auto child_player = child->m_infoset ->m_player ->shared_from_this ();
899914 auto prior_action = prior_actions.at (child_player).top ();
@@ -902,6 +917,26 @@ void GameTreeRep::BuildInfosetParents()
902917 if (path_choices.find (child->m_infoset ->shared_from_this ()) != path_choices.end ()) {
903918 const GameAction replay_action = path_choices.at (child->m_infoset ->shared_from_this ());
904919 position.emplace (AbsentMindedEdge{replay_action, child});
920+
921+ // Start of the traversal of unreachable subtrees
922+ for (const auto &[current_action, subtree_root] : child->GetActions ()) {
923+ if (current_action != replay_action) {
924+
925+ std::stack<GameNodeRep *> nodes_to_visit;
926+ nodes_to_visit.push (subtree_root.get ());
927+
928+ while (!nodes_to_visit.empty ()) {
929+ GameNodeRep *current_unreachable_node = nodes_to_visit.top ();
930+ nodes_to_visit.pop ();
931+ m_unreachableNodes->insert (current_unreachable_node);
932+
933+ for (const auto &unreachable_child : current_unreachable_node->GetChildren ()) {
934+ nodes_to_visit.push (unreachable_child.get ());
935+ }
936+ }
937+ }
938+ }
939+ // End of the traversal of unreachable subtrees
905940 }
906941 else {
907942 position.emplace (child->GetActions ().begin ());
0 commit comments