Skip to content
Draft
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: 1 addition & 1 deletion doc/gui.efg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ To select the font used to draw the labels in the tree, select
:menuselection:`Format --> Font`.
The standard font selection dialog for the operating
system is displayed, showing the fonts available on the system. Since
available fonts vary across systems, when opening a workbook on a
available fonts vary across systems, when opening a workspace on a
system different from the system on which it was saved, Gambit tries
to match the font style as closely as possible when the original font
is not available.
Expand Down
26 changes: 5 additions & 21 deletions doc/gui.general.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,30 +80,14 @@ versions dating back to release 0.94 in 1995. (Users interested in the
details of these file formats can consult :ref:`file-formats`
for more information.)

Beginning with release 2005.12.xx, the graphical interface now reads
and writes a new file format, which is referred to as a"Gambit
workbook." This extended file format stores not only the
The graphical interface reads and writes an extended format, referred to
as a "Gambit workspace".
This stores not only the
representation of the game, but also additional information, including
parameters for laying out the game tree, the colors assigned to
players, any equilibria or other analysis done on the game, and so
forth. So, for example, the workbook file can be used to store the
forth. So, for example, the workspace file can be used to store the
analysis of a game and then return to it. These files by convention
end in the extension .gbt.

The graphical interface will read files in all three formats: .gbt,
.efg, and .nfg. The "Save" and "Save as" commands, however, always
save in the Gambit workbook (.gbt) format. To save the game itself as
an extensive (.efg) or strategic (.nfg) game, use the items on the
"Export" submenu of the "File" menu. This is useful in interfacing
with older versions of Gambit, with other tools which read and write
those formats, and in using the underlying Gambit analysis command-
line tools directly, as those programs accept .efg or .nfg game files.
Users primarily interested in using Gambit solely via the graphical
interface are encouraged to use the workbook (.gbt) format.



As it is a new format, the Gambit workbook format is still under
development and may change in details. It is intended that newer
versions of the graphical interface will still be able to read
workbook files written in older formats.
.efg, and .nfg.
8 changes: 4 additions & 4 deletions src/gui/analysis.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ template <class T> void AnalysisProfileList<T>::AddOutput(const wxString &p_outp
auto profile =
std::make_shared<MixedStrategyProfile<T>>(OutputToMixedProfile<T>(m_doc, p_output));
m_mixedProfiles.push_back(profile);
if (m_doc->IsTree()) {
if (m_doc->GetGame()->IsTree()) {
m_behavProfiles.push_back(std::make_shared<MixedBehaviorProfile<T>>(*profile));
}
m_current = m_mixedProfiles.size();
Expand All @@ -120,7 +120,7 @@ template <class T> void AnalysisProfileList<T>::BuildNfg()

template <class T> int AnalysisProfileList<T>::NumProfiles() const
{
return (m_doc->IsTree()) ? m_behavProfiles.size() : m_mixedProfiles.size();
return (m_doc->GetGame()->IsTree()) ? m_behavProfiles.size() : m_mixedProfiles.size();
}

template <class T> void AnalysisProfileList<T>::Clear()
Expand Down Expand Up @@ -202,7 +202,7 @@ template <class T> std::string AnalysisProfileList<T>::GetPayoff(int pl, int p_i
const int index = (p_index == -1) ? m_current : p_index;

try {
if (m_doc->IsTree()) {
if (m_doc->GetGame()->IsTree()) {
return lexical_cast<std::string>(
m_behavProfiles[index]->GetPayoff(m_doc->GetGame()->GetPlayer(pl)),
m_doc->GetStyle().NumDecimals());
Expand Down Expand Up @@ -417,7 +417,7 @@ template <class T> void AnalysisProfileList<T>::Save(std::ostream &p_file) const
p_file << static_cast<const char *>(m_description.mb_str()) << "\n";
p_file << "</description>\n";

if (m_doc->IsTree()) {
if (m_doc->GetGame()->IsTree()) {
for (int j = 1; j <= NumProfiles(); j++) {
const MixedBehaviorProfile<T> &behav = *m_behavProfiles[j];
p_file << "<profile type=\"behav\">\n";
Expand Down
8 changes: 1 addition & 7 deletions src/gui/app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ AppLoadResult Application::LoadFile(const wxString &p_filename, wxWindow *p_pare
}

auto *doc = new GameDocument(NewTree());
if (doc->LoadDocument(p_filename)) {
if (doc->LoadWorkspace(p_filename)) {
doc->SetFilename(p_filename);
m_fileHistory.AddFileToHistory(p_filename);
m_fileHistory.Save(*wxConfigBase::Get());
Expand Down Expand Up @@ -167,12 +167,6 @@ void Application::SetCurrentDir(const wxString &p_dir)
wxConfigBase::Get()->Write(_T("/General/CurrentDirectory"), p_dir);
}

bool Application::AreDocumentsModified() const
{
return std::any_of(m_documents.begin(), m_documents.end(),
std::mem_fn(&GameDocument::IsModified));
}

} // namespace Gambit::GUI

IMPLEMENT_APP(Gambit::GUI::Application)
1 change: 0 additions & 1 deletion src/gui/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class Application final : public wxApp {
{
m_documents.erase(std::find(m_documents.begin(), m_documents.end(), p_doc));
}
bool AreDocumentsModified() const;
//@}
};

Expand Down
2 changes: 1 addition & 1 deletion src/gui/dlgameprop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ GamePropertiesDialog::GamePropertiesDialog(wxWindow *p_parent, GameDocument *p_d
wxALL, 5);
}

if (m_doc->IsTree()) {
if (game->IsTree()) {
if (game->IsPerfectRecall()) {
boxSizer->Add(new wxStaticText(this, wxID_STATIC, _("This is a game of perfect recall")), 0,
wxALL, 5);
Expand Down
8 changes: 4 additions & 4 deletions src/gui/dlinsertmove.cc
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void InsertMoveDialog::OnPlayer(wxCommandEvent &)
if (playerNumber == 0) {
player = m_doc->GetGame()->GetChance();
}
else if (playerNumber <= static_cast<int>(m_doc->NumPlayers())) {
else if (playerNumber <= static_cast<int>(m_doc->GetGame()->NumPlayers())) {
player = m_doc->GetGame()->GetPlayer(playerNumber);
}

Expand Down Expand Up @@ -187,17 +187,17 @@ GamePlayer InsertMoveDialog::GetPlayer() const
if (playerNumber == 0) {
return m_doc->GetGame()->GetChance();
}
if (playerNumber <= static_cast<int>(m_doc->NumPlayers())) {
if (playerNumber <= static_cast<int>(m_doc->GetGame()->NumPlayers())) {
return m_doc->GetGame()->GetPlayer(playerNumber);
}
const GamePlayer player = m_doc->GetGame()->NewPlayer();
player->SetLabel("Player " + lexical_cast<std::string>(m_doc->NumPlayers()));
player->SetLabel("Player " + lexical_cast<std::string>(m_doc->GetGame()->NumPlayers()));
return player;
}

GameInfoset InsertMoveDialog::GetInfoset() const
{
if (m_playerItem->GetSelection() <= static_cast<int>(m_doc->NumPlayers())) {
if (m_playerItem->GetSelection() <= static_cast<int>(m_doc->GetGame()->NumPlayers())) {
const GamePlayer player = GetPlayer();
const int infosetNumber = m_infosetItem->GetSelection();

Expand Down
16 changes: 8 additions & 8 deletions src/gui/dlnash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ NashChoiceDialog::NashChoiceDialog(wxWindow *p_parent, GameDocument *p_doc)
wxCommandEventHandler(NashChoiceDialog::OnCount));
topSizer->Add(m_countChoice, 0, wxALL | wxEXPAND, 5);

if (p_doc->NumPlayers() == 2 && m_doc->IsConstSum()) {
if (p_doc->GetGame()->NumPlayers() == 2 && m_doc->GetGame()->IsConstSum()) {
wxString methodChoices[] = {s_recommended, s_lp, s_simpdiv, s_logit, s_enumpoly};
m_methodChoice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 5, methodChoices);
Expand All @@ -79,7 +79,7 @@ NashChoiceDialog::NashChoiceDialog(wxWindow *p_parent, GameDocument *p_doc)
m_methodChoice->SetSelection(0);
topSizer->Add(m_methodChoice, 0, wxALL | wxEXPAND, 5);

if (m_doc->IsTree()) {
if (m_doc->GetGame()->IsTree()) {
wxString repChoices[] = {wxT("using the extensive game"), wxT("using the strategic game")};
m_repChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 2, repChoices);
m_repChoice->SetSelection(0);
Expand Down Expand Up @@ -114,14 +114,14 @@ void NashChoiceDialog::OnCount(wxCommandEvent &p_event)
m_methodChoice->Append(s_recommended);

if (p_event.GetSelection() == 0) {
if (m_doc->NumPlayers() == 2 && m_doc->IsConstSum()) {
if (m_doc->GetGame()->NumPlayers() == 2 && m_doc->GetGame()->IsConstSum()) {
m_methodChoice->Append(s_lp);
}
m_methodChoice->Append(s_simpdiv);
m_methodChoice->Append(s_logit);
}
else if (p_event.GetSelection() == 1) {
if (m_doc->NumPlayers() == 2) {
if (m_doc->GetGame()->NumPlayers() == 2) {
m_methodChoice->Append(s_lcp);
}
m_methodChoice->Append(s_enumpure);
Expand All @@ -131,7 +131,7 @@ void NashChoiceDialog::OnCount(wxCommandEvent &p_event)
m_methodChoice->Append(s_enumpoly);
}
else {
if (m_doc->NumPlayers() == 2) {
if (m_doc->GetGame()->NumPlayers() == 2) {
m_methodChoice->Append(s_enummixed);
}
}
Expand Down Expand Up @@ -195,7 +195,7 @@ std::shared_ptr<AnalysisOutput> NashChoiceDialog::GetCommand() const

if (method == s_recommended) {
if (m_countChoice->GetSelection() == 0) {
if (m_doc->NumPlayers() == 2 && m_doc->IsConstSum()) {
if (m_doc->GetGame()->NumPlayers() == 2 && m_doc->GetGame()->IsConstSum()) {
cmd = std::make_shared<AnalysisProfileList<Rational>>(m_doc, useEfg);
cmd->SetCommand(prefix + wxT("lp") + options);
cmd->SetDescription(wxT("One equilibrium by solving a linear program ") + game);
Expand All @@ -207,7 +207,7 @@ std::shared_ptr<AnalysisOutput> NashChoiceDialog::GetCommand() const
}
}
else if (m_countChoice->GetSelection() == 1) {
if (m_doc->NumPlayers() == 2) {
if (m_doc->GetGame()->NumPlayers() == 2) {
cmd = std::make_shared<AnalysisProfileList<Rational>>(m_doc, useEfg);
cmd->SetCommand(prefix + wxT("lcp") + options);
cmd->SetDescription(wxT("Some equilibria by solving a linear complementarity program ") +
Expand All @@ -220,7 +220,7 @@ std::shared_ptr<AnalysisOutput> NashChoiceDialog::GetCommand() const
}
}
else {
if (m_doc->NumPlayers() == 2) {
if (m_doc->GetGame()->NumPlayers() == 2) {
cmd = std::make_shared<AnalysisProfileList<Rational>>(m_doc, false);
cmd->SetCommand(prefix + wxT("enummixed"));
cmd->SetDescription(
Expand Down
2 changes: 1 addition & 1 deletion src/gui/dlnashmon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void NashMonitorDialog::Start(std::shared_ptr<AnalysisOutput> p_command)
m_doc->BuildNfg();
}

m_doc->AddProfileList(p_command);
m_doc->DoAddEquilibriumOutput(p_command);

m_process = new wxProcess(this, GBT_ID_PROCESS);
m_process->Redirect();
Expand Down
4 changes: 2 additions & 2 deletions src/gui/efgdisplay.cc
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ void EfgDisplay::OnKeyEvent(wxKeyEvent &p_event)
PrepareDC(dc);
OnDraw(dc);

if (player < static_cast<int>(m_doc->NumPlayers())) {
if (player < static_cast<int>(m_doc->GetGame()->NumPlayers())) {
auto entry = m_layout.GetNodeEntry(node);
const wxRect rect = entry->GetPayoffExtent(player + 1);
int xx, yy;
Expand Down Expand Up @@ -919,7 +919,7 @@ void EfgDisplay::OnLeftDoubleClick(wxMouseEvent &p_event)

// Editing an existing outcome
auto entry = m_layout.GetNodeEntry(node);
for (size_t pl = 1; pl <= m_doc->NumPlayers(); pl++) {
for (size_t pl = 1; pl <= m_doc->GetGame()->NumPlayers(); pl++) {
const wxRect rect = entry->GetPayoffExtent(pl);
if (rect.Contains(x, y)) {
int xx, yy;
Expand Down
30 changes: 20 additions & 10 deletions src/gui/efglayout.cc
Original file line number Diff line number Diff line change
Expand Up @@ -481,12 +481,15 @@ wxString TreeLayout::CreateNodeLabel(const std::shared_ptr<NodeEntry> &p_entry,
return _T("");
}
case GBT_NODE_LABEL_REALIZPROB:
return {m_doc->GetProfiles().GetRealizProb(n).c_str(), *wxConvCurrent};
return {m_doc->GetWorkspace().GetProfiles().GetRealizProb(n).c_str(), *wxConvCurrent};
case GBT_NODE_LABEL_BELIEFPROB:
return {m_doc->GetProfiles().GetBeliefProb(n).c_str(), *wxConvCurrent};
return {m_doc->GetWorkspace().GetProfiles().GetBeliefProb(n).c_str(), *wxConvCurrent};
case GBT_NODE_LABEL_VALUE:
if (n->GetInfoset() && n->GetPlayer()->GetNumber() > 0) {
return {m_doc->GetProfiles().GetNodeValue(n, n->GetPlayer()->GetNumber()).c_str(),
return {m_doc->GetWorkspace()
.GetProfiles()
.GetNodeValue(n, n->GetPlayer()->GetNumber())
.c_str(),
*wxConvCurrent};
}
else {
Expand Down Expand Up @@ -521,19 +524,25 @@ wxString TreeLayout::CreateBranchLabel(const std::shared_ptr<NodeEntry> &p_entry
.c_str(),
*wxConvCurrent};
}
else if (m_doc->NumProfileLists() == 0) {
else if (m_doc->GetWorkspace().NumProfileLists() == 0) {
return wxT("");
}
else {
return {m_doc->GetProfiles().GetActionProb(parent, p_entry->GetChildNumber()).c_str(),
return {m_doc->GetWorkspace()
.GetProfiles()
.GetActionProb(parent, p_entry->GetChildNumber())
.c_str(),
*wxConvCurrent};
}
case GBT_BRANCH_LABEL_VALUE:
if (m_doc->NumProfileLists() == 0) {
if (m_doc->GetWorkspace().NumProfileLists() == 0) {
return wxT("");
}
else {
return {m_doc->GetProfiles().GetActionValue(parent, p_entry->GetChildNumber()).c_str(),
return {m_doc->GetWorkspace()
.GetProfiles()
.GetActionValue(parent, p_entry->GetChildNumber())
.c_str(),
*wxConvCurrent};
}
default:
Expand Down Expand Up @@ -712,11 +721,12 @@ void TreeLayout::GenerateLabels() const
parent->GetInfoset()->GetAction(entry->GetChildNumber()))));
}
else {
const int profile = m_doc->GetCurrentProfile();
const int profile = m_doc->GetWorkspace().GetCurrentProfile();
if (profile > 0) {
try {
entry->SetActionProb((double)lexical_cast<Rational>(
m_doc->GetProfiles().GetActionProb(parent, entry->GetChildNumber())));
entry->SetActionProb(
(double)lexical_cast<Rational>(m_doc->GetWorkspace().GetProfiles().GetActionProb(
parent, entry->GetChildNumber())));
}
catch (ValueException &) {
// This occurs when the probability is undefined
Expand Down
22 changes: 11 additions & 11 deletions src/gui/efgpanel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ gbtTreePlayerPanel::gbtTreePlayerPanel(wxWindow *p_parent, GameDocument *p_doc,

void gbtTreePlayerPanel::OnUpdate()
{
if (!m_doc->IsTree()) {
if (!m_doc->GetGame()->IsTree()) {
return;
}

Expand All @@ -199,36 +199,36 @@ void gbtTreePlayerPanel::OnUpdate()
wxString(m_doc->GetGame()->GetPlayer(m_player)->GetLabel().c_str(), *wxConvCurrent));

m_payoff->SetForegroundColour(color);
if (m_doc->GetCurrentProfile() > 0) {
const std::string pay = m_doc->GetProfiles().GetPayoff(m_player);
if (m_doc->GetWorkspace().GetCurrentProfile() > 0) {
const std::string pay = m_doc->GetWorkspace().GetProfiles().GetPayoff(m_player);
m_payoff->SetLabel(wxT("Payoff: ") + wxString(pay.c_str(), *wxConvCurrent));
GetSizer()->Show(m_payoff, true);

if (const GameNode node = m_doc->GetSelectNode()) {
m_nodeValue->SetForegroundColour(color);
std::string value = m_doc->GetProfiles().GetNodeValue(node, m_player);
std::string value = m_doc->GetWorkspace().GetProfiles().GetNodeValue(node, m_player);
m_nodeValue->SetLabel(wxT("Node value: ") + wxString(value.c_str(), *wxConvCurrent));
GetSizer()->Show(m_nodeValue, true);

if (node->GetInfoset() && node->GetPlayer()->GetNumber() == m_player) {
m_nodeProb->SetForegroundColour(color);
value = m_doc->GetProfiles().GetRealizProb(node);
value = m_doc->GetWorkspace().GetProfiles().GetRealizProb(node);
m_nodeProb->SetLabel(wxT("Node reached: ") + wxString(value.c_str(), *wxConvCurrent));
GetSizer()->Show(m_nodeProb, true);

m_infosetValue->SetForegroundColour(color);
value = m_doc->GetProfiles().GetInfosetValue(node);
value = m_doc->GetWorkspace().GetProfiles().GetInfosetValue(node);
m_infosetValue->SetLabel(wxT("Infoset value: ") + wxString(value.c_str(), *wxConvCurrent));
GetSizer()->Show(m_infosetValue, true);

m_infosetProb->SetForegroundColour(color);
value = m_doc->GetProfiles().GetInfosetProb(node);
value = m_doc->GetWorkspace().GetProfiles().GetInfosetProb(node);
m_infosetProb->SetLabel(wxT("Infoset reached: ") +
wxString(value.c_str(), *wxConvCurrent));
GetSizer()->Show(m_infosetProb, true);

m_belief->SetForegroundColour(color);
value = m_doc->GetProfiles().GetBeliefProb(node);
value = m_doc->GetWorkspace().GetProfiles().GetBeliefProb(node);
m_belief->SetLabel(wxT("Belief: ") + wxString(value.c_str(), *wxConvCurrent));
GetSizer()->Show(m_belief, true);
}
Expand Down Expand Up @@ -441,7 +441,7 @@ gbtTreePlayerToolbar::gbtTreePlayerToolbar(wxWindow *p_parent, GameDocument *p_d

topSizer->Add(m_chancePanel, 0, wxALL | wxEXPAND, 5);

for (size_t pl = 1; pl <= m_doc->NumPlayers(); pl++) {
for (size_t pl = 1; pl <= m_doc->GetGame()->NumPlayers(); pl++) {
m_playerPanels.push_back(new gbtTreePlayerPanel(this, m_doc, pl));
topSizer->Add(m_playerPanels[pl], 0, wxALL | wxEXPAND, 5);
}
Expand All @@ -452,13 +452,13 @@ gbtTreePlayerToolbar::gbtTreePlayerToolbar(wxWindow *p_parent, GameDocument *p_d

void gbtTreePlayerToolbar::OnUpdate()
{
while (m_playerPanels.size() < m_doc->NumPlayers()) {
while (m_playerPanels.size() < m_doc->GetGame()->NumPlayers()) {
auto *panel = new gbtTreePlayerPanel(this, m_doc, m_playerPanels.size() + 1);
m_playerPanels.push_back(panel);
GetSizer()->Add(panel, 0, wxALL | wxEXPAND, 5);
}

while (m_playerPanels.size() > m_doc->NumPlayers()) {
while (m_playerPanels.size() > m_doc->GetGame()->NumPlayers()) {
gbtTreePlayerPanel *panel = m_playerPanels.back();
GetSizer()->Detach(panel);
panel->Destroy();
Expand Down
Loading
Loading