2 large if statements firing at the same time

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('.');
}

Nice. Now do chess.

:wink:

a7

A joke of course, chess would be really difficult! Even human player Vs human player.

If you enjoyed tic-tac-toe (noughts-and-crosses over here), the next challenging-but-achievable step up would be "connect-4".

I have a chess-playing program I wrote in college. Anyone want to port it from Fortran? :slight_smile:

You could use A Fortranuino.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.