TicTacToe, I'm real close. . .

Started by
6 comments, last by Anon Mike 17 years, 9 months ago
Ok, I've got it to compile, I've got the turns to switch, everything seems to be working fine with one minor detail. The computer won't make more than one move! Compile it for yourself and see what I mean. I've been looking at this code and evaluating the logic and, it's frusterating. Here's the code:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

//function prototypes
void DisplayInstructions();
char* GetHumanTurn();
char* AskYesorNo(string question);
char* GetOpponentTurn(char* Human);
void DisplayBoard(const vector<char>& board);
char* winner(vector<char>* board);
int GetHumanMove(const vector<char>* board);
bool ItisLegal(const vector<char> board, int move);
int AskNumber(string question);
int GetComputerMove(vector<char> board, char* Computer);

//characters
char EMPTY = ' ';
char X = 'X';
char O = 'O';
char NO_ONE = 'N';
char TIE = 'T';

int main()
{
    //setting up the game
    int move;
    DisplayInstructions();
    vector<char> board(9, EMPTY);
    char* Human = GetHumanTurn();
    char* Computer = GetOpponentTurn(Human);
    char* turn = &X;
    
    //the game loop
    while(winner(&board) == &NO_ONE)
    {
                         if(*Human == *turn)
                         {
                                   move = GetHumanMove(&board);
                                   board[move] = *Human;
                                   }
                         if(*Computer == *turn)
                         {
                                   move = GetComputerMove(board, Computer);
                                   board[move] = *Computer;
                                   }
                        cout << endl << endl;           
                        DisplayBoard(board);
                        //now switch the turn symbol from X to O or O to X
                        turn = GetOpponentTurn(turn);
                        }

    system("PAUSE");
    return 0;
}

void DisplayInstructions()
{
     cout << "Welcome to Tic Tac Toe! \nWhere you will test your might against man's greatest creation, the computer!\nBe prepared to go one on one with the processor as you battle for supremacy,\nand the entire human race!" << endl;
     cout << "The rules are simple, pick a number that corresponds with the position on the \nboard.\n\nExample board:\n\n";
     cout << "| 0 | - - | 1 | - - | 2 |\n\n| 3 | - - | 4 | - - | 5 |\n\n| 6 | - - | 7 | - - | 8 |" << endl;
}

char* GetHumanTurn()
{
      char* HumanTurn = AskYesorNo("\nDo you want to go first? (y or n)");
      if(*HumanTurn == X)
      {
                    return &X;
                    }
      else
      {
          return &O;
          }
}

char* AskYesorNo(string question)
{
      char answer;
      cout << endl;
      do
      {
      cout << question;
      cin >> answer;
      }
      while(answer != 'y' && answer != 'n');
      if(answer == 'y')
      {
                return &X;
                }
                if(answer == 'n')
                {
                          return &O;
                          }
}     

char* GetOpponentTurn(char* Human)
{
      if(*Human == X)
      {
                return &O;
                }
                else
                {
                    return &X;
                    }
}

void DisplayBoard(const vector<char>& board)
{
     cout << "| " << board[0] <<" | - - | " << board[1] << " | - - | " << board[2] << " |\n\n| " << board[3] <<" | - - | " << board[4] << " | - - | "<< board[5] << " |\n\n| " << board[6] << " | - - | " << board[7] << " | - - | " << board[8] << " |" << endl;
}     

char* winner(vector<char>* board)
{
      int WINNING_MOVES[8][3] = { {0, 1, 2},
                            {3, 4, 5},
                            {6, 7, 8},
                            {0, 3, 6},
                            {1, 4, 7},
                            {2, 5, 8},
                            {0, 4, 8},
                            {2, 4, 8} };
                            
      const int ALL_BOARDS = 8;
      
      for(int i = 0; i < ALL_BOARDS; ++i)
      {
              if( ((*board)[WINNING_MOVES[0]] != EMPTY) &&
              ((*board)[WINNING_MOVES[0]] == (*board)[WINNING_MOVES[1]]) &&
              ((*board)[WINNING_MOVES[1]] == (*board)[WINNING_MOVES[2]]) )
              {
                                             return &(*board)[WINNING_MOVES[0]];
                                             }
                                             }
              if(count(board->begin(), board->end(), EMPTY) == 0)
              {
                                       return &TIE;
                                       }
                                       
                                       return &NO_ONE;
}
              
int GetHumanMove(const vector<char>* board)
{
    
    int move = AskNumber("Where do you want to move? (0-8)");
    while(!ItisLegal(*board, move))
    {
                                   cout << endl << "That space is occupied. . . choose another." << endl;
                                   move = AskNumber("Where do you want to move? (0-8)");
}
return move;
}              
               
int AskNumber(string question)
{
     int move;
     do 
     {
     cout << endl << question;
     cin >> move;
     }
     while(move < 0 || move > 8);
     return move;
}

bool ItisLegal(const vector<char> board, int move)
{
     return (board[move] == EMPTY);
}

int GetComputerMove(vector<char> board, char* Computer)
{
         const int MAX_SPACES = 9;
         for(int move = 0; move < MAX_SPACES; ++move)
         {
                 board[move] = *Computer;
                 if(ItisLegal(board, move))
                 {
                                      if(*(winner(&board)) == *Computer)
                                      {
                                                        return move;
                                                        }
                                                        }
                                                        board[move] = EMPTY;
                                                        }
         
         char* Human = GetOpponentTurn(Computer);
         
         for(int move = 0; move < MAX_SPACES; ++move)
         {
                 board[move] = *Human;
                 if(ItisLegal(board, move))
                 {
                                      if(*(winner(&board)) == *Human)
                                      {
                                                        return move;
                                                        }
                                                        }
                                                        board[move] = EMPTY;
                                                        }
                                                        
         vector<int>AllMoves;
         AllMoves.push_back(0);
         AllMoves.push_back(1);
         AllMoves.push_back(2);
         AllMoves.push_back(3);
         AllMoves.push_back(4);
         AllMoves.push_back(5);
         AllMoves.push_back(6);
         AllMoves.push_back(7);
         AllMoves.push_back(8);
         random_shuffle(AllMoves.begin(), AllMoves.end());
         
         for(int move = 0; move < MAX_SPACES; ++move)
         {
                 AllMoves[move] = *Computer;
                 if(ItisLegal(board, move))
                 {
                                      return move;
                                      }
                                      AllMoves[move] = EMPTY;
                                      }
                                      
}

Advertisement
OK, let's take a look at this.

A) Please limit the length of a line to 80 characters.
B) You seem to have X & O as chars, yet you return them in such things as GetOppenentTurn, and GetHumanTurn as pointers. You then dereference the pointers to get the first character. Why not just have them returning chars in the first place?
C) The computer does make a move every time. But it always puts it in spot 0. Why? If you look at the code

for(int move = 0; move < MAX_SPACES; ++move)  {    board[move] = *Computer;    if(ItisLegal(board, move))      {        if(*(winner(&board)) == *Computer)          {            return move;          }      }    board[move] = EMPTY;  }


Step through this.
You're iterating through every spot on the board. You then procede to store the spot with the board with the computers value. You then check if it's empty, which it never will be, and then procede to make that value empty.

*Edit*
Later in the function

for(move = 0; move < MAX_SPACES; ++move)	{		AllMoves[move] = *Computer;		if(ItisLegal(board, move))		{			return move;		}		AllMoves[move] = EMPTY;	}


But the board at move 0 will always return true, since it was previously made empty.

D) Make sure if your function has a return value, to at least return something.

[Edited by - Nytegard on July 5, 2006 1:57:39 PM]
Not really in regards to your question... just an FYI..

You can use characters from the extended ASCII character set to draw a board with better borders (this might be restricted to IBM compatible pcs, which most people have anyway).

More specifically try this so you get an idea of how to actually see a portion of the extended ascii set:

for(int i = 179; i < 219; i++)   cout << (unsigned char) i << "\n";


Extended ASCII
Just a small note on style, try to keep your brackets lined up, especially when it comes to embedded if statements/loops/etc. Otherwise, it can get kind of confusing for someone trying to read your code.
Ok I revised the code so that chars wern't assigned before they were tested for legality, but I still get the same results. Here's my new code:

#include <iostream>#include <string>#include <vector>#include <algorithm>using namespace std;//function prototypesvoid DisplayInstructions();char* GetHumanTurn();char* AskYesorNo(string question);char* GetOpponentTurn(char* Human);void DisplayBoard(const vector<char>& board);char* winner(vector<char>* board);int GetHumanMove(const vector<char>* board);bool ItisLegal(const vector<char> board, int move);int AskNumber(string question);int GetComputerMove(vector<char> board, char* Computer);//characterschar EMPTY = ' ';char X = 'X';char O = 'O';char NO_ONE = 'N';char TIE = 'T';int main(){    //setting up the game    int move;    DisplayInstructions();    vector<char> board(9, EMPTY);    char* Human = GetHumanTurn();    char* Computer = GetOpponentTurn(Human);    char* turn = &X;        //the game loop    while(winner(&board) == &NO_ONE)    {                         if(*Human == *turn)                         {                                   move = GetHumanMove(&board);                                   board[move] = *Human;                                   }                         if(*Computer == *turn)                         {                                   move = GetComputerMove(board, Computer);                                   board[move] = *Computer;                                   }                        cout << endl << endl;                                   DisplayBoard(board);                        //now switch the turn symbol from X to O or O to X                        turn = GetOpponentTurn(turn);                        }    system("PAUSE");    return 0;}void DisplayInstructions(){     cout << "Welcome to Tic Tac Toe! \nWhere you will test your might against man's greatest creation, the computer!\nBe prepared to go one on one with the processor as you battle for supremacy,\nand the entire human race!" << endl;     cout << "The rules are simple, pick a number that corresponds with the position on the \nboard.\n\nExample board:\n\n";     cout << "| 0 | - - | 1 | - - | 2 |\n\n| 3 | - - | 4 | - - | 5 |\n\n| 6 | - - | 7 | - - | 8 |" << endl;}char* GetHumanTurn(){      char* HumanTurn = AskYesorNo("\nDo you want to go first? (y or n)");      if(*HumanTurn == X)      {                    return &X;                    }      else      {          return &O;          }}char* AskYesorNo(string question){      char answer;      cout << endl;      do      {      cout << question;      cin >> answer;      }      while(answer != 'y' && answer != 'n');      if(answer == 'y')      {                return &X;                }                if(answer == 'n')                {                          return &O;                          }}     char* GetOpponentTurn(char* Human){      if(*Human == X)      {                return &O;                }                else                {                    return &X;                    }}void DisplayBoard(const vector<char>& board){     cout << "| " << board[0] <<" | - - | " << board[1] << " | - - | " << board[2] << " |\n\n| " << board[3] <<" | - - | " << board[4] << " | - - | "<< board[5] << " |\n\n| " << board[6] << " | - - | " << board[7] << " | - - | " << board[8] << " |" << endl;}     char* winner(vector<char>* board){      int WINNING_MOVES[8][3] = { {0, 1, 2},                            {3, 4, 5},                            {6, 7, 8},                            {0, 3, 6},                            {1, 4, 7},                            {2, 5, 8},                            {0, 4, 8},                            {2, 4, 8} };                                  const int ALL_BOARDS = 8;            for(int i = 0; i < ALL_BOARDS; ++i)      {              if( ((*board)[WINNING_MOVES[0]] != EMPTY) &&              ((*board)[WINNING_MOVES[0]] == (*board)[WINNING_MOVES[1]]) &&              ((*board)[WINNING_MOVES[1]] == (*board)[WINNING_MOVES[2]]) )              {                                             return &(*board)[WINNING_MOVES[0]];                                             }                                             }              if(count(board->begin(), board->end(), EMPTY) == 0)              {                                       return &TIE;                                       }                                                                              return &NO_ONE;}              int GetHumanMove(const vector<char>* board){        int move = AskNumber("Where do you want to move? (0-8)");    while(!ItisLegal(*board, move))    {                                   cout << endl << "That space is occupied. . . choose another." << endl;                                   move = AskNumber("Where do you want to move? (0-8)");}return move;}                             int AskNumber(string question){     int move;     do      {     cout << endl << question;     cin >> move;     }     while(move < 0 || move > 8);     return move;}bool ItisLegal(const vector<char> board, int move){     return (board[move] == EMPTY);}int GetComputerMove(vector<char> board, char* Computer){         const int MAX_SPACES = 9;         for(int move = 0; move < MAX_SPACES; ++move)         {                 if(ItisLegal(board, move))                 {                                     board[move] = *Computer;                                      if(*(winner(&board)) == *Computer)                                      {                                                        return move;                                                        }                                                        }                                                        board[move] = EMPTY;                                                        }                  char* Human = GetOpponentTurn(Computer);                  for(int move = 0; move < MAX_SPACES; ++move)         {                 if(ItisLegal(board, move))                 {                                     board[move] = *Human;                                      if(*(winner(&board)) == *Human)                                      {                                                        return move;                                                        }                                                        }                                                        board[move] = EMPTY;                                                        }                                                                 vector<int>AllMoves;         AllMoves.push_back(0);         AllMoves.push_back(1);         AllMoves.push_back(2);         AllMoves.push_back(3);         AllMoves.push_back(4);         AllMoves.push_back(5);         AllMoves.push_back(6);         AllMoves.push_back(7);         AllMoves.push_back(8);         random_shuffle(AllMoves.begin(), AllMoves.end());                  for(int move = 0; move < MAX_SPACES; ++move)         {                 if(ItisLegal(board, move))                 {                                      return move;                                      }                                      }                                      }
UPDATE: D'oh I took out the emptying part and it seems to work, although the AI takes some weird moves. . . It barely ever blocks me when I'm about to win, but it does seem to be dead set on winning for itself. . .
After some more observation, the AI always begins with the 2nd spot, and dosen't seem as if it wants to block my moves first, I'll keep observing.
Quote:Original post by ju2wheels
Not really in regards to your question... just an FYI..

You can use characters from the extended ASCII character set to draw a board with better borders (this might be restricted to IBM compatible pcs, which most people have anyway).


It's limited to what code page the user has. So if you do something like that your app will probably print total garbage for the borders in (say) Japan or anywhere other than the US and to a lesser extent western europe. I would advice not even trying to go down that road. Even if you never intend to give this app to anybody outside the US it's just a bad habit to get into.
-Mike

This topic is closed to new replies.

Advertisement