Skip to content

Commit 229f495

Browse files
committed
Implement collection classes for games.
This implements a new template class, ElementCollection, which represents a collection of objects in a game. This handles efficient access and iteration over game objects without the need to allocate a new container. Closes #516
1 parent 5b7788a commit 229f495

43 files changed

Lines changed: 420 additions & 421 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/games/behavmixed.cc

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -465,29 +465,25 @@ T MixedBehaviorProfile<T>::DiffNodeValue(const GameNode &p_node, const GamePlaye
465465
CheckVersion();
466466
ComputeSolutionData();
467467

468-
if (p_node->NumChildren() > 0) {
469-
const GameInfoset infoset = p_node->GetInfoset();
470-
471-
if (infoset == p_oppAction->GetInfoset()) {
472-
// We've encountered the action; since we assume perfect recall,
473-
// we won't encounter it again, and the downtree value must
474-
// be the same.
475-
return map_nodeValues[p_node->GetChild(p_oppAction)][p_player];
476-
}
477-
else {
478-
T deriv = T(0);
479-
for (auto action : infoset->GetActions()) {
480-
deriv += (DiffNodeValue(p_node->GetChild(action), p_player, p_oppAction) *
481-
GetActionProb(action));
482-
}
483-
return deriv;
484-
}
485-
}
486-
else {
468+
if (p_node->IsTerminal()) {
487469
// If we reach a terminal node and haven't encountered p_oppAction,
488470
// derivative wrt this path is zero.
489471
return T(0);
490472
}
473+
if (p_node->GetInfoset() == p_oppAction->GetInfoset()) {
474+
// We've encountered the action; since we assume perfect recall,
475+
// we won't encounter it again, and the downtree value must
476+
// be the same.
477+
return map_nodeValues[p_node->GetChild(p_oppAction)][p_player];
478+
}
479+
else {
480+
T deriv = T(0);
481+
for (auto action : p_node->GetInfoset()->GetActions()) {
482+
deriv +=
483+
(DiffNodeValue(p_node->GetChild(action), p_player, p_oppAction) * GetActionProb(action));
484+
}
485+
return deriv;
486+
}
491487
}
492488

493489
//========================================================================

src/games/behavmixed.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ MixedBehaviorProfile<Rational> GameRep::NewRandomBehaviorProfile(int p_denom,
244244
auto profile = MixedBehaviorProfile<Rational>(Game(const_cast<GameRep *>(this)));
245245
for (auto player : GetPlayers()) {
246246
for (auto infoset : player->GetInfosets()) {
247-
std::list<Rational> dist = UniformOnSimplex(p_denom, infoset->NumActions(), generator);
247+
std::list<Rational> dist =
248+
UniformOnSimplex(p_denom, infoset->GetActions().size(), generator);
248249
auto prob = dist.cbegin();
249250
for (auto action : infoset->GetActions()) {
250251
profile[action] = *prob;

src/games/file.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ void ParsePayoffBody(GameFileLexer &p_parser, Game &p_nfg)
428428
{
429429
const StrategySupportProfile profile(p_nfg);
430430
for (auto iter : StrategyContingencies(profile)) {
431-
for (auto player : p_nfg->GetPlayers()) {
431+
for (const auto &player : p_nfg->GetPlayers()) {
432432
p_parser.ExpectCurrentToken(TOKEN_NUMBER, "numerical payoff");
433433
iter->GetOutcome()->SetPayoff(player, Number(p_parser.GetLastText()));
434434
p_parser.GetNextToken();

src/games/game.cc

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ namespace Gambit {
4141

4242
GameOutcomeRep::GameOutcomeRep(GameRep *p_game, int p_number) : m_game(p_game), m_number(p_number)
4343
{
44-
for (const auto &player : p_game->GetPlayers()) {
44+
for (const auto &player : m_game->m_players) {
4545
m_payoffs[player] = Number();
4646
}
4747
}
@@ -68,20 +68,11 @@ GamePlayerRep::~GamePlayerRep()
6868
}
6969
}
7070

71-
Array<GameStrategy> GamePlayerRep::GetStrategies() const
72-
{
73-
m_game->BuildComputedValues();
74-
Array<GameStrategy> ret(m_strategies.size());
75-
std::transform(m_strategies.cbegin(), m_strategies.cend(), ret.begin(),
76-
[](const GameStrategyRep *s) -> GameStrategy { return s; });
77-
return ret;
78-
}
79-
8071
void GamePlayerRep::MakeStrategy()
8172
{
82-
Array<int> c(NumInfosets());
73+
Array<int> c(m_infosets.size());
8374

84-
for (size_t i = 1; i <= NumInfosets(); i++) {
75+
for (size_t i = 1; i <= m_infosets.size(); i++) {
8576
if (m_infosets[i - 1]->flag == 1) {
8677
c[i] = m_infosets[i - 1]->whichbranch;
8778
}
@@ -118,12 +109,12 @@ void GamePlayerRep::MakeReducedStrats(GameNodeRep *n, GameNodeRep *nn)
118109
n->ptr = nullptr;
119110
}
120111

121-
if (n->NumChildren() > 0) {
112+
if (!n->IsTerminal()) {
122113
if (n->m_infoset->m_player == this) {
123114
if (n->m_infoset->flag == 0) {
124115
// we haven't visited this infoset before
125116
n->m_infoset->flag = 1;
126-
for (size_t i = 1; i <= n->NumChildren(); i++) {
117+
for (size_t i = 1; i <= n->m_children.size(); i++) {
127118
GameNodeRep *m = n->m_children[i - 1];
128119
n->whichbranch = m;
129120
n->m_infoset->whichbranch = i;
@@ -175,52 +166,19 @@ void GamePlayerRep::MakeReducedStrats(GameNodeRep *n, GameNodeRep *nn)
175166
}
176167
}
177168

178-
GameInfoset GamePlayerRep::GetInfoset(int p_index) const { return m_infosets[p_index - 1]; }
179-
180-
Array<GameInfoset> GamePlayerRep::GetInfosets() const
181-
{
182-
Array<GameInfoset> ret(m_infosets.size());
183-
std::transform(m_infosets.cbegin(), m_infosets.cend(), ret.begin(),
184-
[](const GameInfosetRep *s) -> GameInfoset { return s; });
185-
return ret;
186-
}
187-
188169
size_t GamePlayerRep::NumSequences() const
189170
{
190171
if (!m_game->IsTree()) {
191172
throw UndefinedException();
192173
}
193-
return std::accumulate(
194-
m_infosets.cbegin(), m_infosets.cend(), 1,
195-
[](int ct, const GameInfosetRep *s) -> int { return ct + s->m_actions.size(); });
174+
return std::transform_reduce(m_infosets.cbegin(), m_infosets.cend(), 1, std::plus<>(),
175+
[](const GameInfosetRep *s) { return s->m_actions.size(); });
196176
}
197177

198178
//========================================================================
199179
// class GameRep
200180
//========================================================================
201181

202-
Array<GamePlayer> GameRep::GetPlayers() const
203-
{
204-
Array<GamePlayer> ret(NumPlayers());
205-
for (size_t pl = 1; pl <= NumPlayers(); pl++) {
206-
ret[pl] = GetPlayer(pl);
207-
}
208-
return ret;
209-
}
210-
211-
Array<GameStrategy> GameRep::GetStrategies() const
212-
{
213-
Array<GameStrategy> ret(MixedProfileLength());
214-
auto output = ret.begin();
215-
for (auto player : GetPlayers()) {
216-
for (auto strategy : player->GetStrategies()) {
217-
*output = strategy;
218-
++output;
219-
}
220-
}
221-
return ret;
222-
}
223-
224182
GameRep::~GameRep()
225183
{
226184
for (auto player : m_players) {

0 commit comments

Comments
 (0)