1. on line 117, if a player wants to start a new game, how do I clear the old object and start fresh? |
An object can only be constructed once. However if you want to "reset" an object, you can destruct it and reassign it to a new one. This is easily accomplished with this:
game = TTT();
TTT(); makes a new object, and assigning it to game copies the new object to game (erasing/destructing the previous game).
2. I have not had much experience with random numbers, but sometimes around line 55 I get a division by zero error message. No idea why this happens. |
% gives you the remainder after division. If you say
rand() % 5
... rand() gives you a random number, and % 5 takes that number, divides it by 5, and gives you back the remainder effectively giving you a random number between [0..4] (since no number larger than 4 could possibly be the remainder of /5)
If do
rand() % 0
, that's a division by zero. If you're getting that error on line 55, then that means your vector is empty. It looks like this could happen if you call computer_turn when the board is completely full.
3. The most frustrating, but so close. Line 150! When a player or computer chooses a square, it goes into a memory array, then the program checks if the number exists in the array and if it does, does not allow user to enter. It works most of the time, but sometimes it skips and does not work properly. I spent a while on this but with no luck. Please assist. |
What purpose does the for loop on line 148 serve? Why do you need to check every square when you know which square the user is trying to set?
There's no need for the nested loop there. Get rid of the for loop and simply check the one square the user is asking about.
EDIT:
okay I just realized why this might be tricky.
The user is inputting his choice in the form of a char, and you need to check to see if the spot on the board that char represents contains that char. The problem is you can't use the char as-is to index your array, because the array needs to take a zero based index.
The trick here is that you can easily convert a numerical char (ie, '6', '3', etc) to an integral value (ie 6, 3, etc) by subtracting the character '0':
1 2 3 4 5
|
char one = '1';
cout << one; // prints the character '1'
int numone = one - '0';
cout << numone; // prints the number '1'
|
So if the user inputs '5', you can subtract '0' from that to get 5, which you can then use to index your board array. HOWEVER, since user input starts at 1, but the board indexes start at 0, you probably want to subtract '1' instead (to convert '5' to 4, making the index zero based).
Also, be sure to watch for out of bounds input. IE: after conversion, you should have a value between [0..8]
/EDIT
4. Looking for criticism. If I am doing something wrong, or if you have a better way of doing things, would love to hear it so I can become a better programer. Please keep in mind I am still a noob. |
Overall I'd say it's very good for a beginner program. Very well organized, easy to follow, and to the point.
The only parts that strike me as 'bad' are in check_win:
a) duplicating the win conditions for X and O is "blech". I would make a separate function that checks for a win and call it twice... once for X and once for O.
b) Not every 2-state variable should be a boolean. It's unintuitive that winner=true means X won and winner=false means O won. If I see winner=false, I would think that means the game is a tie. A more sensible approach would have winner be a char set to X or O to indicate the winner. Or better yet, change it to a game status with 4 states:
X = game over, X won
O = game over, O won
T = game over, tie
[space] = game still in progress
Or even better yet, use an enum rather than magic characters.
5. If you have any good ideas for AI, something more advanced than my random, would like to hear it as well. |
A minimally intelligent AI would complete its 3rd move for the win if it has 2 in a row and an open 3rd space. It also probably would want to look for the player having 2 in a row and then block him.
If you want to get really smart, you can have it look for possible "forks"/"traps" (ie: getting 2 in a row in multiple ways, so that even if the player blocks one, it can take the other).