Skip to content

Commit 6ef5d57

Browse files
committed
Rationalise implementation of outcome objects
This performs some outstanding rationalisation of `GameObjectRep` objects: * Removes indexing of payoffs by player index * Templates `GetPayoff` to obtain payoffs directly in the desired representation * Store payoffs using a `std::map` instead of `Array`. Closes #490.
1 parent 70ee889 commit 6ef5d57

20 files changed

Lines changed: 68 additions & 64 deletions

src/games/behavmixed.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ void MixedBehaviorProfile<T>::GetPayoff(const GameNode &node, const T &prob,
381381
const GamePlayer &player, T &value) const
382382
{
383383
if (node->GetOutcome()) {
384-
value += prob * static_cast<T>(node->GetOutcome()->GetPayoff(player));
384+
value += prob * node->GetOutcome()->GetPayoff<T>(player);
385385
}
386386

387387
if (!node->IsTerminal()) {
@@ -520,7 +520,7 @@ void MixedBehaviorProfile<T>::ComputePass2_beliefs_nodeValues_actionValues(
520520
if (node->GetOutcome()) {
521521
GameOutcome outcome = node->GetOutcome();
522522
for (auto player : m_support.GetGame()->GetPlayers()) {
523-
map_nodeValues[node][player] += static_cast<T>(outcome->GetPayoff(player));
523+
map_nodeValues[node][player] += outcome->GetPayoff<T>(player);
524524
}
525525
}
526526

src/games/behavpure.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ T PureBehaviorProfile::GetPayoff(const GameNode &p_node, const GamePlayer &p_pla
4949
T payoff(0);
5050

5151
if (p_node->GetOutcome()) {
52-
payoff += static_cast<T>(p_node->GetOutcome()->GetPayoff(p_player));
52+
payoff += p_node->GetOutcome()->GetPayoff<T>(p_player);
5353
}
5454

5555
if (!p_node->IsTerminal()) {

src/games/game.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ namespace Gambit {
4141
// class GameOutcomeRep
4242
//========================================================================
4343

44-
GameOutcomeRep::GameOutcomeRep(GameRep *p_game, int p_number)
45-
: m_game(p_game), m_number(p_number), m_payoffs(m_game->NumPlayers())
44+
GameOutcomeRep::GameOutcomeRep(GameRep *p_game, int p_number) : m_game(p_game), m_number(p_number)
4645
{
46+
for (const auto &player : p_game->GetPlayers()) {
47+
m_payoffs[player] = Number();
48+
}
4749
}
4850

4951
//========================================================================

src/games/game.h

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class GameOutcomeRep : public GameObject {
121121
GameRep *m_game;
122122
int m_number;
123123
std::string m_label;
124-
Array<Number> m_payoffs;
124+
std::map<GamePlayerRep *, Number> m_payoffs;
125125

126126
/// @name Lifecycle
127127
//@{
@@ -143,12 +143,8 @@ class GameOutcomeRep : public GameObject {
143143
/// Sets the text label associated with the outcome
144144
void SetLabel(const std::string &p_label) { m_label = p_label; }
145145

146-
/// Gets the payoff associated with the outcome to player 'pl'
147-
const Number &GetPayoff(int pl) const { return m_payoffs[pl]; }
148146
/// Gets the payoff associated with the outcome to the player
149-
const Number &GetPayoff(const GamePlayer &p_player) const;
150-
/// Sets the payoff to player 'pl'
151-
void SetPayoff(int pl, const Number &p_value);
147+
template <class T> const T &GetPayoff(const GamePlayer &p_player) const;
152148
/// Sets the payoff to the player
153149
void SetPayoff(const GamePlayer &p_player, const Number &p_value);
154150
//@}
@@ -586,27 +582,34 @@ class GameRep : public BaseGameRep {
586582
// all classes to be defined.
587583

588584
inline Game GameOutcomeRep::GetGame() const { return m_game; }
589-
inline const Number &GameOutcomeRep::GetPayoff(const GamePlayer &p_player) const
585+
586+
template <class T> const T &GameOutcomeRep::GetPayoff(const GamePlayer &p_player) const
590587
{
591-
if (p_player->GetGame() != GetGame()) {
588+
try {
589+
return static_cast<const T &>(m_payoffs.at(p_player));
590+
}
591+
catch (const std::out_of_range &) {
592592
throw MismatchException();
593593
}
594-
return m_payoffs[p_player->GetNumber()];
595594
}
596595

597-
inline void GameOutcomeRep::SetPayoff(int pl, const Number &p_value)
596+
template <> inline const Number &GameOutcomeRep::GetPayoff(const GamePlayer &p_player) const
598597
{
599-
m_game->IncrementVersion();
600-
m_payoffs[pl] = p_value;
598+
try {
599+
return m_payoffs.at(p_player);
600+
}
601+
catch (const std::out_of_range &) {
602+
throw MismatchException();
603+
}
601604
}
602605

603606
inline void GameOutcomeRep::SetPayoff(const GamePlayer &p_player, const Number &p_value)
604607
{
605608
if (p_player->GetGame() != GetGame()) {
606609
throw MismatchException();
607610
}
611+
m_payoffs[p_player] = p_value;
608612
m_game->IncrementVersion();
609-
m_payoffs[p_player->GetNumber()] = p_value;
610613
}
611614

612615
inline GamePlayer GameStrategyRep::GetPlayer() const { return m_player; }

src/games/gameexpl.cc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ Rational GameExplicitRep::GetMinPayoff(int player) const
6666
p2 = NumPlayers();
6767
}
6868

69-
Rational minpay = static_cast<Rational>(m_outcomes.front()->GetPayoff(p1));
69+
Rational minpay = m_outcomes.front()->GetPayoff<Rational>(GetPlayer(p1));
7070
for (auto outcome : m_outcomes) {
7171
for (int p = p1; p <= p2; p++) {
72-
minpay = std::min(minpay, static_cast<Rational>(outcome->GetPayoff(p)));
72+
minpay = std::min(minpay, outcome->GetPayoff<Rational>(GetPlayer(p)));
7373
}
7474
}
7575
return minpay;
@@ -91,10 +91,10 @@ Rational GameExplicitRep::GetMaxPayoff(int player) const
9191
p2 = NumPlayers();
9292
}
9393

94-
Rational maxpay = static_cast<Rational>(m_outcomes.front()->GetPayoff(p1));
94+
Rational maxpay = m_outcomes.front()->GetPayoff<Rational>(GetPlayer(p1));
9595
for (auto outcome : m_outcomes) {
9696
for (int p = p1; p <= p2; p++) {
97-
maxpay = std::max(maxpay, static_cast<Rational>(outcome->GetPayoff(p)));
97+
maxpay = std::max(maxpay, outcome->GetPayoff<Rational>(GetPlayer(p)));
9898
}
9999
}
100100
return maxpay;

src/games/gametable.cc

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Rational TablePureStrategyProfileRep::GetPayoff(const GamePlayer &p_player) cons
9393
{
9494
GameOutcomeRep *outcome = dynamic_cast<GameTableRep &>(*m_nfg).m_results[m_index];
9595
if (outcome) {
96-
return static_cast<Rational>(outcome->GetPayoff(p_player));
96+
return outcome->GetPayoff<Rational>(p_player);
9797
}
9898
else {
9999
return Rational(0);
@@ -102,13 +102,12 @@ Rational TablePureStrategyProfileRep::GetPayoff(const GamePlayer &p_player) cons
102102

103103
Rational TablePureStrategyProfileRep::GetStrategyValue(const GameStrategy &p_strategy) const
104104
{
105-
int player = p_strategy->GetPlayer()->GetNumber();
105+
const auto &player = p_strategy->GetPlayer();
106106
GameOutcomeRep *outcome =
107107
dynamic_cast<GameTableRep &>(*m_nfg)
108-
.m_results[m_index - m_profile.at(p_strategy->GetPlayer())->m_offset +
109-
p_strategy->m_offset];
108+
.m_results[m_index - m_profile.at(player)->m_offset + p_strategy->m_offset];
110109
if (outcome) {
111-
return static_cast<Rational>(outcome->GetPayoff(player));
110+
return outcome->GetPayoff<Rational>(player);
112111
}
113112
else {
114113
return Rational(0);
@@ -164,7 +163,7 @@ T TableMixedStrategyProfileRep<T>::GetPayoff(int pl, int index, int current) con
164163
auto &g = dynamic_cast<GameTableRep &>(*game);
165164
GameOutcomeRep *outcome = g.m_results[index];
166165
if (outcome) {
167-
return static_cast<T>(outcome->GetPayoff(pl));
166+
return outcome->GetPayoff<T>(this->m_support.GetGame()->GetPlayer(pl));
168167
}
169168
else {
170169
return T(0);
@@ -197,7 +196,7 @@ void TableMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, int const_pl, int c
197196
auto &g = dynamic_cast<GameTableRep &>(*game);
198197
GameOutcomeRep *outcome = g.m_results[index];
199198
if (outcome) {
200-
value += prob * static_cast<T>(outcome->GetPayoff(pl));
199+
value += prob * outcome->GetPayoff<T>(this->m_support.GetGame()->GetPlayer(pl));
201200
}
202201
}
203202
else {
@@ -230,7 +229,7 @@ void TableMixedStrategyProfileRep<T>::GetPayoffDeriv(int pl, int const_pl1, int
230229
auto &g = dynamic_cast<GameTableRep &>(*game);
231230
GameOutcomeRep *outcome = g.m_results[index];
232231
if (outcome) {
233-
value += prob * static_cast<T>(outcome->GetPayoff(pl));
232+
value += prob * outcome->GetPayoff<T>(this->m_support.GetGame()->GetPlayer(pl));
234233
}
235234
}
236235
else {
@@ -371,7 +370,7 @@ void GameTableRep::WriteNfgFile(std::ostream &p_file) const
371370
p_file << "{ " + QuoteString(outcome->GetLabel()) << ' '
372371
<< FormatList(
373372
players,
374-
[outcome](const GamePlayer &p) { return std::string(outcome->GetPayoff(p)); },
373+
[outcome](const GamePlayer &p) { return outcome->GetPayoff<std::string>(p); },
375374
true, false)
376375
<< " }" << std::endl;
377376
}
@@ -393,7 +392,7 @@ GamePlayer GameTableRep::NewPlayer()
393392
auto player = new GamePlayerRep(this, m_players.size() + 1, 1);
394393
m_players.push_back(player);
395394
for (auto outcome : m_outcomes) {
396-
outcome->m_payoffs.push_back(Number());
395+
outcome->m_payoffs[player] = Number();
397396
}
398397
return player;
399398
}

src/games/gametree.cc

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,8 @@ Rational SubtreeSum(const GameNode &p_node)
720720
}
721721

722722
if (p_node->GetOutcome()) {
723-
for (int pl = 1; pl <= p_node->GetGame()->NumPlayers(); pl++) {
724-
sum += static_cast<Rational>(p_node->GetOutcome()->GetPayoff(pl));
723+
for (const auto &player : p_node->GetGame()->GetPlayers()) {
724+
sum += p_node->GetOutcome()->GetPayoff<Rational>(player);
725725
}
726726
}
727727
return sum;
@@ -916,7 +916,7 @@ void WriteEfgFile(std::ostream &f, const GameNode &n)
916916
f << n->GetOutcome()->GetNumber() << " " << QuoteString(n->GetOutcome()->GetLabel()) << ' '
917917
<< FormatList(
918918
n->GetGame()->GetPlayers(),
919-
[n](const GamePlayer &p) { return std::string(n->GetOutcome()->GetPayoff(p)); }, true)
919+
[n](const GamePlayer &p) { return n->GetOutcome()->GetPayoff<std::string>(p); }, true)
920920
<< std::endl;
921921
}
922922
else {
@@ -968,11 +968,10 @@ int GameTreeRep::BehavProfileLength() const
968968
GamePlayer GameTreeRep::NewPlayer()
969969
{
970970
IncrementVersion();
971-
GamePlayerRep *player = nullptr;
972-
player = new GamePlayerRep(this, m_players.size() + 1);
971+
auto player = new GamePlayerRep(this, m_players.size() + 1);
973972
m_players.push_back(player);
974973
for (auto &outcome : m_outcomes) {
975-
outcome->m_payoffs.push_back(Number());
974+
outcome->m_payoffs[player] = Number();
976975
}
977976
ClearComputedValues();
978977
return player;

src/games/nash.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ template <class T> class SubgameSolution {
103103
for (const auto &player : p_subroot->GetGame()->GetPlayers()) {
104104
T value = p_profile.GetPayoff(*subplayer);
105105
if (outcome) {
106-
value += static_cast<T>(outcome->GetPayoff(*subplayer));
106+
value += outcome->GetPayoff<T>(*subplayer);
107107
}
108108
solution.node_values[p_subroot]->SetPayoff(player, Number(static_cast<Rational>(value)));
109109
++subplayer;

src/games/writer.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ std::string WriteHTMLFile(const Game &p_game, const GamePlayer &p_rowPlayer,
7070
for (const auto &player : p_game->GetPlayers()) {
7171
try {
7272
if (profile->GetOutcome()) {
73-
theHtml += static_cast<std::string>(profile->GetOutcome()->GetPayoff(player));
73+
theHtml += profile->GetOutcome()->GetPayoff<std::string>(player);
7474
}
7575
else {
7676
theHtml += "0";
@@ -148,7 +148,7 @@ std::string WriteLaTeXFile(const Game &p_game, const GamePlayer &p_rowPlayer,
148148
for (const auto &player : p_game->GetPlayers()) {
149149
try {
150150
if (profile->GetOutcome()) {
151-
theHtml += static_cast<std::string>(profile->GetOutcome()->GetPayoff(player));
151+
theHtml += profile->GetOutcome()->GetPayoff<std::string>(player);
152152
}
153153
else {
154154
theHtml += "0";

src/gui/dleditnode.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ dialogEditNode::dialogEditNode(wxWindow *p_parent, const Gambit::GameNode &p_nod
114114
item = "Outcome" + Gambit::lexical_cast<std::string>(outc);
115115
}
116116

117-
item += (" (" + static_cast<std::string>(outcome->GetPayoff(1)) + ", " +
118-
static_cast<std::string>(outcome->GetPayoff(2)));
117+
item += (" (" + outcome->GetPayoff<std::string>(efg->GetPlayer(1)) + ", " +
118+
outcome->GetPayoff<std::string>(efg->GetPlayer(2)));
119119
if (efg->NumPlayers() > 2) {
120-
item += ", " + static_cast<std::string>(outcome->GetPayoff(3));
120+
item += ", " + outcome->GetPayoff<std::string>(efg->GetPlayer(3));
121121
if (efg->NumPlayers() > 3) {
122122
item += ",...)";
123123
}

0 commit comments

Comments
 (0)