Jump to content
  • Advertisement
Sign in to follow this  
rycon

Comments on my TicTacToe program

This topic is 4948 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

I have a TicTacToe program up and running. I would love to hear any comments on this. What I did right, what I did wrong. I want to learn from this so, fire away, just be constructive. If I did something wrong tell me why it is wrong. Thanks.

#include <iostream>
#include <stdlib.h>
#include <conio.h>
#include <time.h>

using namespace std;

void ShowMainTitle();
void ShowEndTitle();
char Menu();
char PlayGame(char mode);
void ShowOutcome(char result);
void DisplayBoard(char* board);
void wait(int seconds);
char ChooseSymbol();
bool GameWon(char* board);
void MakeMove(char* board, int playertype, char symbol);
void ComputerMove(char* board, char symbol);
void PlayerMove(char* board, char symbol);

// Constants for Game Mode
const char HUMAN_VS_HUMAN = '1';
const char HUMAN_VS_COMPUTER = '2';
const char COMPUTER_VS_COMPUTER = '3';
const char QUIT = '4';

// Constants for Game Outcome
const char TIE = 'T';

// Constants for Player Type
const int HUMAN = 1;
const int COMPUTER = 2;

/***************************************************************************
    Main 
***************************************************************************/
int main()
{
    ShowMainTitle();
  
    // Seed random number generator 
    srand(time(NULL));
    
    char mode;
    while((mode = Menu()) != QUIT)
    { 
        char outcome;
        outcome = PlayGame(mode);
        ShowOutcome(outcome);
    }
    
    ShowEndTitle();    
  
    return 0;
}


////////////////////////////////////////////////////////////////////////////
//
//  Tic Tac Toe Core Functions
//
////////////////////////////////////////////////////////////////////////////

/***************************************************************************
    Main game play function.  Keeps track of turns.  Call move and check_win
    functions. Returns the winning symbol or TIE.
***************************************************************************/
char PlayGame(char mode)
{
    char board[9] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};   
    int XPlayerType;
    int OPlayerType;
    
    // Set X or O to either Human or Computer                  
    switch(mode)
    {
    case HUMAN_VS_HUMAN:
        XPlayerType = HUMAN;
        OPlayerType = HUMAN;
        break;
    
    case HUMAN_VS_COMPUTER:
        char symbol;
        symbol = ChooseSymbol();
        if(symbol == 'X')
        {
            XPlayerType = HUMAN;
            OPlayerType = COMPUTER;
        }
        else {
            XPlayerType = COMPUTER;
            OPlayerType = HUMAN;
        }
        break;
        
    case COMPUTER_VS_COMPUTER:
        XPlayerType = COMPUTER;
        OPlayerType = COMPUTER;
        break;     
    }
                            
    int turn = 1;
    
    // Main game loop    
    while(turn <= 9)
    {
        DisplayBoard(board);
        
        if(turn % 2 == 1)
        {
            // X's turn
            MakeMove(board, XPlayerType, 'X');
            if(GameWon(board))
            {
                DisplayBoard(board);
                return 'X';
            }
        }
        else {
            // O's turn
            MakeMove(board, OPlayerType, 'O');
            if(GameWon(board))
            {
                DisplayBoard(board);
                return 'O';
            }
        }
       
        ++turn;  
    }
    
    // If loop completes game is a Tie.
    DisplayBoard(board);
    return TIE;
}

/***************************************************************************
    Determines the playertype and calls PlayerMove or ComputerMove accordingly.
***************************************************************************/
void MakeMove(char* board, int playertype, char symbol)
{
    if (playertype == COMPUTER)
        ComputerMove(board, symbol);
    else
        PlayerMove(board, symbol);
}

/***************************************************************************
    Gets the player move as input.  Processes the move and updates the game
    board.
***************************************************************************/
void PlayerMove(char* board, char symbol)
{
    bool validmove;
    do
    {
        cout << endl << endl;
        cout.width(32);
        cout << symbol << " Enter move -->  ";
        
        int move;
        move = getch();
        
        // Valid moves are 1-9, ascii values 49-57.
        if((move < 49) || (move > 57))
        {
            // Input is out of bounds. Reset display and flag move as invalid.
            system("cls");
            DisplayBoard(board);
            validmove = FALSE;
        }
        else {
            //Translate from ascii to array index.
            move = move - 49;
            if((board[move] == 'X') || (board[move] == 'O'))
            {
                // Square is full. Reset display and flag move as invalid.
                system("cls");
                DisplayBoard(board);
                validmove = FALSE;
            }
            else {
                // Valid move. Update game board and flag move as valid.
                board[move] = symbol;
                validmove = TRUE;
            }
        }
    }
    while(!validmove);
      
}

/***************************************************************************
    AI for computer moves. Finds legal move and updates game board.
***************************************************************************/
void ComputerMove(char* board, char symbol)
{
    char tempboard[9];
    char temp;
    char opponent;
      
    cout << endl << endl;
    cout.width(34);
    cout << symbol << " is moving..." << endl;
    
    wait(2);
    
    // Make a copy of game board to evalute potential moves.
    for(int i = 0; i < 9; ++i)
        tempboard = board;
   
    // If Computer Can win on next turn, take that move.
    // Loop over entire board evaluating a move a each square.   
    for(int i = 0; i < 9; ++i)
    {
        if((tempboard != 'X') && (tempboard != 'O'))
        {
            // Empty square.  Make move and check for win.
            temp = tempboard;
            tempboard = symbol;
            if(GameWon(tempboard))
            {
                // A win. Update game board.
                board = symbol;
                return;
            }
            // No win. Restore tempboard.
            tempboard = temp;
        }
    }
   
    // If Opponent Can win on next move, then block.
    // Determine opponent symbol
    if(symbol == 'X')
        opponent = 'O';
    else
        opponent = 'X';
      
    // Loop over entire board evaluating each square.
    for(int i = 0; i < 9; ++i)
    {
        if((tempboard != 'X') && (tempboard != 'O'))
        {
            // Empty square. Make move and check for win.
            temp = tempboard;
            tempboard =  opponent;
            if(GameWon(tempboard))
            {
                // A win.  Block.
                board = symbol;
                return;
            }
            // No win. Restore tempboard.
            tempboard = temp;
        }
    }
   
    // If center is empty, take that move.
    if((board[4] != 'X') && (board[4] != 'O'))
    {
        board[4] = symbol;
        return;
    }
     
    // Finally, make a random move.
    // Loop until find a legal random move. 
    do
    {
        int move = rand() % 9;
        if((board[move] == 'X') || (board[move] == 'O'))
            continue;
        board[move] = symbol;
        break;
    }
    while(true);
}

/***************************************************************************
    Checks all 8 possible win combinations. Returns TRUE if a win exists.
***************************************************************************/
bool GameWon(char* board)
{
#define CHECK(x,y,z) (board[x] == board[y] && board[x] == board[z])

    bool horizontal = CHECK(0,1,2) || CHECK(3,4,5) || CHECK(6,7,8);
    bool vertical = CHECK(0,3,6) || CHECK(1,4,7) || CHECK(2,5,8);
    bool diagonal = CHECK(0,4,8) || CHECK(2,4,6);
    
    return horizontal || vertical || diagonal;
    
#undef CHECK
}


////////////////////////////////////////////////////////////////////////////
//
//  Input Functions
//
////////////////////////////////////////////////////////////////////////////

/***************************************************************************
    Displays menu and gets user input. Returns 1 of 3 game modes, or QUIT.
***************************************************************************/
char Menu()
{
    char choice;
    
    do
    {
        system("cls");
        cout << endl << endl  << endl << endl;
        
        cout.width(50);
        cout << "Available Game Modes." << endl << endl;
        cout.width(46);
        cout << "1. Human vs Human" << endl;
        cout.width(49);
        cout << "2. Human vs Computer" << endl;
        cout.width(52);
        cout << "3. Computer vs Computer" << endl;
        cout.width(40);
        cout << "4. End Game"  << endl << endl << endl;
        
        cout.width(51);
        cout << "Select Game Mode -->  ";
        
        choice = getch();
    }
    while((choice < '1') || (choice > '4'));
    
    return choice;
}

/***************************************************************************
    Prompts player to choose X or O for their symbol
***************************************************************************/
char ChooseSymbol()
{
    char symbol;
    
    do
    {
        system("cls");
        cout << endl << endl << endl << endl <<endl;
        cout.width(60);
        cout << "Which symbol do you want (X or O)? -->  ";
       
        symbol = getch();
        
        // Convert to Caps.
        if(symbol == 'x')
            symbol = 'X';
        if(symbol == 'o')
            symbol = 'O';
    }
    while((symbol != 'X') && (symbol != 'O'));
               
    return symbol;
}


////////////////////////////////////////////////////////////////////////////
//
//  Display Functions
//
////////////////////////////////////////////////////////////////////////////

/***************************************************************************
    Displays a main title
***************************************************************************/
void ShowMainTitle()
{
    system("title TicTacToe");
    
    system("cls");
    cout << endl << endl  << endl << endl << endl << endl;
    cout.width(45);
    cout << "Tic Tac Toe" << endl << endl;
    cout.width(45);
    cout << "Version 1.0" << endl;
    
    wait(3);
}

/***************************************************************************
    Displays an end title
***************************************************************************/
void ShowEndTitle()
{
    system("cls");
    
    cout << endl << endl << endl << endl << endl << endl << endl;
    cout.width(57);
    cout << "Thank you for playing Tic Tac Toe." << endl; 
    wait(2);
}

/***************************************************************************
    Displays the game board
***************************************************************************/
void DisplayBoard(char* board)
{
 
    system("cls");
    cout << endl << endl << endl << endl << endl;
    
    cout.width(48);
    cout << "     |     |     " << endl;
    cout.width(34);
    cout << board[0] << "  |  " << board[1] << "  |  " << board[2]  << endl;
    cout.width(48);
    cout << "     |     |     " << endl;
    cout.width(48);
    cout << "-----------------" << endl;
    cout.width(48);
    cout << "     |     |     " << endl;
    cout.width(34);
    cout << board[3] << "  |  " << board[4] << "  |  " << board[5]  << endl;
    cout.width(48);
    cout << "     |     |     " << endl;
    cout.width(48);
    cout << "-----------------" << endl;
    cout.width(48);
    cout << "     |     |     " << endl;
    cout.width(34);
    cout << board[6] << "  |  " << board[7] << "  |  " << board[8]  << endl;
    cout.width(48);
    cout << "     |     |     " << endl;
    
       
}

/***************************************************************************
    Displays outcome of a game.
***************************************************************************/
void ShowOutcome(char result)
{
    cout << endl << endl << endl << endl << endl;
    
    if(result == TIE)
    {
        cout.width(57);
        cout << "The game was a tie. No one wins!!!" << endl;
    }
    else
    {
        cout.width(40);
        cout << "Congratulations ";
        cout << result;
        cout << ", you won!!!" << endl;
    }
        
    wait(3);
}


////////////////////////////////////////////////////////////////////////////
//
//  Utility Functions
//
////////////////////////////////////////////////////////////////////////////

/***************************************************************************
    Delay function
***************************************************************************/
void wait(int seconds)
{
    clock_t end = clock() + seconds * CLK_TCK;  
    while(clock() <= end);
}


Share this post


Link to post
Share on other sites
Advertisement
I did it in Microsoft Visual C++ 6.0.
Change TRUE to true and FALSE to false
In MSVC, it says multiple redefinition, which I know is only in MSVC, so I changed the for loops to i, j and k. After I did that and changed TRUE to true and FALSE to false, it ran perfectly. Very nice game, I liked it!

Share this post


Link to post
Share on other sites
Very well done! Your code is so clean! Yes "TRUE" and "FALSE" should be "true" and "false". A clean way to fix this is to put

#define TRUE 1
#define FALSE 0

near the top of the source code. It worked under Dev C++ this way.

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!