Plays consistent with a node
An interesting quantity, until now not offered directly, is the set of plays of a game that are consistent with a given node in a game tree. Because at present we support only trees (as opposed to more general graphs), a "play" of a game is equivalent to a terminal node of the game.
For this issue we will add the following:
- In C++, implement a function
std::vector<GameNode> GameRep::GetPlays(GameNode node) const, which will return the set of terminal nodes which are descendants of node.
Internally we will make an initial implementation as follows:
- To
GameTreeRep add a data member std::map<GameNodeRep *, std::vector<GameNodeRep *>> m_nodePlays. m_nodePlays.at(node) returns the vector of terminal nodes which follow node.
- To
BuildComputedValues(), clear m_nodePlays and then traverse the tree one time, building this map. By definition each terminal node's vector of plays will be a singleton vector; each nonterminal node's vector of plays will be the catenation of those of its immediate children.
ClearComputedValues() will clear m_nodePlays.
GetPlays(node) will generate the std::vector<GameNode> via the usual std::copy approach used elsewhere in similar functions.
When calling GetPlays() (and the below) we will need to call BuildComputedValues() to ensure the cached data is present.
Plays consistent with an information set
Once we have the above, we can also define the set of plays consistent with an information set:
In C++, implement a function std::vector<GameNode> GameRep::GetPlays(GameInfoset infoset) const. This can be implemented most straightforwardly by creating a vector that catenates the plays associated with the information set's member nodes.
Plays consistent with an action
Finally, we can define the plays consistent with an action as the terminal nodes which follow an action in the tree.
In C++, implement a function std::vector<GameNode> GameRep::GetPlays(GameAction action) const. Again, this can be implemented as an explicit catenation: iterate over members of the information set, for that member find the child node that follows action, and take the plays associated with that child as part of the output.
Python implementation
These will be exposed in Python as Game.get_plays(obj), where obj can be any of Node, Infoset, or Action as appropriate, and call the appropriate C++ function.
Testing, documentation, optimisation
This will give us enough to create an appropriate test suite to confirm this all is working correctly. Appropriate docstrings and updates to the documentation should be included.
This first implementation is straightforward but patently not efficient. The focus in this sub-issue is defining the relevant concepts and functions and having a test suite in place. We will use that in subsequent work for implementing more efficient and scalable implementations.
Plays consistent with a node
An interesting quantity, until now not offered directly, is the set of plays of a game that are consistent with a given node in a game tree. Because at present we support only trees (as opposed to more general graphs), a "play" of a game is equivalent to a terminal node of the game.
For this issue we will add the following:
std::vector<GameNode> GameRep::GetPlays(GameNode node) const, which will return the set of terminal nodes which are descendants ofnode.Internally we will make an initial implementation as follows:
GameTreeRepadd a data memberstd::map<GameNodeRep *, std::vector<GameNodeRep *>> m_nodePlays.m_nodePlays.at(node)returns the vector of terminal nodes which follownode.BuildComputedValues(), clearm_nodePlaysand then traverse the tree one time, building this map. By definition each terminal node's vector of plays will be a singleton vector; each nonterminal node's vector of plays will be the catenation of those of its immediate children.ClearComputedValues()will clearm_nodePlays.GetPlays(node)will generate thestd::vector<GameNode>via the usualstd::copyapproach used elsewhere in similar functions.When calling
GetPlays()(and the below) we will need to callBuildComputedValues()to ensure the cached data is present.Plays consistent with an information set
Once we have the above, we can also define the set of plays consistent with an information set:
In C++, implement a function
std::vector<GameNode> GameRep::GetPlays(GameInfoset infoset) const. This can be implemented most straightforwardly by creating a vector that catenates the plays associated with the information set's member nodes.Plays consistent with an action
Finally, we can define the plays consistent with an action as the terminal nodes which follow an action in the tree.
In C++, implement a function
std::vector<GameNode> GameRep::GetPlays(GameAction action) const. Again, this can be implemented as an explicit catenation: iterate over members of the information set, for that member find the child node that followsaction, and take the plays associated with that child as part of the output.Python implementation
These will be exposed in Python as
Game.get_plays(obj), whereobjcan be any ofNode,Infoset, orActionas appropriate, and call the appropriate C++ function.Testing, documentation, optimisation
This will give us enough to create an appropriate test suite to confirm this all is working correctly. Appropriate docstrings and updates to the documentation should be included.
This first implementation is straightforward but patently not efficient. The focus in this sub-issue is defining the relevant concepts and functions and having a test suite in place. We will use that in subsequent work for implementing more efficient and scalable implementations.