Jump to content
  • Advertisement
Sign in to follow this  
kevtimc

TicTacToe, I'm real close. . .

This topic is 4515 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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;
                                      }
                                      
}

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 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)
{
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;
}
}

}

Share this post


Link to post
Share on other sites
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. . .

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!