Sign in to follow this  

My simple TicTacToe

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

Well this is my first little game in C++, nothing great or fancy. Maybe it will be of use to some other beginner.
#include <iostream>

using namespace std;

typedef unsigned short USHORT;

enum BOOL
{
	FALSE,
	TRUE
};

void Display(char rBoard[]);
char Player(USHORT count);
BOOL CheckWin(char rBoard[]);

int main()
{
    BOOL quit_loop = FALSE;
    char board[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
    USHORT choice, counter = 0;

    while (!quit_loop)
    {
        Display(board);
        cout << Player(counter) << ", Enter move (0 to Exit): ";
        cin >> choice;

        if (choice == 0)
        {
            quit_loop = TRUE;
        }
        else
        {
            board[choice - 1] = Player(counter);

            if (CheckWin(board))
            {
				Display(board);
                cin.ignore();
                cout << Player(counter) << ", WINS!";
                cin.get();
                quit_loop = TRUE;
            }
            else
            {
                counter++;
            }
        }
    }
    return 0;
}

void Display(char rBoard[])
{
	cout << '\n';
	
    for (unsigned short n = 0; n < 9; n++)
    {
        cout << rBoard[n] << " ";

        if (n == 2 || n == 5 || n == 8)
        {
            cout << "\n";
        }
    }
    cout << '\n';
}

char Player(USHORT count)
{
    if (count % 2 == 0)
    {
        return ('X');
    }
    else
    {
        return ('O');
    }
}

BOOL CheckWin(char rBoard[])
{
    if ((rBoard[0] == rBoard[1]) && (rBoard[0] == rBoard[2]) ||
        (rBoard[3] == rBoard[4]) && (rBoard[3] == rBoard[5]) ||
        (rBoard[6] == rBoard[7]) && (rBoard[6] == rBoard[8]) ||

        (rBoard[0] == rBoard[3]) && (rBoard[0] == rBoard[6]) ||
        (rBoard[1] == rBoard[4]) && (rBoard[1] == rBoard[7]) ||
        (rBoard[2] == rBoard[5]) && (rBoard[2] == rBoard[8]) ||

        (rBoard[0] == rBoard[4]) && (rBoard[0] == rBoard[8]) ||
        (rBoard[2] == rBoard[4]) && (rBoard[2] == rBoard[6]))
        {
            return TRUE;
        }
        else
        {
            return FALSE;
        }
}

Share this post


Link to post
Share on other sites
It looks good. I attatched some code just to show you a couple of alternative solutions.


void Display(char rBoard[])
{
cout << '\n';

for (unsigned short n = 1; n <= 9; n++)
{
cout << rBoard[n - 1] << " ";

if (!(n % 3)) // more general solution
{
cout << "\n";
}
}
cout << '\n';
}

BOOL CheckWin(char rBoard[])
{
#define CHECK(x, y, z) (rBoard[x] == rBoard[y] && rBoard[x] == rBoard[z])

// this is essentially the same but with macros. don't think it's better, I just
// wanted to show you how you can use them to make the code more readable and save
// you typing when you have a lot of similair code snippets.

BOOL left = CHECK(0, 1, 2) || CHECK(3, 4, 5) || CHECK(6, 7, 8);
BOOL up = CHECK(0, 3, 6) || CHECK(1, 4, 7) || CHECK(2, 5, 8);
BOOL diagonal = CHECK(0, 4, 8) || CHECK(2, 4, 6);

return left || up || diagonal;

#undef CHECK
}




Share this post


Link to post
Share on other sites
- Since you are using C++, please use the boolean type that is built right in to the language, rather than some outdated typedef. It will allow you to avoid checking cases of a conditional, and thus express things more directly.

- Worrying about the size of your integer values is probably counter-productive; anything will be big enough, and it's a matter of a couple of bytes, so just do things the simple way - use 'int', the "default" numeric type. Anyway, you weren't even consistent about using the typedef before :)

- "break" from an infinite while loop is not a sin.


#include <iostream>

using namespace std;

void Display(char rBoard[]);
char Player(int count);
bool CheckWin(char rBoard[]);
// What is the "r" supposed to stand for anyway? O_O

int main() {
char board[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9'};
int choice, counter = 0;

while (true) {
Display(board);
cout << Player(counter) << ", Enter move (0 to Exit): ";
cin >> choice;
if (choice == 0) { break; }
// Otherwise, make the move...
board[choice - 1] = Player(counter);
if (CheckWin(board)) {
Display(board);
cin.ignore();
cout << Player(counter) << ", WINS!";
cin.get();
break;
} else {
counter++;
}
}
return 0;
}

void Display(char rBoard[]) {
cout << '\n';
// slight adaptation to doho's idea here.
// This handling of the loop indices is IMHO a bit clearer. The conditional
// expression perhaps isn't, but it's more concise :)
for (int n = 0; n < 9; n++) {
// at ends of lines, n mod 3 == 2 (2, 5 or 8).
// Thus we output a newline instead of a space
cout << rBoard[n] << ((n % 3) == 2) ? '\n' : ' ';
}
cout << endl; // probably a good idea to make sure it's flushed
}

char Player(int count) {
// A little trick here - try to use data instead of code when you can ;)
char symbols[] = {'X', 'O'};
return symbols[count % 2];
}

bool CheckWin(char rBoard[]) {
// Just return the expression result; we don't need to jump through any hoops
// to get a boolean out of it.
return (rBoard[0] == rBoard[1]) && (rBoard[0] == rBoard[2]) ||
(rBoard[3] == rBoard[4]) && (rBoard[3] == rBoard[5]) ||
(rBoard[6] == rBoard[7]) && (rBoard[6] == rBoard[8]) ||

(rBoard[0] == rBoard[3]) && (rBoard[0] == rBoard[6]) ||
(rBoard[1] == rBoard[4]) && (rBoard[1] == rBoard[7]) ||
(rBoard[2] == rBoard[5]) && (rBoard[2] == rBoard[8]) ||

(rBoard[0] == rBoard[4]) && (rBoard[0] == rBoard[8]) ||
(rBoard[2] == rBoard[4]) && (rBoard[2] == rBoard[6]);
}



Overall, though, a good start. Now you can think about doing some error handling, possibly making the win-checking data driven, and maybe even writing AI :)

Share this post


Link to post
Share on other sites
He means to load the win checking logic from a file. That way a change in the rules for checking a win doesn't force you to recompile the code. For TTT it isn't necessary, actually it isn't ever really necessary, but data driven design is something we should be working toward, so getting used to it from the beginning is probably a good idea.

Share this post


Link to post
Share on other sites
Well - I guess you could load it from a file for the practice, but having an array would be reasonable just to demonstrate the concept - looping over an array is a little nicer than having one HUGE conditional expression. :) Anyway, the goal is to avoid duplication; as it stands, the conditional duplicates "rBoard[]" all the time, and you can't really get around that without creating some data.


char wins[][] = { {0, 1, 2}, {3, 4, 5}, /* etc. */ };
for (int i = 0; i < 8; i++) {
if ((rBoard[wins[i][0]] == rBoard[wins[i][1]]) &&
(rBoard[wins[i][0]] == rBoard[wins[i][2]])) {
// a bit trickier, but only one "case" to consider, eight times.
return true;
}
return false; // no match found.
}



Obviously not perfect - the complexity has to go somewhere - but this is a lot nicer, because you are letting the computer do the dumb part instead of copying and pasting yourself. The dumb parts are what computers are good at - they won't make mistakes.

Share this post


Link to post
Share on other sites
Quote:
Original post by doho
BOOL CheckWin(char rBoard[])
{
#define CHECK(x, y, z) (rBoard[x] == rBoard[y] && rBoard[x] == rBoard[z])

// this is essentially the same but with macros. don't think it's better, I just
// wanted to show you how you can use them to make the code more readable and save
// you typing when you have a lot of similair code snippets.

BOOL left = CHECK(0, 1, 2) || CHECK(3, 4, 5) || CHECK(6, 7, 8);
BOOL up = CHECK(0, 3, 6) || CHECK(1, 4, 7) || CHECK(2, 5, 8);
BOOL diagonal = CHECK(0, 4, 8) || CHECK(2, 4, 6);

return left || up || diagonal;

#undef CHECK
}


That's a really nice and good looking code snippet!

Share this post


Link to post
Share on other sites
Thanks for the feedback guys. There is always room for improvement :)

Doho I was being a bit lazy :P with regards to the mod part, just a quick rush, but yeah I see now that way is the more effective way :)

Zahlman:

1 - I just use r and p to remind me of a pointer or a reference :) I am busy learning C++, am I doing something wrong using that?

2 - With regards to BOOL, can you believe, I only found out 1 day ago that it is built in C++ and there is no need to define it.

3 - The integer sizes ... yes I'm being a little picky, thats just me :D. Lets just say it has something to do with my past experience with Pascal where in the very beginning I frequently managed to run out of memory to compile with - global variables are wonderful when you are an absolute beginner.

4 - Breaking from a loop ... another thing from past experience - was told a number of times that using something like break ... goto ... are evil :)

Lastly, does any one know if there is something like clrscr? I am not sure of the header or its definition ... any help?

Share this post


Link to post
Share on other sites

This topic is 4593 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this