#include <iostream>#include <vector>#include <algorithm>#include <ctime>using namespace std;const char PLAYER_SYMBOL = 'X';const char PC_SYMBOL = 'O';const char DEFAULT_SYMBOL = '-';class TicTacToe{private: vector <int> freeNodes; // the free nodes vector <int> usedNodes; // the used nodes char board [3] [3]; // set the boardpublic: void setBoard () // set the board to empty { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { board [j] = '-'; } } } void setFreeNodes () { for (int i = 1; i <= 9; i++) { freeNodes.push_back (i); } } void printBoard () // print the board on the screen { cout << "\n"; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { cout << board [j] << " "; } cout << "\n"; } } int getNode () { int node; cout << "\n" << "Enter a number from 1-9: "; cin >> node; return node; } bool checkInput (int node) { vector <int>::iterator it; for (it = freeNodes.begin(); it < freeNodes.end(); it++) { if (node == *it) { return true; } } cout << "\n" << "Invalid input."; return false; } void applyInputToBoard (int node, bool playsP1, bool playsPC) { int i, j; if (node % 3 != 0) { i = node / 3; j = node % 3 - 1; } else { i = node / 3 - 1; j = 2; } if (playsP1 == true) board [j] = PLAYER_SYMBOL; // ('X') else board [j] = PC_SYMBOL; // ('O') } void undoInputToBoard (int node) // undo the pc's move (see pcNode) { int i, j; if (node % 3 != 0) { i = node / 3; j = node % 3 - 1; } else { i = node / 3 - 1; j = 2; } // undo the move board [j] = DEFAULT_SYMBOL; // ('-') } void addRemoveNodes (int node) { usedNodes.push_back (node); // add the node in usedNodes sort (usedNodes.begin(), usedNodes.end() ); //remove the node from freeNodes int position = 0; vector <int>::const_iterator it; for (it = freeNodes.begin(); it < freeNodes.end(); it++) { if (*it == node) { break; } position ++; // position is the position of the number (node) in the vector } /*when (*it = node), position isn't increased, because it breaks the loop. But that doesn't matter because when erase, I have to delete -1 because it starts from the the first element. position is already -1 so I don't have to subtract anything. eg it should have been "freeNodes.erase (freeNodes.begin() + position - 1);", but position is -1 from the node's position, so, it's ok.*/ freeNodes.erase (freeNodes.begin() + position); sort (freeNodes.begin(), freeNodes.end() ); } int checkWin () { enum Won { none = 0, winsP1 = 1, winsPC = 2 }; //horizontal for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board [j] != DEFAULT_SYMBOL && board [j+1] != DEFAULT_SYMBOL && board [j+2]) { if (board [j] == board [j+1]) { if (board [j] == board [j+2]) { if (board [j] == PLAYER_SYMBOL) return winsP1; else return winsPC; } } } } } //vertical for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board [j] != DEFAULT_SYMBOL && board [i+1] [j] != DEFAULT_SYMBOL && board [i+2] [j]) { if (board [j] == board [i+1] [j]) { if (board [j] == board [i+2] [j]) { if (board [j] == PLAYER_SYMBOL) return winsP1; else return winsPC; } } } } } //diagonal for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (board [j] != DEFAULT_SYMBOL && board [i+1] [j+1] != DEFAULT_SYMBOL && board [i+2] [j+2] != DEFAULT_SYMBOL) { if (board [0] [0] == board [i+1] [j+1]) { if (board [0] [0] == board [i+2] [j+2]) { if (board [j] == PLAYER_SYMBOL) return winsP1; else return winsPC; } } } } } return none; } int pcNode () { vector <int>::iterator it = freeNodes.begin(); // for every free node, check if can win for (it = freeNodes.begin(); it < freeNodes.end(); it++) { bool winsP1, winsPC; applyInputToBoard (*it, false, true); int win = checkWin(); if (win == 1) winsP1 = true; else if (win == 2) winsPC = true; if (winsPC == true) // if this is a winning move, done return *it; else // if not, undo the move :) { undoInputToBoard (*it); } } ///// srand (static_cast<unsigned int>(time(NULL))); int node; int randomNode = 1 + rand() % 9; it = freeNodes.begin(); while (it < freeNodes.end() ) { if (randomNode == *it) // if node is free { int i = randomNode; return randomNode; } it++; if (it == freeNodes.end() ) // if the node is not in freeNodes (if it's not free), repeat again { it = freeNodes.begin(); randomNode = 1 + rand () % 9; } } node = randomNode; return node; } void print() { cout << "\n" << "Used nodes: "; vector <int>::const_iterator it; for (it = usedNodes.begin(); it < usedNodes.end(); it++) { cout << *it << " "; } cout << "\n" << "Free nodes: "; for (it = freeNodes.begin(); it < freeNodes.end(); it++) { cout << *it << " "; } cout << "\n"; }};int main(){ cout << "Tic Tac Toe" << "\t" << "by Minas Mina" << "\n" << "You: X" << "\t" << "PC: O"; TicTacToe game; // create an object for the class game.setBoard(); // set the board game.setFreeNodes(); bool playsP1 = true, playsPC = false; bool winsP1 = false, winsPC = false; while ( (winsP1 == false) && (winsPC == false) ) { if (playsP1 == true) { int node; bool acceptInput = false; while (acceptInput == false) { node = game.getNode(); acceptInput = game.checkInput (node); // check if the node is free } game.addRemoveNodes (node); game.applyInputToBoard (node, playsP1, playsPC); //update the board int win = game.checkWin(); if (win == 1) winsP1 = true; else if (win == 2) winsPC = true; game.printBoard(); playsP1 = false; playsPC = true; game.print(); } if (winsP1 == true || winsPC == true) break; if (playsPC == true) { int node = game.pcNode (); cout << "\n" << "The pc plays " << node; game.addRemoveNodes (node); game.applyInputToBoard (node, playsP1, playsPC); //update the board int win = game.checkWin(); if (win == 1) winsP1 = true; else if (win == 2) winsPC = true; game.printBoard(); playsP1 = true; playsPC = false; game.print(); } } if (winsP1 == true) cout << "\n" << "You win!!"; else cout << "\n" << "You lose.."; cout << "\n"; system ("PAUSE"); return 0;}
I only need to make the AI better (pcNode function). It currently wins when it can, else it places in random nodes. :)