Simple Tic Tac Toe using pointers

By Sonny on May 12, 2010

A simple tic tac toe game using pointers. Just a simple example of how you can use pointers. Simple AI, as well.
This was just a project i had to do when i first learned pointers.

//Tic-Tac-Toe using pointers

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

/*
set constants
create functions
create an empty board
display instructions
computer gets x
player gets o
ask the player if he wishes to go first.
    if player goes first
        player gets x
        computer gets o
    else
        computer gets x
        player gets o
display board
while nobody has won and it isnt a tie

    decide moves
    if player move
        set player piece to position on board
    else
        calculate best move for computer
        set computer piece to best position
    update board

decide winner
display winner
ask if player wants to play again
    if yes
        initiate game
    else game over

*/

const char EMPTY = ' ';
const char x = 'X';
const char o = 'O';
const char TIE = 'T';
const char NONE = 'N';

void instructions();
char askYesNo(string question);
int askNumber(string question, int high, int low = 1);
void displayBoard(const vector<char>* const board);
char winner(const vector<char>* const board);
bool isLegal(int move, const vector<char>* const board);
int humanMove(const vector<char>* const board, char human);
int computerMove(vector<char> board, char comp);
void announceWinner(char winner, char human, char comp);
char playAgain(string question);
void playGame();

int main()
{
    int move;
    const int NUM_SQUARES = 9;
    vector<char> board(NUM_SQUARES, EMPTY);

    instructions();
    char computer = x;
    char human = o;
    char ans = askYesNo("Do you want to go first?");
    if (ans == 'y')
    {
        human = x;
        computer = o;
    }
    char turn = x;
    displayBoard(&board);

    while (winner(&board) == NONE)
    {
        if (turn == human)
        {
            move = humanMove(&board, human);
            board[move] = human;
        }

        else
        {
            move = computerMove(board, computer);
            board[move] = computer;
        }
        displayBoard(&board);

        if (turn == human)
        {
            turn = computer;
        }
        else { turn = human; }
    }
    announceWinner(winner(&board), human, computer);
    ans = playAgain("Do you want to play again? (y/n): ");
    if (ans == 'y')
    {
        cout << endl;
        playGame();
    }
    else
    {
        cout << "Thanks for playing!";
        return 0;
    }
}

void playGame()
{
    main();
}

char playAgain(string question)
{
    char ans = 'n';
    cout << question;
    cin >> ans;
    return ans;
}
void instructions()
{
    cout << "Welcome to the ultimate man-machine showdown: Tic-Tac-Toe.\n";
    cout << "-where human brain is pit against silicon processor\n\n";

    cout << "Make your move known by entering a number, 0 - 8. The number\n";
    cout << "corresponds to the desired board position, as illustrated:\n\n";

    cout << "1 | 2 | 3\n";
    cout << "---------\n";
    cout << "4 | 5 | 6\n";
    cout << "---------\n";
    cout << "7 | 8 | 9\n\n";
    cout << "Prepare yourself, human. The battle is about to begin.\n\n";
}

char askYesNo(string question)
{
    char response;
    do
    {
        cout << question << "(y/n): ";
        cin >> response;
    } while (response != 'y' && response != 'n');
    return response;
}

int askNumber(string question, int high, int low)
{
    int number;
    do
    {
        cout << question << "("<< low << "- "<< high << "): ";
        cin >> number;
    } while (number > high || number < low);
    return number+1;
}

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

char winner(const vector<char>* const board)
{
    // all possible winning rows
    const int WINNING_ROWS[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, 6}
                                       };

    const int TOTAL_ROWS = 8;

// if any winning row has three values that are the same (and not EMPTY),
// then we have a winner
for(int row = 0; row < TOTAL_ROWS; ++row)
{
    if ( ((*board)[WINNING_ROWS[row][0]] != EMPTY) &&
         ((*board)[WINNING_ROWS[row][0]] == (*board)[WINNING_ROWS[row][1]]) &&
         ((*board)[WINNING_ROWS[row][1]] == (*board)[WINNING_ROWS[row][2]]) )
    {
         return (*board)[WINNING_ROWS[row][0]];
    }
}

// since nobody has won, check for a tie (no empty squares left)
if (count(board->begin(), board->end(), EMPTY) == 0)
    return TIE;

// since nobody has won and it isn't a tie, the game ain't over
return NONE;
}

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

int humanMove(const vector<char>* const board, char human)
{
    int move = askNumber("Where will you move?", (board->size()));
    while (!isLegal(move-2, board))
    {
        cout << "\nThat square is already occupied, foolish human.\n";
        move = askNumber("Where will you move?", (board->size()));
    }
    cout << "Fine...\n";
    return move-2;
}

int computerMove(vector<char> board, char computer)
{
    cout << "I shall take square number ";

    // if computer can win on next move, make that move
    for(unsigned int move = 0; move < board.size(); ++move)
    {
        if (isLegal(move, &board))
        {
            board[move] = computer;
            if (winner(&board) == computer)
            {
                cout << move+1 << endl;
                return move;
            }
            // done checking this move, undo it
            board[move] = EMPTY;
        }
    }

    // if human can win on next move, block that move
    char human;
    if (computer == x)
    {
        human = o;
    }
    else { human = x; }

    for(unsigned int move = 0; move < board.size(); ++move)
    {
        if (isLegal(move, &board))
        {
            board[move] = human;
            if (winner(&board) == human)
            {
                cout << move+1 << endl;
                return move;
            }
            // done checking this move, undo it
            board[move] = EMPTY;
        }
    }

    // the best moves to make, in order
    const int BEST_MOVES[] = {5, 1, 3, 7, 9, 2, 4, 6, 8};
    // since no one can win on next move, pick best open square
    for(unsigned int i = 0; i < board.size(); ++i)
    {
        int move = BEST_MOVES[i];
        if (isLegal(move-1, &board))
        {
            cout << move << endl;
            return move-1;
        }
     }
    return 0;
}

void announceWinner(char winner, char human, char computer)
{
    if (winner == computer)
    {
        cout << "computer" << " wins!\n";
        cout << "As I predicted, human, I am triumphant once more-proof\n";
        cout << "that computers are superior to humans in all regards.\n";
    }
    else if (winner == human)
    {
        cout << "human" << " wins!\n";
        cout << "No, no! It cannot be! Somehow you tricked me, human.\n";
        cout << "But never again! I, the computer, so swear it!\n";
    }
    else
    {
        cout << "It's a tie.\n";
        cout << "You were most lucky, human, and somehow managed to tie me.\n";
        cout << "Celebrate... for this is the best you will ever achieve.\n";
    }
}

Comments

Sign in to comment.
Mfoust   -  Feb 10, 2011

works great, haven't won yet tho...
(i finally won after like 80 games)

 Respond  
Hawkee   -  May 13, 2010

I only gave it a few tries, but I appreciate that it compiled on OS X. Keep the C++ snippets coming!

 Respond  
Sonny   -  May 12, 2010

lol. it's pretty easy to win. since the ai is flawed, as it follows a pattern. but thanks for trying it, and commenting.

 Respond  
Hawkee   -  May 12, 2010

Awesome, it works perfectly. I couldn't win though..

 Respond  
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.