//Stick Game //Rusty Burchfield //Created: June 17, 2003 //Modified: June 17, 2003 //PLEASE DO NOT COPY, MODIFY, OR DISTRIBUTE MY SOURCE CODE WITHOUT MY PERMISSION!!! #include #include #include #include #define debug false #ifndef debug #define debug true //ofstream fout("debug.out"); //Open debug output file #endif bool AIWon = false; bool AILost = false; bool Dump = false; struct node { char Line; int Num; int Player; //-1 is AI node *next; node() :next(NULL) {} }; node *Begin = new node; node *End = Begin; struct Coord { char Line; int Num; }; void DrawSticks(int Sticks[3]); void Rules(); void Menu(); //void DebugOutput(int Sticks[3]); void DumpGame(); Coord MoveAI(int Sticks[3]); void main() { int Sticks[3]; int Option; int Player; int Error1; int Error2; int Human; bool AI; Coord Move; srand( (unsigned)time( NULL ) ); Sticks[0] = 3; Sticks[1] = 5; Sticks[2] = 7; Error1 = 0; while (true) { Menu(); cout << "> "; cin >> Option; Error1++; if (Error1 > 1000) break; if (Error2 > 100) { cout << "\n\nA console error has occured. Please be sure that the data you enter is in the format requested.\n\n"; Error2 = 0; } if (Option == 4) { Rules(); continue; } if (Option == 5) return; if ((Option < 1) || (Option > 3)) { Error1++; continue; } Human = 1; AI = false; if (Option != 3) AI = true; if (Option == 2) Human = 2; Option = -1; Player = 1; Sticks[0] = 3; Sticks[1] = 5; Sticks[2] = 7; AIWon = false; AILost = false; Dump = false; Error2 = 0; while (true) { if ((! AI) || (Player == Human)) { DrawSticks(Sticks); cout << "Enter Move Player " << Player << " (ex. B 3) or X1 to Exit: "; cin >> Move.Line >> Move.Num; } else { cout << "\nAI is thinking...\n"; Move = MoveAI(Sticks); cout << "AI: " << Move.Line << " " << Move.Num << "\n"; } if ((Move.Line == 'X') || (Move.Line == 'x')) break; if (Error2 > 100) break; Error2++; if ((Move.Line >= 'a') && (Move.Line <= 'c')) { Move.Line -= 'a'; Move.Line += 'A'; } if (((Move.Line < 'A') || (Move.Line > 'C')) || ((Move.Num > Sticks[Move.Line - 'A']) || (Move.Num <= 0))) { cout << "Invalid! Please try again.\n"; continue; } Sticks[Move.Line - 'A'] -= Move.Num; //Begin Linked list stuff //This is where the moves are stored in the linked list End->Line = Move.Line; End->Num = Move.Num; //Store the player number or -1 for AI if it was the AI's move if ((Player != Human) && (AI)) End->Player = -1; else End->Player = Player; if (Player == 2) Player = 1; else Player++; if ((Sticks[0] == 0) && (Sticks[1] == 0) && (Sticks[2] == 0)) { if ((Player != Human) && (AI)) cout << "\n\nAI wins!!!\n\n"; else cout << "\n\nPlayer " << Player << " wins!!!\n\n"; break; } else //If the game is to continue add a new node; { End->next = new node; End = End->next; } //End Linked list stuff } if ((AIWon) && (AILost) && (debug)) { cout << "You have beaten the AI even thought it thought it was going to win!!! "; cout << "Please email the \"Debug.out\" file in the game directory to GICodeWarrior@hotmail.com sohe can analyze it and fix the glitch in the AI.\n\nThank you for your time.\n"; DumpGame(); } else if (Dump) { cout << "An unhandled exception has occured. Please Email \"Debug.out\" to GICodeWarrior@hotmail.com for review.\n\nThank you for your time.\n"; DumpGame(); } //Delete Linked List while (Begin != NULL) { End = Begin->next; delete Begin; Begin = End; } Begin = new node; End = Begin; } cout << "FATAL ERROR!!!\n"; cout << "FATAL ERROR!!!\n"; cout << "FATAL ERROR!!!\n"; } void DrawSticks(int Sticks[3]) { cout << "\n"; for (int X = 0; X < 3; X++) { for (int Y = 0; Y < 3; Y++) { if (Y == 1) { switch (X) { case 0: cout << "A"; break; case 1: cout << "B"; break; case 2: cout << "C"; break; } } else cout << " "; for (int Z = 0; Z < Sticks[X]; Z++) cout << " " << char(179); cout << "\n"; } cout << "\n\n"; } /*cout << "\n"; cout << " | | |\n"; cout << "A | | |\n"; cout << " | | |\n"; cout << "\n"; cout << "\n"; cout << " | | | | |\n"; cout << "B | | | | |\n"; cout << " | | | | |\n"; cout << "\n"; cout << "\n"; cout << " | | | | | | |\n"; cout << "C | | | | | | |\n"; cout << " | | | | | | |\n"; cout << "\n";*/ } void Rules() { cout << "\n\n*** Stick Game Rules ***\n"; cout << "\n"; cout << "(1) Two players alternate moves until all sticks are gone.\n"; cout << "(2) A single turn consists of removing as many sticks as des1ired from one row.\n"; cout << "(3) The last player to remove a stick has lost the game.\n"; cout << "\n\n"; } void Menu()//int C) { cout << "\n\n-=-=Menu=-=-\n\n"; cout << "(1) New Game - Human vs. AI (Human First)\n"; cout << "(2) New Game - Human vs. AI (AI First)\n"; cout << "(3) New Game - Human vs. Human\n"; cout << "(4) Rules\n"; cout << "(5) Exit\n\n"; } Coord MoveAI(int Sticks[3]) { Coord AIMove; int random = rand(); //Helps keep things random in my opinion //Uncertain Conditionals //Losing Conditionals //Test to see if this is the second move if ((Sticks[0] == 2) && (Sticks[1] == 5) && (Sticks[2] == 7)) { AILost = true; AIMove.Line = (random % 2) + 'B'; AIMove.Num = 1; return(AIMove); } if ((Sticks[0] == 3) && (Sticks[1] == 4) && (Sticks[2] == 7)) { AILost = true; AIMove.Line = ((random % 2) * 2) + 'A'; AIMove.Num = 1; return(AIMove); } if ((Sticks[0] == 3) && (Sticks[1] == 5) && (Sticks[2] == 6)) { AILost = true; AIMove.Line = (random % 2) + 'A'; AIMove.Num = 1; return(AIMove); } //Check for 2 4 6 if ((Sticks[0] == 2) && (Sticks[1] == 4) && (Sticks[2] == 6)) { AILost = true; AIMove.Line = ((random % 2) * 3) + 'A'; //Randomly pick one of the rows AIMove.Num = 1; //Don't give away that we have lost return(AIMove); } //Check for two even rows > 1 if ((Sticks[0] == Sticks[1]) && (Sticks[2] == 0) && (Sticks[0] > 1)) { AILost = true; AIMove.Line = (random % 2) + 'A'; //Randomly pick one of the two rows AIMove.Num = (Sticks[0] % 2) + (Sticks[0] / 2); //Remove half (round up) return(AIMove); } if ((Sticks[0] == Sticks[2]) && (Sticks[1] == 0) && (Sticks[0] > 1)) { AILost = true; AIMove.Line = ((random % 2) * 2) + 'A'; //Randomly pick one of the two rows AIMove.Num = (Sticks[0] % 2) + (Sticks[0] / 2); //Remove half (round up) return(AIMove); } if ((Sticks[1] == Sticks[2]) && (Sticks[0] == 0) && (Sticks[1] > 1)) { AILost = true; AIMove.Line = (random % 2) + 'B'; //Randomly pick one of the two rows AIMove.Num = (Sticks[1] % 2) + (Sticks[1] / 2); //Remove half (round up) return(AIMove); } //Check for 3 2 1 if ((Sticks[0] == 3) && (((Sticks[1] == 1) && (Sticks[2] == 2)) || ((Sticks[1] == 2) && (Sticks[2] == 1)))) { AILost = true; AIMove.Line = 'A'; AIMove.Num = 2; return(AIMove); } if ((Sticks[1] == 3) && (((Sticks[0] == 1) && (Sticks[2] == 2)) || ((Sticks[0] == 2) && (Sticks[2] == 1)))) { AILost = true; AIMove.Line = 'B'; AIMove.Num = 2; return(AIMove); } if ((Sticks[2] == 3) && (((Sticks[0] == 1) && (Sticks[1] == 2)) || ((Sticks[0] == 2) && (Sticks[1] == 1)))) { AILost = true; AIMove.Line = 'C'; AIMove.Num = 2; return(AIMove); } //Check for 5 4 1 if ((Sticks[0] == 1) && (((Sticks[1] == 4) && (Sticks[2] == 5)) || ((Sticks[1] == 5) && (Sticks[2] == 4)))) { AILost = true; AIMove.Line = (random % 2) + 'B'; AIMove.Num = 2; return(AIMove); } //Check for 1 1 1 if ((Sticks[0] == 1) && (Sticks[1] == 1) && (Sticks[2] == 1)) { AILost = true; AIMove.Line = (random % 3) + 'A'; AIMove.Num = 1; return(AIMove); } //Check for 1 0 0 if ((Sticks[0] == 1) && (Sticks[1] == 0) && (Sticks[2] == 0)) { AILost = true; AIMove.Line = 'A'; AIMove.Num = 1; return(AIMove); } if ((Sticks[0] == 0) && (Sticks[1] == 1) && (Sticks[2] == 0)) { AILost = true; AIMove.Line = 'B'; AIMove.Num = 1; return(AIMove); } if ((Sticks[0] == 0) && (Sticks[1] == 0) && (Sticks[2] == 1)) { AILost = true; AIMove.Line = 'C'; AIMove.Num = 1; return(AIMove); } //Winning Conditionals //Test to see if this is the first move if ((Sticks[0] == 3) && (Sticks[1] == 5) && (Sticks[2] == 7)) { AIMove.Line = (random % 3) + 'A'; //Randomly pick one of the three rows AIMove.Num = 1; return(AIMove); } //Try to force 2 4 6 on the human player if ((Sticks[0] == 2) && (Sticks[1] == 4) && (Sticks[2] == 7)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = 1; return(AIMove); } if ((Sticks[0] == 2) && (Sticks[1] == 5) && (Sticks[2] == 6)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = 1; return(AIMove); } if ((Sticks[0] == 3) && (Sticks[1] == 4) && (Sticks[2] == 6)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = 1; return(AIMove); } //Check to see if only one row has sticks if ((Sticks[0] > 1) && (Sticks[1] == 0) && (Sticks[2] == 0)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 1; return(AIMove); } if ((Sticks[1] > 1) && (Sticks[0] == 0) && (Sticks[2] == 0)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 1; return(AIMove); } if ((Sticks[2] > 1) && (Sticks[1] == 0) && (Sticks[0] == 0)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 1; return(AIMove); } //Check to see if only two rows remain, at least one containing only 1 stick if ((Sticks[0] == 0) && (Sticks[1] == 1) && (Sticks[2] >= 1)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2]; return(AIMove); } if ((Sticks[0] == 0) && (Sticks[2] == 1) && (Sticks[1] >= 1)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1]; return(AIMove); } if ((Sticks[1] == 0) && (Sticks[0] == 1) && (Sticks[2] >= 1)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2]; return(AIMove); } if ((Sticks[1] == 0) && (Sticks[2] == 1) && (Sticks[0] >= 1)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0]; return(AIMove); } if ((Sticks[2] == 0) && (Sticks[1] == 1) && (Sticks[0] >= 1)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0]; return(AIMove); } if ((Sticks[2] == 0) && (Sticks[0] == 1) && (Sticks[1] >= 1)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1]; return(AIMove); } //Check to see if AI can impose 1 1 1 on the human if ((Sticks[0] == 1) && (Sticks[1] == 1) && (Sticks[2] > 1)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 1; return(AIMove); } if ((Sticks[0] == 1) && (Sticks[1] > 1) && (Sticks[2] == 1)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 1; return(AIMove); } if ((Sticks[0] > 1) && (Sticks[1] == 1) && (Sticks[2] == 1)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 1; return(AIMove); } //Check to see if AI can impose two even rows > 1 on the human if ((Sticks[0] == Sticks[1]) && (Sticks[0] > 1) && (Sticks[2] > 0)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2]; return(AIMove); } if ((Sticks[0] == Sticks[2]) && (Sticks[0] > 1) && (Sticks[1] > 0)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1]; return(AIMove); } if ((Sticks[1] == Sticks[2]) && (Sticks[1] > 1) && (Sticks[0] > 0)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0]; return(AIMove); } //Same as above // different wa though // just a separater if ((Sticks[0] == 0) && (Sticks[1] > Sticks[2])) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - Sticks[2]; return(AIMove); } if ((Sticks[0] == 0) && (Sticks[1] < Sticks[2])) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - Sticks[1]; return(AIMove); } if ((Sticks[1] == 0) && (Sticks[0] > Sticks[2])) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - Sticks[2]; return(AIMove); } if ((Sticks[1] == 0) && (Sticks[0] < Sticks[2])) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - Sticks[0]; return(AIMove); } if ((Sticks[2] == 0) && (Sticks[1] > Sticks[0])) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - Sticks[0]; return(AIMove); } if ((Sticks[2] == 0) && (Sticks[1] < Sticks[0])) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - Sticks[1]; return(AIMove); } //Check if AI can impose 3 2 1 on human player (Will take 18 if's) if ((Sticks[0] == 3) && (Sticks[1] == 2) && (Sticks[2] > 1)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 1; return(AIMove); } if ((Sticks[0] == 3) && (Sticks[1] > 1) && (Sticks[2] == 2)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 1; return(AIMove); } if ((Sticks[1] == 3) && (Sticks[0] == 2) && (Sticks[2] > 1)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 1; return(AIMove); } if ((Sticks[1] == 3) && (Sticks[0] > 1) && (Sticks[2] == 2)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 1; return(AIMove); } if ((Sticks[2] == 3) && (Sticks[1] == 2) && (Sticks[0] > 1)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 1; return(AIMove); } if ((Sticks[2] == 3) && (Sticks[1] > 1) && (Sticks[0] == 2)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 1; return(AIMove); } //Same as above *********** Separator **************** so I don't go crazy (At least not yet!!!) if ((Sticks[0] == 2) && (Sticks[1] == 1) && (Sticks[2] > 3)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 3; return(AIMove); } if ((Sticks[0] == 2) && (Sticks[1] > 3) && (Sticks[2] == 1)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 3; return(AIMove); } if ((Sticks[1] == 2) && (Sticks[0] == 1) && (Sticks[2] > 3)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 3; return(AIMove); } if ((Sticks[1] == 2) && (Sticks[0] > 3) && (Sticks[2] == 1)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 3; return(AIMove); } if ((Sticks[2] == 2) && (Sticks[1] == 1) && (Sticks[0] > 3)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 3; return(AIMove); } if ((Sticks[2] == 2) && (Sticks[1] > 3) && (Sticks[0] == 1)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 3; return(AIMove); } //Same as above *********** Separator **************** Still not crazy, yet if ((Sticks[0] == 1) && (Sticks[1] == 3) && (Sticks[2] > 2)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 2; return(AIMove); } if ((Sticks[0] == 1) && (Sticks[1] > 2) && (Sticks[2] == 3)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 2; return(AIMove); } if ((Sticks[1] == 1) && (Sticks[0] == 3) && (Sticks[2] > 2)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 2; return(AIMove); } if ((Sticks[1] == 1) && (Sticks[0] > 2) && (Sticks[2] == 3)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 2; return(AIMove); } if ((Sticks[2] == 1) && (Sticks[1] == 3) && (Sticks[0] > 2)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 2; return(AIMove); } if ((Sticks[2] == 1) && (Sticks[1] > 2) && (Sticks[0] == 3)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 2; return(AIMove); } //Check if AI can impose 5 4 1 on human player if ((Sticks[0] == 1) && (Sticks[1] == 4) && (Sticks[2] > 5)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 5; return(AIMove); } if ((Sticks[0] == 1) && (Sticks[1] == 5) && (Sticks[2] > 4)) { AIWon = true; AILost = false; AIMove.Line = 'C'; AIMove.Num = Sticks[2] - 4; return(AIMove); } if ((Sticks[0] == 1) && (Sticks[1] > 4) && (Sticks[2] == 5)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 4; return(AIMove); } if ((Sticks[0] == 1) && (Sticks[1] > 5) && (Sticks[2] == 4)) { AIWon = true; AILost = false; AIMove.Line = 'B'; AIMove.Num = Sticks[1] - 5; return(AIMove); } if ((Sticks[0] > 1) && (Sticks[1] == 4) && (Sticks[2] == 5)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 1; return(AIMove); } if ((Sticks[0] > 1) && (Sticks[1] == 5) && (Sticks[2] == 4)) { AIWon = true; AILost = false; AIMove.Line = 'A'; AIMove.Num = Sticks[0] - 1; return(AIMove); } //Any moves I missed Dump = true; if (! AILost) cout << "SEVERE AI ERROR..."; else cout << "BASIC AI ERROR..."; if (Sticks[0] > 0) { AIMove.Line = 'A'; AIMove.Num = Sticks[0]; return(AIMove); } if (Sticks[1] > 0) { AIMove.Line = 'B'; AIMove.Num = Sticks[1]; return(AIMove); } if (Sticks[2] > 0) { AIMove.Line = 'C'; AIMove.Num = Sticks[2]; return(AIMove); } } void DumpGame() { ofstream fout("debug.out"); //Open debug output file End = Begin; while(End != NULL) { fout << End->Line << " " << End->Num << " " << End->Player << endl; End = End->next; } fout.close(); } /*void DebugOutput(int Sticks[3]) { fout << "\n"; for (int X = 0; X < 3; X++) { for (int Y = 0; Y < 3; Y++) { if (Y == 1) { switch (X) { case 0: fout << "A"; break; case 1: fout << "B"; break; case 2: fout << "C"; break; } } else fout << " "; for (int Z = 0; Z < Sticks[X]; Z++) fout << " |"; fout << "\n"; } fout << "\n\n"; } }*/