Jump to content
  • Advertisement
Sign in to follow this  
password

Tic tac toe curse

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

I have an unfinished tic tac toe project I left aside a while ago, because it always appear buggy problems when I make it in graphics. I really want to finish this to increase my portfolio but there are two or three bugs I can't find in the program. First of all, the first time I made tic tac toe it was in console. I did it from the book "Beginning C++ Game Programming" which everyone here seems familiar with. This game is sort of a copy of this game, or atleast the way I did it is fairly the same as the console game in that book, but this game is in SDL aswell. I believe posting the whole source of the game would only make it worse for me and get no help, so I will post the parts I believe is causing this. The problem is that when the player chooses to be first out to put a piece, the computer does it first anyways. And that piece is a X piece which is not supposed to be starting out either. The other, little more serious problem is that after the computer/player has put the piece, none of the others can do anything anymore. For example, if the computer puts the first piece, the player is still unable to do anything at all. I have checked the source code several times and edited it many times at that but still no result. The first part that may be causing some of this is the following code: Part of event loop code:
                if (event.button.button == SDL_BUTTON_LEFT) {
                    mousex = event.button.x;
                    mousey = event.button.y;
                
                    if (turn == player) {
                        int currentx;
                        int currenty;
                        int element=0;
                
                        for (int i=0;i<3;i++) {
                            for (int a=0;a<3;a++) {
                                currenty = 72+(i*1)+(i*81);
                                currentx = 50+(a*1)+(a*88);
                        
                                if ((mousex>=currentx && mousex<=currentx+88) && (mousey>=currenty && mousey<=currenty+81)) { 
                                    if (gameboard[element] == '0') {
                                        gameboard[element] = player;
                                        turn = computer;
                                        i=3;
                                        a=3;
                                        break;
                                    }
                                }
                            
                                element++;
                            }
                        }
                    }

It simply checks if it is the player's turn and checks if the spot the clicks at is an empty spot. If that spot is empty the gameboard will be filled with the piece player represents. The gameboard is a normal array, don't ask why it's not a two-dimensional because that's the least problem right now and I want it to be a normal array this time. The game loop when the game is active looks like this:
if (move()) turn = player; 
checkwinner();

The move() function looks like this:
bool move() {    
    if (turn == computer) {         
        for (int i=0;i<9;i++) {
            if (gameboard=='0')
                gameboard == computer;
            
            if (checkwinner() == computer)
                return true;
            else
                gameboard='0';
        }
        
        if (gameboard[4] == '0') {
            gameboard[4] = computer;
            return true;
        }
     
        char bestmoves[5] = {4,0,2,6,8};     
        
        for (int i=0;i<9;i++) {
            for (int b=0;b<4;b++)  {
                if (gameboard=='0' && i==bestmoves) {
                    gameboard = computer;
                    return true;
                }
            }
        }
        
        for (int i=0;i<9;i++) {
            if (gameboard=='0') {
                gameboard = computer;
                return true;
            }    
        }
    }
    return false;
}

The thing that is so weird is that i'm also checking if it is the computers turn but he still puts his own piece when he's not the one that is supposed to start. There is nothing wrong with the turn values either. The program outputs the players and the computers turn on the screen and the values are what they are supposed to. Well anyways, help is greatly appreciated..

Share this post


Link to post
Share on other sites
Advertisement
I quickly read through your code and I noticed this one error:


if (gameboard=='0')
gameboard == computer;


Obviously this is typo and should be:


if (gameboard=='0')
gameboard = computer;

Don't your compiler throw some warning about this?

Share this post


Link to post
Share on other sites
Quote:
Original post by Kimeli
I quickly read through your code and I noticed this one error:


if (gameboard=='0')
gameboard == computer;


Obviously this is typo and should be:


if (gameboard=='0')
gameboard = computer;

Don't your compiler throw some warning about this?


No, there was no warning about that. I edited it though and it still acts the same way as before..

Share this post


Link to post
Share on other sites
Let's do some math and rewrite your even handler (bold: added, greyed italic: removed):

if (event.button.button == SDL_BUTTON_LEFT && turn == player) {
mousex = event.button.x;
mousey = event.button.y;

//if (turn == player) {
//int currentx;
//int currenty;
//int element=0;


// we are going to remove this nasty loop. Your board is located
// at 72,50 and each cell is 81x88 (82x89 with the border)
const int boardx = 72;
const int boardy = 50;
const int cellsizex = 82;
const int cellsizey = 89;
int cellx = (mousex - boardx) / cellsizex;
int celly = (mousey - boardy) / cellsizey;
int element = celly * 3 + cellx;

//for (int i=0;i<3;i++) {
//for (int a=0;a<3;a++) {
//currenty = 72+(i*1)+(i*81);
//currentx = 50+(a*1)+(a*88);

//if ((mousex>=currentx && mousex<=currentx+88) && (mousey>=currenty && mousey<=currenty+81)) {

if (gameboard[element] == '0') {
gameboard[element] = player;
turn = computer;
//i=3;
//a=3;
//break;

}
//}
//element++;
//}
//}
//}

}
But that's a minor issue (although you should ever try to simplify your algorithms when you can.

Anyway, I don't see anything wrong in the code you posted. The fact that the computer plays when it is not its turn means that he believe it is its turn. Simple "if" like this can't lie - and if there was a bug in the compiler in such a simple statement then someone else would have spotted it.

What is the initial value of "turn"? Is it correctly initialized?

BTW, you should always return true when it is the turn of the computer meaning that your last loop don't have to return something, but once you exit the loop you must return true. This will make you immune to logic bugs that may arise if your modify your move() function.

Regards,

Share this post


Link to post
Share on other sites
Wow, that made the code much more better and easier to read, thanks for writing that up..

The turn char is global and is initialized like this: char turn='O';. Before the actual game starts, there is a question if you want to start or let the computer start. This code works fine though and i've made it so the program output these values on the screen just to see if they're correct or not. The turn variable succefully swaps between the players.

"Ask if you want to start or not code", mode=0 is before the game, mode=1 is the actual game.

if (mode==0) {
if (mousey>=160 && mousey<=175) {
if (mousex>=205 && mousex<=233) {
player='O';
computer='X';
mode=1;
} else if (mousex>=290 && mousex<=315) {
player='X';
computer='O';
mode=1;
}
}
}




Quote:

BTW, you should always return true when it is the turn of the computer meaning that your last loop don't have to return something, but once you exit the loop you must return true. This will make you immune to logic bugs that may arise if your modify your move() function.


I think I know what you mean. I removed the last return true and replaced return false at the end with return true, it makes sense.

Share this post


Link to post
Share on other sites
Quote:
Original post by password
Wow, that made the code much more better and easier to read, thanks for writing that up..


Don't use this code like this - it contains a very obvious error. Try to click outside the board and see what happens - it will badly crash [smile]. Fixing this issue is not very hard, so I'll let you doing that [smile].

Quote:
Original post by password
The turn char is global and is initialized like this: char turn='O';. Before the actual game starts, there is a question if you want to start or let the computer start. This code works fine though and i've made it so the program output these values on the screen just to see if they're correct or not. The turn variable succefully swaps between the players.


"Ask if you want to start or not code", mode=0 is before the game, mode=1 is the actual game.
*** Source Snippet Removed ***
[/quote]
Sounds fine too. I PMed you my private email address - can you send me a zip with the whole source please? Hopefully, I'll be able to spot the problem in a short time. PS: if you try to sell this address, you skin will turn blue. There is some in-based anti-stealing counter-mesure inside.

Quote:
Original post by password
Quote:
BTW, you should always return true when it is the turn of the computer meaning that your last loop don't have to return something, but once you exit the loop you must return true. This will make you immune to logic bugs that may arise if your modify your move() function.


I think I know what you mean. I removed the last return true and replaced return false at the end with return true, it makes sense.


Don't go that fast - the function should only return true if the computer had to play [smile].

Share this post


Link to post
Share on other sites
Quote:
Original post by Emmanuel Deloget
Don't use this code like this - it contains a very obvious error. Try to click outside the board and see what happens - it will badly crash [smile]. Fixing this issue is not very hard, so I'll let you doing that [smile].


I didn't think that far, but strange enough nothing happens when I press outside the board, not inside either. Maybe that is because the program is so buggy as it is already :)

I've sent you a mail with the source code, I hope you will be able to find what is causing this.

Share this post


Link to post
Share on other sites
Fyi


char bestmoves[5] = {4,0,2,6,8};

for (int i=0;i<9;i++) {
for (int b=0;b<4;b++) {
if (gameboard=='0' && i==bestmoves) {
gameboard = computer;
return true;
}
}
}


You are never checking to see if '8' is available. That should be
for ( int b=0; b < 5; b++ ).

As to your main problem, I think its occuring outside the code you have pasted.

Share this post


Link to post
Share on other sites
There are numerous problems in your source code, so let's see them one by one (not necesserally in the line number order).

  if (winningrows[0] && winningrows[1] && winningrows[2] == player) {
Doesn't do what you think at all. What you want to do is to test if all these values are equal to "player", but you actually test only the third one - the first two are tested against 0 (not '0'). What you want to do is
  if (winningrows[0] == player && winningrows[1] == player && winningrows[2] == player) {

Next point:
  char bestmoves[5] = {4,0,2,6,8};     

for (int i=0;i<9;i++) {
for (int b=0;b<4;b++) {
if (gameboard=='0' && i==bestmoves) {
gameboard = computer;
return true;
}
}
}
This can be simplified to
  for (int i=0; i<5; ++i) {
if (gameboard[bestmoves] == '0') {
gameboard[bestmoves] = computer;
return true;
}
}

Third: you don't make sure that the event you get is a mouse down (or mouse up) event. As a consequence, you might handle the events more than once (once when the button is pressed, and another one when the button is released). You have to add some simple guards around the mouse event handlers (see this tutorial for more information

I will continue this later, since I have some work to do now [smile]

Share this post


Link to post
Share on other sites
Quote:
Original post by Emmanuel Deloget
  if (winningrows[0] && winningrows[1] && winningrows[2] == player) {
Doesn't do what you think at all. What you want to do is to test if all these values are equal to "player", but you actually test only the third one - the first two are tested against 0 (not '0'). What you want to do is
  if (winningrows[0] == player && winningrows[1] == player && winningrows[2] == player) {



This is truly a sloppy and careless misstake from my side. It was not intended to check for 0 as in false. I'm surprised an error like this was hidden here all along.

It's weird I forgot to add the mouseevent check, maybe it was removed or something. That would explain why there is a 4 character empty space between the switch and the first if statement in the event loop. Anyways, it's good you pointed that out because I thought all that stuff already was set up correctly :)

Many things have been cleared up, but the main problem still seem to remain. There are some new things that have appeared aswell. I'll be looking into this thread from time to time to see if you have found anything else. If you don't have time for it that's ok, i'm telling this in case It seems like i'm putting this burden onto someone else because i'm lazy and don't want to do anything by myself :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!