📄 efg.cc
字号:
//// $Source: /home/gambit/CVS/gambit/sources/game/efg.cc,v $// $Date: 2002/08/26 05:50:06 $// $Revision: 1.7 $//// DESCRIPTION:// Implementation of extensive form game representation//// This file is part of Gambit// Copyright (c) 2002, The Gambit Project//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.//#include "base/base.h"#include "math/rational.h"#ifdef __GNUG__#pragma implementation "infoset.h"#pragma implementation "efplayer.h"#pragma implementation "node.h"#endif // __GNUG__#include "efg.h"#include "efgutils.h"#include "efstrat.h"//----------------------------------------------------------------------// EFPlayer: Member function definitions//----------------------------------------------------------------------EFPlayer::~EFPlayer(){ while (infosets.Length()) delete infosets.Remove(1);}//----------------------------------------------------------------------// Action: Member function definitions//----------------------------------------------------------------------bool Action::Precedes(const Node * n) const{ while ( n != n->Game()->RootNode() ) { if ( n->GetAction() == this ) return true; else n = n->GetParent(); } return false;}//----------------------------------------------------------------------// Infoset: Member function definitions//----------------------------------------------------------------------bool Infoset::Precedes(const Node * n) const{ while ( n != n->Game()->RootNode() ) { if ( n->GetInfoset() == this ) return true; else n = n->GetParent(); } return false;}Infoset::Infoset(efgGame *e, int n, EFPlayer *p, int br) : E(e), number(n), player(p), actions(br), flag(0) { while (br) { actions[br] = new Action(br, "", this); br--; }}Infoset::~Infoset() { for (int i = 1; i <= actions.Length(); i++) delete actions[i];}void Infoset::PrintActions(gOutput &f) const{ f << "{ "; for (int i = 1; i <= actions.Length(); i++) f << '"' << EscapeQuotes(actions[i]->name) << "\" "; f << "}";}Action *Infoset::InsertAction(int where){ Action *action = new Action(where, "", this); actions.Insert(action, where); for (; where <= actions.Length(); where++) actions[where]->number = where; return action;}void Infoset::RemoveAction(int which){ delete actions.Remove(which); for (; which <= actions.Length(); which++) actions[which]->number = which;}const gList<Action *> Infoset::ListOfActions(void) const{ gList<Action *> answer; for (int i = 1; i <= actions.Length(); i++) answer += actions[i]; return answer;}const gList<const Node *> Infoset::ListOfMembers(void) const{ gList<const Node *> answer; for (int i = 1; i <= members.Length(); i++) answer += members[i]; return answer;}//------------------------------------------------------------------------// ChanceInfoset: Member function definitions//------------------------------------------------------------------------ChanceInfoset::ChanceInfoset(efgGame *E, int n, EFPlayer *p, int br) : Infoset(E, n, p, br), probs(br){ for (int i = 1; i <= br; probs[i++] = gRational(1, br));}Action *ChanceInfoset::InsertAction(int where){ Action *action = Infoset::InsertAction(where); probs.Insert((gNumber) 0, where); return action;}void ChanceInfoset::RemoveAction(int which){ Infoset::RemoveAction(which); probs.Remove(which);}void ChanceInfoset::PrintActions(gOutput &f) const{ f << "{ "; for (int i = 1; i <= actions.Length(); i++) { f << '"' << EscapeQuotes(actions[i]->GetName()) << "\" "; f << probs[i] << ' '; } f << "}";}//----------------------------------------------------------------------// Node: Member function definitions//----------------------------------------------------------------------Node::Node(efgGame *e, Node *p) : mark(false), number(0), E(e), infoset(0), parent(p), outcome(0), gameroot((p) ? p->gameroot : this){ }Node::~Node(){ for (int i = children.Length(); i; delete children[i--]);}int Node::NumberInInfoset(void) const{ for (int i = 1; i <= GetInfoset()->NumMembers(); i++) if (GetInfoset()->GetMember(i) == this) return i; // This could be speeded up by adding a member to Node to keep track of this throw efgGame::Exception();}Node *Node::NextSibling(void) const { if (!parent) return 0; if (parent->children.Find((Node * const) this) == parent->children.Length()) return 0; else return parent->children[parent->children.Find((Node * const)this) + 1];}Node *Node::PriorSibling(void) const{ if (!parent) return 0; if (parent->children.Find((Node * const)this) == 1) return 0; else return parent->children[parent->children.Find((Node * const)this) - 1];}Action *Node::GetAction(void) const{ if (this == Game()->RootNode()) { return 0; } const gArray<Action *> &actions = GetParent()->GetInfoset()->Actions(); for (int i = 1; i <= actions.Length(); i++) { if (this == GetParent()->GetChild(actions[i])) { return actions[i]; } } return 0;}void Node::DeleteOutcome(efgOutcome *outc){ if (outc == outcome) outcome = 0; for (int i = 1; i <= children.Length(); i++) children[i]->DeleteOutcome(outc);}//------------------------------------------------------------------------// Efg: Constructors, destructor, constructive operators//------------------------------------------------------------------------#ifdef MEMCHECKint efgGame::_NumObj = 0;#endif // MEMCHECKefgGame::efgGame(void) : sortisets(true), m_dirty(false), m_revision(0), m_outcome_revision(-1), title("UNTITLED"), chance(new EFPlayer(this, 0)), afg(0), lexicon(0){ root = new Node(this, 0);#ifdef MEMCHECK _NumObj++; gout << "--- Efg Ctor: " << _NumObj << "\n";#endif // MEMCHECK SortInfosets();}efgGame::efgGame(const efgGame &E, Node *n /* = 0 */) : sortisets(false), m_dirty(false), m_revision(0), m_outcome_revision(-1), title(E.title), comment(E.comment), players(E.players.Length()), outcomes(0, E.outcomes.Last()), chance(new EFPlayer(this, 0)), afg(0), lexicon(0) { for (int i = 1; i <= players.Length(); i++) { (players[i] = new EFPlayer(this, i))->name = E.players[i]->name; for (int j = 1; j <= E.players[i]->infosets.Length(); j++) { Infoset *s = new Infoset(this, j, players[i], E.players[i]->infosets[j]->actions.Length()); s->name = E.players[i]->infosets[j]->name; for (int k = 1; k <= s->actions.Length(); k++) s->actions[k]->name = E.players[i]->infosets[j]->actions[k]->name; players[i]->infosets.Append(s); } } for (int i = 1; i <= E.GetChance()->NumInfosets(); i++) { ChanceInfoset *t = (ChanceInfoset *) E.GetChance()->Infosets()[i]; ChanceInfoset *s = new ChanceInfoset(this, i, chance, t->NumActions()); s->name = t->GetName(); for (int act = 1; act <= s->probs.Length(); act++) { s->probs[act] = t->probs[act]; s->actions[act]->name = t->actions[act]->name; } chance->infosets.Append(s); } for (int outc = 1; outc <= E.NumOutcomes(); outc++) { outcomes[outc] = new efgOutcome(this, outc); outcomes[outc]->m_name = E.outcomes[outc]->m_name; outcomes[outc]->m_payoffs = E.outcomes[outc]->m_payoffs; } root = new Node(this, 0); CopySubtree(root, (n ? n : E.RootNode())); if (n) { for (int pl = 1; pl <= players.Length(); pl++) { for (int i = 1; i <= players[pl]->infosets.Length(); i++) { if (players[pl]->infosets[i]->members.Length() == 0) delete players[pl]->infosets.Remove(i--); } } } sortisets = true; SortInfosets();}#include "lexicon.h"efgGame::~efgGame(){ delete root; delete chance; for (int i = 1; i <= players.Length(); delete players[i++]); for (int i = 1; i <= outcomes.Last(); delete outcomes[i++]); if (lexicon) delete lexicon; lexicon = 0;}//------------------------------------------------------------------------// Efg: Private member functions//------------------------------------------------------------------------void efgGame::DeleteLexicon(void) const{ if (lexicon) delete lexicon; lexicon = 0;}Infoset *efgGame::GetInfosetByIndex(EFPlayer *p, int index) const{ for (int i = 1; i <= p->infosets.Length(); i++) if (p->infosets[i]->number == index) return p->infosets[i]; return 0;}efgOutcome *efgGame::GetOutcomeByIndex(int index) const{ for (int i = 1; i <= outcomes.Last(); i++) { if (outcomes[i]->m_number == index) { return outcomes[i]; } } return 0;}void efgGame::Reindex(void){ int i; for (i = 1; i <= players.Length(); i++) { EFPlayer *p = players[i]; for (int j = 1; j <= p->infosets.Length(); j++) p->infosets[j]->number = j; } for (i = 1; i <= outcomes.Last(); i++) outcomes[i]->m_number = i;}void efgGame::NumberNodes(Node *n, int &index){ n->number = index++; for (int child = 1; child <= n->children.Length(); NumberNodes(n->children[child++], index));} void efgGame::SortInfosets(void){ if (!sortisets) return; int pl; for (pl = 0; pl <= players.Length(); pl++) { gList<Node *> nodes; Nodes(*this, nodes); EFPlayer *player = (pl) ? players[pl] : chance; int i, isets = 0; // First, move all empty infosets to the back of the list so // we don't "lose" them int foo = player->infosets.Length(); i = 1; while (i < foo) { if (player->infosets[i]->members.Length() == 0) { Infoset *bar = player->infosets[i]; player->infosets[i] = player->infosets[foo]; player->infosets[foo--] = bar; } else i++; } // This will give empty infosets their proper number; the nonempty // ones will be renumbered by the next loop for (i = 1; i <= player->infosets.Length(); i++) if (player->infosets[i]->members.Length() == 0) player->infosets[i]->number = i; else player->infosets[i]->number = 0; for (i = 1; i <= nodes.Length(); i++) { Node *n = nodes[i]; if (n->GetPlayer() == player && n->GetInfoset()->number == 0) { n->GetInfoset()->number = ++isets; player->infosets[isets] = n->GetInfoset(); } } } // Now, we sort the nodes within the infosets gList<Node *> nodes; Nodes(*this, nodes); for (pl = 0; pl <= players.Length(); pl++) { EFPlayer *player = (pl) ? players[pl] : chance; for (int iset = 1; iset <= player->infosets.Length(); iset++) { Infoset *s = player->infosets[iset]; for (int i = 1, j = 1; i <= nodes.Length(); i++) { if (nodes[i]->infoset == s) s->members[j++] = nodes[i]; } } } int nodeindex = 1; NumberNodes(root, nodeindex);} Infoset *efgGame::CreateInfoset(int n, EFPlayer *p, int br){ Infoset *s = (p->IsChance()) ? new ChanceInfoset(this, n, p, br) : new Infoset(this, n, p, br); p->infosets.Append(s); return s;}efgOutcome *efgGame::CreateOutcomeByIndex(int index){ NewOutcome(index); return outcomes[outcomes.Last()];}void efgGame::CopySubtree(Node *n, Node *m){ n->name = m->name; if (m->gameroot == m) n->gameroot = n; if (m->outcome) { n->outcome = m->outcome; } if (m->infoset) { EFPlayer *p; if (m->infoset->player->number) p = players[m->infoset->player->number]; else p = chance; Infoset *s = p->Infosets()[m->infoset->number]; AppendNode(n, s); for (int i = 1; i <= n->children.Length(); i++) CopySubtree(n->children[i], m->children[i]); }}//------------------------------------------------------------------------// Efg: Title access and manipulation//------------------------------------------------------------------------void efgGame::SetTitle(const gText &s){ title = s; m_revision++; m_dirty = true;}const gText &efgGame::GetTitle(void) const{ return title; }void efgGame::SetComment(const gText &s){ comment = s; m_revision++; m_dirty = true;}const gText &efgGame::GetComment(void) const{ return comment; } //------------------------------------------------------------------------// Efg: Writing data files//------------------------------------------------------------------------void efgGame::WriteEfgFile(gOutput &f, Node *n) const{ if (n->children.Length() == 0) { f << "t \"" << EscapeQuotes(n->name) << "\" "; if (n->outcome) { f << n->outcome->m_number << " \"" << EscapeQuotes(n->outcome->m_name) << "\" "; f << "{ "; for (int pl = 1; pl <= NumPlayers(); pl++) { f << n->outcome->m_payoffs[pl]; if (pl < NumPlayers()) f << ", "; else f << " }\n"; } } else f << "0\n"; } else if (n->infoset->player->number) { f << "p \"" << EscapeQuotes(n->name) << "\" " << n->infoset->player->number << ' '; f << n->infoset->number << " \"" << EscapeQuotes(n->infoset->name) << "\" "; n->infoset->PrintActions(f); f << " "; if (n->outcome) { f << n->outcome->m_number << " \"" << EscapeQuotes(n->outcome->m_name) << "\" "; f << "{ "; for (int pl = 1; pl <= NumPlayers(); pl++) { f << n->outcome->m_payoffs[pl]; if (pl < NumPlayers()) f << ", "; else f << " }\n"; } } else f << "0\n"; } else { // chance node f << "c \"" << n->name << "\" "; f << n->infoset->number << " \"" << EscapeQuotes(n->infoset->name) << "\" "; n->infoset->PrintActions(f); f << " "; if (n->outcome) { f << n->outcome->m_number << " \"" << EscapeQuotes(n->outcome->m_name) << "\" "; f << "{ "; for (int pl = 1; pl <= NumPlayers(); pl++) { f << n->outcome->m_payoffs[pl]; if (pl < NumPlayers()) f << ", "; else f << " }\n"; } } else f << "0\n"; } for (int i = 1; i <= n->children.Length(); i++) WriteEfgFile(f, n->children[i]);}void efgGame::WriteEfgFile(gOutput &p_file, int p_nDecimals) const{ int oldPrecision = p_file.GetPrec(); p_file.SetPrec(p_nDecimals); try {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -