Your code is far too long and you should be able to reduce it significantly by making use of functions, not using numbered variables (put them in an array). You should also give your variables sensible names, especially if they are declared global.
Below a demo code using serial input instead of buttons. Study it, learn from it, adjust it to your needs.
// grid, initialised with zeroes
char grid[3][3];
// player to make move; first player is X
char player = 'X';
// number of moves
byte numMoves = 0;
void setup()
{
Serial.begin(57600);
// fill grid with spaces
memset(grid, ' ' , sizeof(grid));
// print empty grid
printGrid();
}
void loop()
{
if (numMoves == 9)
{
Serial.println("No winner");
cleanup();
}
if (Serial.available() > 0)
{
char c = Serial.read();
if (c < '1' || c > '9')
{
Serial.println("invalid input");
return;
}
// calculate position in grid
byte xPos = (c - '0' - 1) % 3;
byte yPos = (c - '0' - 1) / 3;
// debug
Serial.print("xPos = "); Serial.println(xPos);
Serial.print("yPos = "); Serial.println(yPos);
// if grid position empty
if (grid[xPos][yPos] == ' ')
{
// increment number of moves
numMoves++;
// use the player variable to put a 'X' or a 'O'
grid[xPos][yPos] = player;
// change player
if (player == 'X')
{
player = 'O';
}
else
{
player = 'X';
}
// print updated grid
printGrid();
// check for winner
char winner = checkWinner();
if (winner != ' ')
{
Serial.print("Winner = "); Serial.println(winner);
cleanup();
}
}
else
{
Serial.println("Already taken");
}
}
}
/*
print the grid
*/
void printGrid()
{
Serial.print("Player to make a move = "); Serial.println(player);
for (byte yCnt = 0; yCnt < 3; yCnt++)
{
Serial.println("+-+-+-+");
Serial.print("|");
for (byte xCnt = 0; xCnt < 3; xCnt++)
{
Serial.write(grid[xCnt][yCnt]);
Serial.print("|");
}
Serial.println();
}
Serial.println("+-+-+-+");
}
/*
check for a winner
Returns:
player letter of there is a winner, else a space
*/
char checkWinner()
{
// check rows
for (byte yCnt = 0; yCnt < 3; yCnt++)
{
if (grid[yCnt][0] == grid[yCnt][1] && grid[yCnt][0] == grid[yCnt][2])
{
return grid[yCnt][0];
}
}
// check columns
for (byte xCnt = 0; xCnt < 3; xCnt++)
{
if (grid[0][xCnt] == grid[1][xCnt] && grid[1][xCnt] == grid[2][xCnt])
{
return grid[0][xCnt];
}
}
// diagonals
if (grid[0][0] == grid[1][1] && grid[1][1] == grid[2][2])
{
return grid[1][1];
}
if (grid[0][2] == grid[1][1] && grid[1][1] == grid[2][0])
{
return grid[1][1];
}
return ' ';
}
/*
cleanup
*/
void cleanup()
{
// fill grid with spaces
memset(grid, ' ', sizeof(grid));
// reset moves to 0
numMoves = 0;
// set initial player
player = 'X';
// print empty grid
printGrid();
}
Here is my take on converting to arrays. I didn't want to press buttons all day to test it so I put in an option for random automatic play. It selects random plays from 1 to 9. I took out the forced crash and put in code to detect both wins and ties.
const byte IncrementButtonPin = 13;
const byte DecrementButtonPin = 12;
const byte EnterButtonPin = 11;
int position = 0;
bool player1 = true;
char board[9];
void NewBoard()
{
position = 0;
player1 = true;
for (int i = 0; i < 9; i++)
board[i] = '1' + i;
ShowBoard();
for (int i = 0; i < 9; i++)
board[i] = ' ';
}
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
delay(200);
Serial.println("Begin");
pinMode(IncrementButtonPin, INPUT_PULLUP);
pinMode(DecrementButtonPin, INPUT_PULLUP);
pinMode(EnterButtonPin, INPUT_PULLUP);
NewBoard();
}
void ShowBoard()
{
for (int row = 0; row < 3; row++)
{
for (int col = 0; col < 3; col++)
{
Serial.print(board[row * 3 + col]);
if (col < 2)
Serial.print("|");
}
Serial.println();
if (row < 2)
Serial.println("-+-+-");
}
}
void loop()
{
// put your main code here, to run repeatedly:
if (digitalRead(IncrementButtonPin) == LOW)
{
position = (position + 1) % 9;
Serial.println(position + 1);
delay(300);
}
if (digitalRead(DecrementButtonPin) == LOW)
{
position = (position + 8) % 9; // Modulo 9 subtract 1
Serial.println(position + 1);
delay(300);
}
#if 0 // Auto Random Play
position = random(9);
#else
if (digitalRead(EnterButtonPin) == LOW)
#endif
{
if (player1)
{
// Player 1: 'X'
if (board[position] == ' ')
{
board[position] = 'X';
player1 = false; // Switch to Player 2
ShowBoard();
}
else
{
Serial.print("Already taken: ");
Serial.println(position + 1);
}
}
else
{
// Player 2: 'O'
if (board[position] == ' ')
{
board[position] = 'O';
player1 = true; // Switch back to Player 1
ShowBoard();
}
else
{
Serial.print("Already taken: ");
Serial.println(position + 1);
}
}
Serial.println(player1 ? 'X' : 'O');
} // End of Enter Pressed
if (CheckForWinner() || CheckForTie())
{
delay(5000);
NewBoard();
}
}
bool CheckForWinner()
{
char player;
// Check for winners
for (int row = 0; row < 3; row++)
{
player = board[row * 3];
if (player != ' ' && board[row * 3] == player && board[row * 3 + 1] == player && board[row * 3 + 2] == player)
{
AnnounceWinner(player, "row", row + 1);
return true;
}
}
for (int col = 0; col < 3; col++)
{
player = board[col];
if (player != ' ' && board[col] == player && board[col + 3] == player && board[col + 6] == player)
{
AnnounceWinner(player, "column", col + 1);
return true;
}
}
// Falling diagonal
player = board[0];
if (player != ' ' && board[0] == player && board[4] == player && board[8] == player)
{
AnnounceWinner(player, "falling diagonal", 0);
return true;
}
// Rising diagonal
player = board[6];
if (player != ' ' && board[6] == player && board[4] == player && board[2] == player)
{
AnnounceWinner(player, "rising diagonal", 0);
return true;
}
return false; // No winner so-far
}
// If every row, column, and diagonal has spaces taken by both
// players then the game is over in a tie.
bool CheckForTie()
{
// Check for rows that might still be won
for (int row = 0; row < 3; row++)
{
if ((board[row * 3] != 'X') && (board[row * 3 + 1] != 'X') && (board[row * 3 + 2] != 'X'))
return false; // No X's so O can win. Not a tie.
if (board[row * 3] != 'O' && board[row * 3 + 1] != 'O' && board[row * 3 + 2] != 'O')
return false; // No O's so X can win. Not a tie.
}
for (int col = 0; col < 3; col++)
{
if ((board[col] != 'X') && (board[col + 3] != 'X') && (board[col + 6] != 'X'))
return false; // No X's so O can win. Not a tie.
if ((board[col] != 'O') && (board[col + 3] != 'O') && (board[col + 6] != 'O'))
return false; // No O's so X can win. Not a tie.
}
Serial.println();
// Falling diagonal
if (board[0] != 'X' && board[4] != 'X' && board[8] != 'X')
return false; // No X's so O can win. Not a tie.
if (board[0] != 'O' && board[4] != 'O' && board[8] != 'O')
return false; // No O's so X can win. Not a tie.
// Rising diagonal
if (board[6] != 'X' && board[4] != 'X' && board[2] != 'X')
return false; // No X's so O can win. Not a tie.
if (board[6] != 'O' && board[4] != 'O' && board[2] != 'O')
return false; // No O's so X can win. Not a tie.
Serial.println("It's a TIE! No winning moves left for either player.");
return true; // No winning moves left
}
void AnnounceWinner(char player, const char *play, int playIndex)
{
Serial.print("Player ");
Serial.print(player);
Serial.print(" wins on ");
Serial.print(play);
if (playIndex != 0)
{
Serial.print(' ');
Serial.print(playIndex);
}
Serial.println('.');
}