Jump to content
  • Advertisement
Sign in to follow this  
Valeraine

Connect 4 clone (simple?) fix

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

Hello, I've been working on a Connect 4 clone and have run into a roadblock. For some reason, whenever the first player places their game piece, the second player automatically places their game piece on top of the first player's piece without giving me a chance to move columns. After the second player puts their piece and it returns to the first player's turn, I'm able to switch columns again. I have a feeling that there is some obvious looping error I've made just staring me in the face, but I just cannot seem to find it. Any help would be greatly appreciated!

Here are the relevant code snippets that I think could be the culprits. This is an XNA 4.0 project, if it matters. If you require more snippets, just let me know:

Update Method:


protected override void Update(GameTime gameTime)
{
if (humanOne.CheckForWin(humanOne.playerIndex) == false)
{
if (humanTwo.CheckForWin(humanTwo.playerIndex) == false)
{
if (humanOne.CheckForTie() == false)
{
if (humanOne.hasTurn == true &&
humanTwo.hasTurn == false)
{
humanOne.PlayerTurn();
}
else if (humanTwo.hasTurn == true &&
humanOne.hasTurn == false)
{
humanTwo.PlayerTurn();
}
}
else
throw new Exception("There is a tie!");
}
else
throw new Exception("Player Two has Won!");
}
else
throw new Exception("Player One has Won!");

humanOne.ChangeTurn(humanOne);
humanTwo.ChangeTurn(humanTwo);

base.Update(gameTime);
}


PlayerTurn Method:


public void PlayerTurn()
{
newState = Keyboard.GetState();

if (CheckKey(Keys.Right))
{
columnIndex++;

if (columnIndex == 7)
columnIndex = 0;
}

if (CheckKey(Keys.Left))
{
columnIndex--;

if (columnIndex == -1)
columnIndex = 6;
}

if (CheckKey(Keys.Enter))
{
for (int y = gameBoard.gameBoardHeight - 1; y > -1; y--)
{
if (gameBoard.GetTile(columnIndex, y) == 0)
{
gameBoard.SetTile(columnIndex, y, playerIndex);
break;
}
}
}
oldState = newState;
}



ChangeTurn Method:


public void ChangeTurn(Player player)
{
if (player.hasTurn == true)
player.hasTurn = false;
else if (player.hasTurn == false)
player.hasTurn = true;
}



CheckKey Method:


public bool CheckKey(Keys theKey)
{
return oldState.IsKeyDown(theKey) && newState.IsKeyUp(theKey);
}

Share this post


Link to post
Share on other sites
Advertisement
It looks like you may be starting a game with either both or neither player having a turn. Is there a point during game startup where hasTurn is initialised for both players? Something like:

humanOne.setHasTurn(true);
humanTwo.setHasTurn(false);

Share this post


Link to post
Share on other sites

It looks like you may be starting a game with either both or neither player having a turn. Is there a point during game startup where hasTurn is initialised for both players? Something like:

humanOne.setHasTurn(true);
humanTwo.setHasTurn(false);




Oops, I forgot to post that. Yes there is a spot in the code where I do that. I have a method that I run after both instances of the human classes have been initialized to pick a random human to go first. To make sure this wasn't the cause of it, I even tried commenting out the method and just changing the values manually, but the problem still exists.

Not sure if it makes a difference or not, but from what I've been observing, it seems that the ChangeTurn method is pretty erratic when it gets called, because sometimes it will give one player two turns in a row, and it doesn't happen at fixed intervals. Maybe this would be easier to show with a diagram:


//This is what the bug should be doing:
- - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- - - - - - - O - - - - - -
- - - - - - - X - - - - - - //One after the other. Still not what I want it to do,
O - - - - - - O - - - - - - //but this is what the bug should be doing...
X - - - - - - X - - - - - -

//This is what the bug is actually doing sometimes:

- - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- - - - - - - X - - - - - -
- - - - - - - O - - - - - - //Two turns in a row for O!
O - - - - - - O - - - - - -
X - - - - - - X - - - - - -

This is what I want it to do

- - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - -
- - - - - - - - - - - - - -
X - - - - - - X - - O - - -



Here is the method:


public void DetermineOrder(Player playerOne, Player playerTwo)
{
Random random = new Random();
int turn = random.Next(0, 2);

if (turn == 0)
{
playerOne.hasTurn = true;
playerTwo.hasTurn = false;
}
else if (turn == 1)
{
playerOne.hasTurn = false;
playerTwo.hasTurn = true;
}
}



And here is where the players are initialized and that method is run:


protected override void LoadContent()
{
//...loading art assets

humanOne = new Human(gameScreen.gameBoard);
humanTwo = new Human(gameScreen.gameBoard);
humanTwo.DetermineOrder(humanOne, humanTwo);

//...loading more art assets

}

Share this post


Link to post
Share on other sites
Never mind - silly me didn't notice that you'd already anticipated that with the check

if (humanOne.hasTurn == true &&
humanTwo.hasTurn == false)

in you Update method.

However, the players get swapped around every time the Update method gets called. There needs to be a check to ensure it only happens after a piece is placed:


if (gameBoard.pieceWasPlaced) /* Or something like that */
{
humanOne.ChangeTurn(humanOne);
humanTwo.ChangeTurn(humanTwo);
}


as it stands, players are being continually swapped, with the result only visible when a key press+release is detected that affects the game (move column, place piece). This would explain the erratic behaviour.

I'm not sure why you get two moves happening in quick succession - the only thing I can think of is key repeat, which would in combination with the continual swapping of players cause something like what you show in your diagrams. The simple way to test this is to hold down the Enter key and see if lots of random pieces get placed.

Share this post


Link to post
Share on other sites
Thank you very much! That has solved all of the problems. Just in case someone runs into a similar problem in the future, here's the working code:

PlayerTurn method:


public bool PlayerHasTurn()
{
newState = Keyboard.GetState();

if (CheckKey(Keys.Right))
{
columnIndex++;

if (columnIndex == 7)
columnIndex = 0;
}

if (CheckKey(Keys.Left))
{
columnIndex--;

if (columnIndex == -1)
columnIndex = 6;
}

if (CheckKey(Keys.Enter))
{
for (int y = gameBoard.gameBoardHeight - 1; y > -1; y--)
{
if (gameBoard.GetTile(columnIndex, y) == 0)
{
gameBoard.SetTile(columnIndex, y, playerIndex);
hasPlacedPiece = true;
break;
}
}
}
oldState = newState;
return hasPlacedPiece;
}



Update method:


protected override void Update(GameTime gameTime)
{
if (humanOne.CheckForWin(humanOne.playerIndex) == false)
{
if (humanTwo.CheckForWin(humanTwo.playerIndex) == false)
{
if (humanOne.CheckForTie() == false)
{
if (humanOne.hasTurn == true &&
humanTwo.hasTurn == false)
{
if (humanOne.PlayerHasTurn())
{
humanOne.ChangeTurn(humanOne);
humanTwo.ChangeTurn(humanTwo);
humanOne.hasPlacedPiece = false;
}
}
else if (humanTwo.hasTurn == true &&
humanOne.hasTurn == false)
{
if (humanTwo.PlayerHasTurn())
{
humanOne.ChangeTurn(humanOne);
humanTwo.ChangeTurn(humanTwo);
humanTwo.hasPlacedPiece = false;
}
}
}
else
throw new Exception("There is a tie!");
}
else
throw new Exception("Player Two has Won!");
}
else
throw new Exception("Player One has Won!");



base.Update(gameTime);
}

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!