Thursday, December 2, 2010

Simple Tic Tac Toe Game (c++)

I've seen a bunch of random people learning programming starting out with Tic Tac Toe games. It is an interesting challenge for beginners and I think its probably a great first-challenge to try once you think you're getting the hang of the language basics.

I myself had never made a Tic Tac Toe game, but after seeing so much beginners having trouble with it, and seeing their code filled with un-necessary "bloat", I decided to try making a lean C++ console based tic tac toe game.

The goal was to make a functional Tic Tac Toe game without the hundreds of lines other people's code usually takes.

In my head I was thinking it might even be possible to do in as few as 30 lines, but that was a bit too optimistic for me in practice.
Although if I didn't handle bad-cases, and didn't format the output nicely, I could probably do that; but the quality of a program should not be sacrificed for "less lines" of code, so I decided to handle all the bad-cases and such I'm aware of (which in turn increased the amount of code the program needed).

Anyways here's the full code:

#include <conio.h>
#include <iostream>
using namespace std;

void ticTacToe() {
char w = 0, b[9] = { '1','2','3','4','5','6','7','8','9' };
char player[][9] = { "Player O", "Player X" };
unsigned int slot = 0, turn = 1, moves = 0;
for(;;) {
system("cls");
cout << "Tic Tac Toe!" << endl << endl;
cout << " " << b[0] << "|" << b[1] << "|" << b[2] << endl << " -+-+-" << endl;
cout << " " << b[3] << "|" << b[4] << "|" << b[5] << endl << " -+-+-" << endl;
cout << " " << b[6] << "|" << b[7] << "|" << b[8] << endl << endl;
if (w || (++moves > 9)) {
if (w) cout << player[w=='X'] << " is the winner!!!" << endl << endl << endl;
else cout << "No Winner!!!" << endl << endl << endl;
cin.clear(); cin.ignore(~0u>>1, '\n'); _getch();
return;
}
cout << player[turn^=1] << " Choose a Slot... ";
cin >> slot;
if (slot < 1 || slot > 9 || b[slot-1] > '9') {
cout << "Please Choose A Valid Slot!!!" << endl;
cin.clear(); cin.ignore(~0u>>1, '\n'); _getch();
turn^=1; moves--;
continue;
}
b[slot-1] = turn ? 'X' : 'O';
((((b[0]==b[1]&&b[0]==b[2]&&(w=b[0])) || (b[3]==b[4]&&b[3]==b[5]&&(w=b[3]))
|| (b[6]==b[7]&&b[6]==b[8]&&(w=b[6])))||((b[0]==b[3]&&b[0]==b[6]&&(w=b[0]))
|| (b[1]==b[4]&&b[1]==b[7]&&(w=b[1])) || (b[2]==b[5]&&b[2]==b[8]&&(w=b[2])))
||((b[0]==b[4]&&b[0]==b[8]&&(w=b[0])) || (b[2]==b[4]&&b[2]==b[6]&&(w=b[2])))));
}
}

int main() {
for(;;) ticTacToe();
return 0;
}


The whole program ended up being 40 lines of code, which since it handles bad-cases, probably isn't that bad.

I would like to point out how few If statements or Switch Statements are needed for a tic tac toe game as seen above.
I usually see tic tac toe code examples filled with If/Switch statements that simply aren't necessary and make the code a lot bigger.

If you dislike the code above then I somewhat agree that the code could be prettier. Since the goal was to keep the amount of code to a minimum, it limited me in my code cleanliness.

If you notice, in my coding style there are times where I group more than one statement on the same line of code.
This is my personal preference when it comes to short statements that go hand-in-hand with each other. There are some programmers that don't like this style of mine, and I respect that, but I like code that is structured pretty, and grouping similar short statements allows me to accomplish nicer looking code IMO.

I kind-of lied with the title of this blog post though. Although this program is 'simple' in terms of 'little code', it isn't very 'simple' in terms of the ability for someone that isn't experienced with c++ to understand.
I used some tricks which newer c++ programmers may have trouble with; and if you do wish to understand or ask about part of the code above don't hesitate to leave a comment.

3 comments:

  1. I have some questions about this, for starters though what is "^=" doing in player[turn^=1]?

    Also the char array confuses me a bit:

    char player[][9] = { "Player O", "Player X" };

    is this an array in an array or something?

    Sorry still trying to understand basic C++.

    ReplyDelete
  2. Hey Milt,

    "turn ^= 1;" is the same thing as "turn = turn ^ 1;".
    The "^" operator is the bitwise xor operator; so the result of the operation is "turn xor 1".

    When you xor the value "0" with "1", then you get "1". When you xor "1" with "0", you get 0.
    In the above code, the only possible values for the variable 'turn' is either 0 or 1, so what "turn ^= 1;" is doing is basically:
    if (turn == 0) turn = 1;
    else turn = 0;

    Its basically acting as a switch to alternate turn between 0 and 1 every time that line of code is reached.

    -----

    the line "char player[][9] = { "Player O", "Player X" };" is declaring a multi-dimensional array.

    the above method essentially lets you create an array of strings that are 8 characters wide.
    we specify player[][9] because strings have a hidden null-byte at the end of them, so the string "Player O" is actually taking up 9 characters.
    in the declaration "player[][9]" we could've instead written "player[2][9]", which would do the same thing. when you leave the first bracket pair blank, the compiler automatically creates the array with a size based on how you defined it.

    ReplyDelete
  3. Ah okay as soon as you said multi-dimensional array it clicked. I see how it works. Didn't know that strings had hidden null bytes at the end though, interesting. This all makes sense now, very nice.

    ReplyDelete