/************************************************************************************* * Filename: A3Part3.cpp Scott O'Brien * * Login: sob401 * * LAB: A * * Assignment: 3, Q3 * * File Description: Connect 4 game * * * * * * * * Date Last Modified: 09/05/2007 * *************************************************************************************/ #include #include #include using namespace std; const int COL = 8; const int ROW = 6; struct GameState { char board[ROW][COL]; char symbol; char nextTurn; }; void drawHeader(); char chooseOption(); void initialiseBoard(GameState &); void drawBoard(GameState); int playMove(GameState &); void computerMove(GameState &); bool makeMove(GameState &, int); int checkWinner(GameState &); bool saveGame(GameState, char[255]); bool loadGame(GameState &, char[255]); bool checkDraw(GameState); int main () { //Set up the game board drawHeader(); char option = chooseOption(); GameState game; initialiseBoard(game); int MoveResult; int winner; char playAgain; char inputResult; do { switch(option) { case 'a': cout << "\nPlaying against computer, good luck!\n"; do { drawBoard(game); if(checkDraw(game)) { cout << "\nDRAW! No more moves possible, game over!"; option = chooseOption(); } else { MoveResult = playMove(game); winner = checkWinner(game); if(MoveResult && !winner && !checkDraw(game)) { drawBoard(game); computerMove(game); winner = checkWinner(game); } } } while(MoveResult && !winner && !checkDraw(game)); if(MoveResult) switch(winner) { case 0: cout << "\n\nDRAW! No more moves possible, game over!\n"; break; case 1: cout << "\n\nCongratulations, you have beaten the computer!\n\n"; break; case 2: drawBoard(game); cout << "\n\nBad luck, the computer beat you.\n\n"; } if(MoveResult) { cout << "Do you want to start a new game (y/n)?: "; cin >> playAgain; cin.clear(); //Clear the input stream inclase more then one input was entered playAgain = tolower(playAgain); if(playAgain == 'n') option = 'd'; } else { cout << "Do you want to save the game? :"; cin >> inputResult; cin.clear(); // Clear the input stream in case more then one input character was sent. inputResult = tolower(inputResult); if(inputResult == 'y') { cout << "Enter name of file to save as: "; char fileName[255]; cin >> fileName; if(saveGame(game, fileName)) cout << "\nGame saved!\n"; } } initialiseBoard(game); option = chooseOption(); break; case 'b': bool isDraw; do { winner = checkWinner(game); isDraw = checkDraw(game); drawBoard(game); switch(winner) { case 0: if(!isDraw) MoveResult = playMove(game); else cout << "\nDRAW! No more moves possible, game over!\n"; break; case 1: cout << "\nPlayer 1 is the winner\n"; break; case 2: cout << "\nPlayer 2 is the winner\n"; } } while(MoveResult && !winner && !isDraw); //Ask the user if they wish to save the game if there is no result if(!winner && !isDraw) { cout << "Do you want to save the game? :"; cin >> inputResult; cin.clear(); //Clear the input stream inclase more then one input was entered inputResult = tolower(inputResult); if(inputResult == 'y') { cout << "Enter name of file to save as: "; char fileName[255]; cin >> fileName; if(saveGame(game, fileName)) cout << "\nGame saved!\n"; } else { cout << "Do you want to start a new game (y/n)?: "; cin >> inputResult; cin.clear(); //Clear the input stream inclase more then one input was entered inputResult = tolower(inputResult); } } else inputResult = 'y'; initialiseBoard(game); if(inputResult == 'n') option = 'd'; else option = chooseOption(); break; case 'c': char fileName[255]; cout << "Enter name of game to load: "; cin >> fileName; loadGame(game, fileName); option = chooseOption(); break; } } while(option != 'd'); cout << "\nThanks for playing Connect Four, the game of the clever people!"; return 0; } void drawHeader() { cout << "*********************************************************\n" << "* Connect Four *\n" << "*********************************************************\n" << "Welcome to the Connect Four computer game. You can choose\n" << "to play against another player or against the computer\n" << "(not implemented in this version).\n" << "In this game the first player to position four of his/her\n" << "pieces on a line will win. The line can be horizontal,\n" << "vertical or at an angle, but the 4 pieces must be next to\n" << "each other.\n" << "*********************************************************\n"; } char chooseOption() { char choice; //Options is in a loop to make sure a valid option gets entered. do { cout << "*************************************\n" << "* Choose an Option *\n" << "*************************************\n" << "* a) Play against the computer *\n" << "* b) Play against another player *\n" << "* c) Load game *\n" << "* d) Quit *\n" << "*************************************\n" << "Enter your choice: "; cin >> choice; cin.clear(); choice = tolower(choice); if(choice < 'a' || choice > 'd') cout << "Invalid input!\n\n"; } while(choice < 'a' || choice > 'd'); return choice; } void initialiseBoard(GameState &game) { for(int rowLoop=0; rowLoop < ROW; rowLoop++) for(int colLoop=0; colLoop < COL; colLoop++) game.board[rowLoop][colLoop] = '.'; game.nextTurn = '1'; game.symbol = 'O'; } void drawBoard(GameState game) { for(int rowLoop=0; rowLoop < ROW; rowLoop++) { for(int colLoop=0; colLoop < COL; colLoop++) cout << ' ' << game.board[rowLoop][colLoop]; cout << endl; } for(int i=1; i <= COL; i++) cout << ' ' << i; cout << endl; } int playMove(GameState &game) { //Gets a number from the user, and loops untill a valid number (between 1-COL) has been chosen //And there is room for the user to move in this column. int choice; cout << "Player " << game.nextTurn << " move (1-" << COL << ", 0 to quit): "; cin >> choice; while(cin.fail()) //in case characters are entered { cout << "\nInvalid input!\n"; cin.clear(); //clear flag so that input can be read cin.ignore(200,'\n'); //flush the input buffer cout << "Player " << game.nextTurn << " move (1-" << COL << ", 0 to quit): "; cin >> choice; } while((choice < 0 || choice > COL) || (choice != 0 && makeMove(game, choice-1) == false)) { if(choice >= 0 && choice <= COL) cout << "\nSorry no more room in this column...\n\n"; else cout << "\nInvalid input!\n"; cout << "Player " << game.nextTurn << " move (1-" << COL << ", 0 to quit): "; cin >> choice; while(cin.fail()) //in case characters are entered { cout << "\nInvalid input!\n"; cin.clear(); //clear flag so that input can be read cin.ignore(200,'\n'); //flush the input buffer cout << "Player " << game.nextTurn << " move (1-" << COL << ", 0 to quit): "; cin >> choice; } } if(!choice) return 0; // makeMove(game, choice-1); return choice; } void computerMove(GameState &game) { srand(time(0)); int move; do move = rand() % 8; while (!makeMove(game, move)); cout << "Computer move: " << move + 1 << endl; } bool makeMove(GameState &game, int slot) { /* The purpose of this function is to simulate a 'drop' of a piece in a column. This function will return false if the move can't be made, or True if the move can be made, and will adjust the GameState to reflect the desired move */ if(game.board[0][slot] != '.') return false; bool done = false; for(int i=ROW-1; i >= 0 && !done; i--) if(game.board[i][slot] == '.') { game.board[i][slot] = game.symbol; game.symbol = (game.symbol == 'X' ? 'O' : 'X'); game.nextTurn = (game.nextTurn == '1' ? '2' : '1'); done = true; } return true; } int checkWinner(GameState &game) { //Check the rows char lastChr; int counter; for(int row = ROW; row >= 0; row--) { lastChr = '.'; counter = 1; for(int col = 0; col < COL; col++) if(lastChr != '.' && game.board[row][col] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[row][col]; } } for(int col = 0; col < COL; col++) { lastChr = '.'; counter = 1; for(int row = 0; row < ROW; row++) if(lastChr != '.' && game.board[row][col] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[row][col]; } } //Check diagonals for(int row = 2; row >= 0; row--) { lastChr = '.'; counter = 1; for(int col = 0; col < COL - row - 2; col++) if(lastChr != '.' && game.board[row+col][col] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[row+col][col]; } } lastChr = '.'; counter = 1; for(int i=0; i< 6; i++) if(lastChr != '.' && game.board[i][i+1] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[i][i+1]; } for(int col = 2; col < COL - 3; col++) { lastChr = '.'; counter = 1; for(int row = 0; row < ROW -col +2; row++) if(lastChr != '.' && game.board[row][col+row] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[row][col+row]; } } for(int row=3; row < 6; row++) { lastChr = '.'; counter = 1; for(int col=0; col < row + 1; col++) if(lastChr != '.' && game.board[row-col][col] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[row-col][col]; } } lastChr = '.'; counter = 1; for(int i=0; i < 6; i++) if(lastChr != '.' && game.board[5-i][i+1] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[5-i][i+1]; } for(int col=0; col < 3; col++) { lastChr = '.'; counter = 1; for(int row=col; row < 6; row++) if(lastChr != '.' && game.board[5-row+col][row+2] == lastChr) { if(++counter == 4) return (lastChr == 'O' ? 1 : 2); } else { counter = 1; lastChr = game.board[5-row+col][row+2]; } } // } return 0; } bool saveGame(GameState game, char fileName[255]) { ofstream saveFile(fileName, ios::out); if(!saveFile) { cout << "Error opening file. The game could not be saved!\n"; return false; } for(int rowLoop=0; rowLoop < ROW; rowLoop++) { for(int colLoop=0; colLoop < COL; colLoop++) saveFile.put(game.board[rowLoop][colLoop]); if(rowLoop < ROW -1) saveFile.put('#'); } saveFile.put(game.symbol); saveFile.put(game.nextTurn); saveFile.close(); return true; } bool loadGame(GameState &game, char fileName[255]) { ifstream loadFile; loadFile.open(fileName); if(!loadFile) { cout << "Error opening the file. The game could not be loaded!\n"; return false; } for(int rowLoop=0; rowLoop < ROW && !loadFile.fail(); rowLoop++) { for(int colLoop=0; colLoop < COL; colLoop++) loadFile.get(game.board[rowLoop][colLoop]); if(rowLoop < ROW -1) loadFile.get(); } loadFile.get(game.symbol); loadFile.get(game.nextTurn); if(loadFile.fail()) { cout << "Error reading from the file. The game could not be loaded!\n"; return false; } cout << "\nGame loaded!\n\n"; loadFile.close(); return true; } bool checkDraw(GameState game) { bool isDraw = true; for(int col = 0; col < COL && isDraw; col++) if(game.board[0][col] == '.') isDraw = false; return isDraw; }