Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
### Changed
- All long-running calculations are now done in a thread in the GUI process, rather than calling the
command-line executables as external processes. (#990)
- When displaying a strategic form, the graphical interface preserves decimal payoffs when those are
what are specified in the game, whenever possible. (#867)

### Removed
- Assigning to `Strategy.label` has been removed; use `Game.relabel_strategies`, which enforces
Expand Down
23 changes: 23 additions & 0 deletions src/games/behavpure.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,29 @@ T PureBehaviorProfile::GetPayoff(const GameNode &p_node, const GamePlayer &p_pla
template double PureBehaviorProfile::GetPayoff(const GameNode &, const GamePlayer &) const;
template Rational PureBehaviorProfile::GetPayoff(const GameNode &, const GamePlayer &) const;

GameOutcome PureBehaviorProfile::GetOutcome(const GameNode &p_start) const
{
GameOutcome outcome;
GameNode node = p_start;
while (true) {
if (node->GetOutcome()) {
if (outcome) {
// More than one outcome-bearing node along this path; the combined
// payoff cannot be attributed to a single outcome's preserved text.
throw UndefinedException();
}
outcome = node->GetOutcome();
}
if (node->IsTerminal()) {
return outcome;
}
if (node->GetInfoset()->IsChanceInfoset()) {
throw UndefinedException();
}
node = node->GetChild(m_profile.at(node->GetInfoset()));
}
}

MixedBehaviorProfile<Rational> PureBehaviorProfile::ToMixedBehaviorProfile() const
{
MixedBehaviorProfile<Rational> temp(m_efg);
Expand Down
7 changes: 7 additions & 0 deletions src/games/behavpure.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ class PureBehaviorProfile {
/// Get the payoff to the player, conditional on reaching a node
template <class T> T GetPayoff(const GameNode &, const GamePlayer &) const;

/// Get the outcome that results from the profile, provided this can be
/// determined without resolving a chance move and without combining more
/// than one outcome along the induced path; throws UndefinedException otherwise.
GameOutcome GetOutcome() const { return GetOutcome(m_efg->GetRoot()); }
/// Get the outcome that results from the profile, conditional on reaching a node
GameOutcome GetOutcome(const GameNode &) const;

/// Convert to a mixed behavior representation
MixedBehaviorProfile<Rational> ToMixedBehaviorProfile() const;
//@}
Expand Down
35 changes: 23 additions & 12 deletions src/games/gametree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1921,9 +1921,25 @@ class TreePureStrategyProfileRep : public PureStrategyProfileRep {
return std::make_shared<TreePureStrategyProfileRep>(*this);
}

/// Build the behavior profile induced by this pure strategy profile
PureBehaviorProfile GetBehaviorProfile() const
{
PureBehaviorProfile behav(m_game);
for (const auto &player : m_game->GetPlayers()) {
for (const auto &infoset : player->GetInfosets()) {
try {
behav.SetAction(infoset->GetAction(GetStrategy(player)->m_behav.at(infoset.get())));
}
catch (std::out_of_range &) {
}
}
}
return behav;
}

public:
TreePureStrategyProfileRep(const Game &p_game) : PureStrategyProfileRep(p_game) {}
GameOutcome GetOutcome() const override { throw UndefinedException(); }
GameOutcome GetOutcome() const override;
void SetOutcome(GameOutcome p_outcome) override { throw UndefinedException(); }
Rational GetPayoff(const GamePlayer &) const override;
Rational GetStrategyValue(const GameStrategy &) const override;
Expand All @@ -1944,19 +1960,14 @@ PureStrategyProfile GameTreeRep::NewPureStrategyProfile() const
// TreePureStrategyProfileRep: Data access and manipulation
//------------------------------------------------------------------------

GameOutcome TreePureStrategyProfileRep::GetOutcome() const
{
return GetBehaviorProfile().GetOutcome();
}

Rational TreePureStrategyProfileRep::GetPayoff(const GamePlayer &p_player) const
{
PureBehaviorProfile behav(m_game);
for (const auto &player : m_game->GetPlayers()) {
for (const auto &infoset : player->GetInfosets()) {
try {
behav.SetAction(infoset->GetAction(GetStrategy(player)->m_behav.at(infoset.get())));
}
catch (std::out_of_range &) {
}
}
}
return behav.GetPayoff<Rational>(p_player);
return GetBehaviorProfile().GetPayoff<Rational>(p_player);
}

Rational TreePureStrategyProfileRep::GetStrategyValue(const GameStrategy &p_strategy) const
Expand Down
12 changes: 10 additions & 2 deletions src/gui/nfgtable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1010,8 +1010,16 @@ class PayoffTable final : public wxGridTableBase {
wxString PayoffTable::GetValue(int row, int col)
{
const PureStrategyProfile profile = m_table->GetPayoffProfile(row, col);
auto player = m_table->GetPayoffPlayer(col);
return wxString::FromUTF8(lexical_cast<std::string>(profile->GetPayoff(player)));
const auto player = m_table->GetPayoffPlayer(col);
try {
if (const auto outcome = profile->GetOutcome()) {
return wxString::FromUTF8(outcome->GetPayoff<std::string>(player));
}
return wxString::FromUTF8("0");
}
catch (const UndefinedException &) {
return wxString::FromUTF8(lexical_cast<std::string>(profile->GetPayoff(player)));
}
}

void PayoffTable::SetValue(int row, int col, const wxString &value)
Expand Down