Console TicTacToe game ...

mvmalderen 0 Tallied Votes 249 Views Share

> I know there are some bad things in my code such as system("CLS"); and that this makes the code unportable and inefficient, but you could just remove it at anytime :)

> It could be that my code is a bit bloated, I didn't put enough time and effort in it so that's my mistake

> I know this is probably one of the million TicTacToes available on the internet, but I just wanted to contribute some (bloated?) code ...

> Any further comments are appreciated ! :)

> There's a little bug (if you can call it that way) in my code (where else LOL :P): If you play the moves in a particular order you can *ALWAYS* win the game against the computer :P, this can easily be fixed by implementing a function which plays random moves :)

> My goal: provide understandable code

> I hope you will enjoy :P !

/******************************************************
*                                                     *
*   TicTacToe Game written by Mathias Van Malderen    *
*   Copyright (c) 2009 Mathias Van Malderen           *
*                                                     *
*   NOTE: It isn't allowed to sell this source !      *
*                                                     *
******************************************************/
#include <iostream>
#include <cstdlib>
#include <conio.h>

using namespace std;

enum field_t {EMPTY = 0, IN_USE = 1, FULL = 2};

class tictactoe {
private:
    char board[3][3]; // our game board
    struct {
        short computer;
        short player;
        short draw;
    } score;
    string possible_moves;
    field_t field_state;
    char digit2chr(short digit);
    short chr2digit(char chr);
    void updateFieldState();
    bool check_player_win();
    bool check_computer_win();
    bool find_player_win();
    bool find_computer_win();
public:
    void draw_board();
    void initialize_board();
    void player_doMove();
    void find_computer_move();
    void checkWinner();
    void getKey();
    short get_player_score();
    short get_computer_score();
    field_t checkfield();
    tictactoe();
};

tictactoe::tictactoe()
{
    // constructor
    score.player = 0;
    score.computer = 0;
    score.draw = 0;
    initialize_board();
}

short chr2digit(char chr)
{
	// convert a character to a digit
	if('0' <= chr && chr <= '9') return static_cast<short>(chr-'0');
	return -1;
}

char tictactoe::digit2chr(short digit)
{
	// convert a digit to a character
	if(0 <= digit && digit <= 9) return static_cast<char>(digit+'0');
	return '?';
}

void tictactoe::getKey()
{
    short c = static_cast<short>(getch());
    if(c == 113)
    {
        exit(0);
    }
}

void tictactoe::checkWinner()
{
    // check whether there's a winner
    updateFieldState();
    if(check_computer_win())
    {
        // computer wins
        score.computer++;

        cout << "Computer Wins !" << endl;

        // new game
        getKey();
        initialize_board();
        draw_board();
    } else if(check_player_win()) {
        // human player wins
        score.player++;

        cout << "You Win !" << endl;

        // new game
        getKey();
        initialize_board();
        draw_board();
    } else if(checkfield() == FULL) {
        // it's a draw
        score.draw++;

        cout << "It's a draw !" << endl;

        // new game
        getKey();
        initialize_board();
        draw_board();
    }
}

void tictactoe::find_computer_move()
{
    // the computer has to play a move

    // 1: If there's a winning play available for the computer, play this one:
    if(find_computer_win()) return;

    // 2: If there's a winning play available for the human player, block this one by playing it:
    if(find_player_win()) return;

    // 3: Is the box in the middle already played? If no, play this one:
    if(board[1][1] == ' ')
    {
        board[1][1] = 'O';
        return;
    }

    // 4: Just play the first possible move (find the first empty field):
    bool looptime = true;
    for(int i = 0; ((i < 3) && looptime); i++)
    {
        for(int j = 0; ((j < 3) && looptime); j++)
        {
            if(board[i][j] == ' ')
            {
                looptime = false;
                board[i][j] = 'O';
                updateFieldState();
            }
        }
    }
}

bool tictactoe::find_computer_win()
{
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            if(board[i][j] == ' ')
            {
                // empty field
                board[i][j] = 'O';
                if(!check_computer_win())
                {
                    board[i][j] = ' ';
                } else {
                    return true;
                }
            }
        }
    }
    return false;
}

bool tictactoe::find_player_win()
{
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            if(board[i][j] == ' ')
            {
                // empty field
                board[i][j] = 'X';
                if(!check_player_win())
                {
                    board[i][j] = ' ';
                } else {
                    board[i][j] = 'O';
                    return true;
                }
            }
        }
    }
    return false;
}

bool tictactoe::check_player_win()
{
    // check whether the human player can win
    if(board[0][0] == 'X' && board[1][1] == 'X' && board[2][2] == 'X') return true;
    if(board[0][2] == 'X' && board[1][1] == 'X' && board[2][0] == 'X') return true;
    if(board[0][0] == 'X' && board[0][1] == 'X' && board[0][2] == 'X') return true;
    if(board[1][0] == 'X' && board[1][1] == 'X' && board[1][2] == 'X') return true;
    if(board[2][0] == 'X' && board[2][1] == 'X' && board[2][2] == 'X') return true;
    if(board[0][0] == 'X' && board[1][0] == 'X' && board[2][0] == 'X') return true;
    if(board[0][1] == 'X' && board[1][1] == 'X' && board[2][1] == 'X') return true;
    if(board[0][2] == 'X' && board[1][2] == 'X' && board[2][2] == 'X') return true;
    return false;
}

bool tictactoe::check_computer_win()
{
    // check whether the computer player can win
    if(board[0][0] == 'O' && board[1][1] == 'O' && board[2][2] == 'O') return true;
    if(board[0][2] == 'O' && board[1][1] == 'O' && board[2][0] == 'O') return true;
    if(board[0][0] == 'O' && board[0][1] == 'O' && board[0][2] == 'O') return true;
    if(board[1][0] == 'O' && board[1][1] == 'O' && board[1][2] == 'O') return true;
    if(board[2][0] == 'O' && board[2][1] == 'O' && board[2][2] == 'O') return true;
    if(board[0][0] == 'O' && board[1][0] == 'O' && board[2][0] == 'O') return true;
    if(board[0][1] == 'O' && board[1][1] == 'O' && board[2][1] == 'O') return true;
    if(board[0][2] == 'O' && board[1][2] == 'O' && board[2][2] == 'O') return true;
    return false;
}

field_t tictactoe::checkfield()
{
    // return the board state
    return field_state;
}

void tictactoe::updateFieldState()
{
    // update the board state (EMPTY, IN_USE, FULL)
    short empty_c = 0;
    for(int i = 0; i < 3; i++)
    {
        for(int j = 0; j < 3; j++)
        {
            if(board[i][j] == ' ')
            {
                empty_c++;
                field_state = IN_USE;
                break;
            } else {
                if(empty_c == 0)
                {
                    field_state = FULL;
                } else {
                    field_state = EMPTY;
                }
            }
        }
    }
}

void tictactoe::player_doMove()
{
    // the human player plays a move
    short row, col;
    cout << "Enter row, col: ";
    cin >> row >> col;
    if(row > 3 || col > 3)
    {
        cout << endl << "Invalid move !" << endl << endl;
        player_doMove();
    } else {
        if(board[row-1][col-1] != ' ')
        {
            // this field has already been played
            cout << endl << "This field is already played !" << endl << endl;
            player_doMove();
        } else {
            // this is an empty field, play the move
            board[row-1][col-1] = 'X';
        }
    }
    updateFieldState();
}

void tictactoe::draw_board()
{
    // draw the game board
    system("CLS");

    cout << endl;

    cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl;
    cout << "TicTacToe Game v1.0 written by Mathias Van Malderen" << endl;
    cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << endl << endl;

    for(int i = 0; i < 3; i++)
    {
        cout << "|---|---|---|" << endl;
        for(int j = 0; j < 3; j++)
        {
            cout << "| " << board[i][j] << " ";
        }
        cout << "|" << endl;
    }
    cout << "|---|---|---|" << endl << endl;

    cout << "Computer score: " << score.computer << "\n" << "Player score: " << score.player << "\n" << "Draws: " << score.draw << endl << endl;
}

void tictactoe::initialize_board()
{
    // reset the game board (clear all fields)
    for(int i = 0; i < 3; i++)
        for(int j = 0; j < 3; j++) board[i][j] = ' ';
    field_state = EMPTY;
}

short tictactoe::get_player_score()
{
    // get the player score
    return score.player;
}

short tictactoe::get_computer_score()
{
    // get the computer score
    return score.computer;
}

int main()
{
    /* The most famous function is this one :P */
    tictactoe test;
    test.draw_board();
    while(test.checkfield() != FULL)
    {
        test.player_doMove();
        test.draw_board();
        test.checkWinner();
        test.find_computer_move();
        test.draw_board();
        test.checkWinner();
    }

    return 0;
}
MosaicFuneral 812 Nearly a Posting Virtuoso

Why would someone sell your code?

Anyway, don't mind if I post my version do you? I haven't written one yet, but I feel like writing one soon.

mvmalderen 2,072 Postaholic

>Why would someone sell your code?
>> I dunno
>>You never know, these people exist :P

glen dc1 3 Newbie Poster

Looks nice ;)

mvmalderen 2,072 Postaholic

>Anyway, don't mind if I post my version do you? I haven't written one yet, but I feel like writing one soon.

No problem :)

It could be that there are some functions in my code which aren't used anywhere, that's because I was rewriting parts of my code, but I've never finished it so I just posted my code and took some functions out of it but I see that I've forgot some :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.