// A simple implmentation of the Peace War Game // See https://en.wikipedia.org/wiki/Peace_war_game #include #include using namespace std; // actions a player may have taken // NONE is for the first time. enum ActionT {NONE, WAR, PEACE}; // Amount gained in each scenario const int BOTH_PEACE = 2; const int BOTH_WAR = 1; const int WIN_WAR = 3; const int LOSE_WAR = 0; // not const, this can be changed. bool VERBOSE = false; // a base player class. class PlayerT { public: PlayerT(string newName=""): cash(0), wins(0), lastAction(NONE), name(newName) { return; } virtual ~PlayerT() { return; }; // my action this time could be based on the other // player's action last time. // // Input: Other player's action last round. // Output: What do I want to do this round. // virtual ActionT Move(ActionT ) = 0; // what did I do last round ActionT LastAction(void) const { return lastAction; } // pay me! void ChangeCash(int amt) { cash += amt; } // how much cash to I have int GetCash(void) const { return cash; } // what type of player am I string Name(void) const{ return name; } private: int cash; int wins; protected: ActionT lastAction; string name; }; // derived player, this one always declares war. class AgressorT: public PlayerT{ public: AgressorT(): PlayerT("Agressor"){ return; } ActionT Move(ActionT ) { lastAction = WAR; return WAR; } }; // peace out dude class HippyT: public PlayerT{ public: HippyT(): PlayerT("Hippy"){ return; } ActionT Move(ActionT) { lastAction = PEACE; return PEACE; } }; // I don't let's just flip a coin. class RandomT: public PlayerT{ public: RandomT(): PlayerT("Random"){ return; } ActionT Move(ActionT) { int action = rand() %2; ActionT move; if (action) { move = WAR; } else { move = PEACE; } lastAction = move; return move; } }; // I do what you did class CopyCatT: public PlayerT{ public: CopyCatT(): PlayerT("Copy Cat") { return; } ActionT Move(ActionT last) { // by default do what they did last time. ActionT action = last; if (lastAction == NONE or last == NONE) { // take a random action. // but if they didn't do anything, pick at random RandomT r; action = r.Move(NONE); } lastAction = action; return action; } }; class PeaceUntilT: public PlayerT{ public: PeaceUntilT(): PlayerT("Peace Until Provoked"), atPeace(true) { return; } ActionT Move(ActionT last) { if (last == WAR or not atPeace ) { lastAction = WAR; atPeace = false; return WAR; } else { lastAction = PEACE; return PEACE; } } private: bool atPeace; }; string ActionTToString(ActionT a); void DoStats(const PlayerT & a, const PlayerT & b, int games); void Battle(PlayerT & a, PlayerT & b); PlayerT * MakePlayer(int type) ; void ChangePlayer(int & type, int & pos, int argc, char * argv[]) { pos++; if (pos < argc) { type = atoi(argv[pos]); pos++; } else { cout << "\t Player type argument requires an integer" << endl; } return; } int main(int argc, char * argv[]) { int i; // values that might be changed by command flags int games=10; int player1Type = 0; int player2Type = 0; bool doStats = false; int seed = time(nullptr); PlayerT * a, * b; // flags // -p1 0-4 // -p2 0-4 // --verbose, -v // --rounds=n, -r 10 default 10 // --stats : enable statistics i = 1; while (i < argc) { if (!strcmp(argv[i],"--verbose") or !strcmp(argv[i],"-v")) { VERBOSE = true; i++; } else if (!strcmp(argv[i],"--stats") or !strcmp(argv[i],"-s")) { doStats = true; i++; } else if (!strcmp(argv[i],"-p1")) { ChangePlayer(player1Type, i, argc, argv); } else if (!strcmp(argv[i],"-p2")) { ChangePlayer(player2Type,i, argc, argv); } else { cout << "\t unknown argument " << argv[i] << endl; i++; } } srand(seed); a = MakePlayer(player1Type); b = MakePlayer(player2Type); if (VERBOSE) { cout << "Player A is a " << a->Name() << endl; cout << "Player B is a " << b->Name() << endl; cout << endl; } for(i=0;iGetCash() << " B:" << b->GetCash() << endl; } } if (doStats) { DoStats(*a,*b,games); } delete a; delete b; return 0; } void Battle(PlayerT & a, PlayerT & b) { ActionT p1Move, p2Move, p1Last, p2Last; p1Last = a.LastAction(); p2Last = b.LastAction(); p1Move = a.Move(p2Last); p2Move = b.Move(p1Last); if (VERBOSE) { cout << "In a battle player A selects " << ActionTToString(p1Move) << " and player B selects " << ActionTToString(p2Move) << endl; } switch(p1Move) { case PEACE: switch (p2Move) { case PEACE: a.ChangeCash(BOTH_PEACE); b.ChangeCash(BOTH_PEACE); break; case WAR: a.ChangeCash(LOSE_WAR); b.ChangeCash(WIN_WAR); break; case NONE: break; } break; case WAR: switch (p2Move) { case PEACE: a.ChangeCash(WIN_WAR); b.ChangeCash(LOSE_WAR); break; case WAR: a.ChangeCash(BOTH_WAR); b.ChangeCash(BOTH_WAR); break; case NONE: break; } break; case NONE: break; } return; } PlayerT * MakePlayer(int type) { PlayerT * rv; switch (type) { case 0: rv = new AgressorT; break; case 1: rv = new HippyT; break; case 2: rv = new CopyCatT; break; case 3: rv = new PeaceUntilT; break; default: rv = new RandomT; break; } return rv; } string ActionTToString(ActionT a){ switch (a) { case NONE: return "None"; case WAR: return "War"; case PEACE: return "Peace"; default: return "Error: Unknown Action"; } } void ReportPlayer(string name, const PlayerT & player) { cout << name << endl; cout << "\tType: " << player.Name() << endl; cout << "\tCash: " << player.GetCash() << endl; return; } void DoStats(const PlayerT & a, const PlayerT & b, int games){ cout << endl; cout << "Games: " << games < b.GetCash()) { cout << "Player A" << endl; } else { cout << "Player B" << endl; } return; }