#include <iostream>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
using namespace std;
class TicTacToe {
private:
char board[3][3];
char currentPlayer;
int row;
int col;
bool endGame;
const int toggleButton;
const int selectButton;
const int resetButton;
const int ledRed;
const int ledGreen;
public:
TicTacToe(int togglePin, int selectPin, int resetPin, int redLed, int greenLed)
: toggleButton(togglePin), selectButton(selectPin), resetButton(resetPin), ledRed(redLed), ledGreen(greenLed) {
currentPlayer = 'X';
row = 0;
col = 0;
endGame = false;
// Initialize the game board
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = ' ';
}
}
// Initialize GPIO pins for buttons
gpio_init(toggleButton);
gpio_set_dir(toggleButton, GPIO_IN);
gpio_pull_up(toggleButton);
gpio_init(selectButton);
gpio_set_dir(selectButton, GPIO_IN);
gpio_pull_up(selectButton);
gpio_init(resetButton);
gpio_set_dir(resetButton, GPIO_IN);
gpio_pull_up(resetButton);
// Initialize GPIO pins for LEDs
gpio_init(ledRed);
gpio_set_dir(ledRed, GPIO_OUT);
gpio_init(ledGreen);
gpio_set_dir(ledGreen, GPIO_OUT);
}
// Function to print the Tic-Tac-Toe board
void displayBoard() {
cout << endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == row && j == col) {
cout << "[" << board[i][j] << "]";
} else {
cout << " " << board[i][j] << " ";
}
if (j < 2) cout << "|";
}
cout << endl;
if (i < 2) {
cout << "---+---+---" << endl;
}
}
cout << endl;
}
// Function to check if the current player has won
bool checkWin() {
// Check rows, columns, and diagonals
for (int i = 0; i < 3; i++) {
if (board[i][0] == currentPlayer && board[i][1] == currentPlayer && board[i][2] == currentPlayer) {
return true; // Row
}
if (board[0][i] == currentPlayer && board[1][i] == currentPlayer && board[2][i] == currentPlayer) {
return true; // Column
}
}
if (board[0][0] == currentPlayer && board[1][1] == currentPlayer && board[2][2] == currentPlayer) {
return true; // Diagonal (top-left to bottom-right)
}
if (board[0][2] == currentPlayer && board[1][1] == currentPlayer && board[2][0] == currentPlayer) {
return true; // Diagonal (top-right to bottom-left)
}
return false;
}
// Function to check for a tie
bool checkTie() {
// Check if all cells are filled
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == ' ') {
return false; // Board is not full
}
}
}
return true; // Board is full (tie)
}
// Function to reset the game
void resetGame() {
// Clear the board
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
board[i][j] = ' ';
}
}
// Reset game state
currentPlayer = 'X';
row = 0;
col = 0;
endGame = false;
cout << "Game reset, Player X starts." << endl;
}
// Function to end the current game
void endCurrentGame() {
endGame = true;
gpio_put(ledRed, false);
gpio_put(ledGreen, false);
sleep_ms(2000); // Delay for 2 seconds
resetGame(); // Reset the game state
}
// Function to run the game loop
void runGameLoop() {
while (1) {
// Check for game reset button
if (gpio_get(resetButton) == 0) {
resetGame();
gpio_put(ledRed, false); // Turn off ledRed
gpio_put(ledGreen, false); // Turn off ledGreen
sleep_ms(500); // Debounce delay
displayBoard();
continue;
}
// Check for button presses
if (gpio_get(toggleButton) == 0) {
// Toggle mode, move the cursor
cout << "Current Player: " << currentPlayer << "!!";
col = (col + 1) % 3;
if (col == 0) {
row = (row + 1) % 3;
}
displayBoard();
sleep_ms(200); // Delay for smoother cursor movement
} else if (gpio_get(selectButton) == 0 && !endGame) {
// Select mode, mark the cell
if (board[row][col] == ' ') {
board[row][col] = currentPlayer;
// Check if the current player has won
if (checkWin()) {
displayBoard();
cout << "Player " << currentPlayer << " wins! Congratulations!" << endl;
endCurrentGame();
} else {
// Check if the board is full (tie)
if (checkTie()) {
displayBoard();
cout << "Game tied!" << endl;
endCurrentGame();
} else {
if (currentPlayer == 'X') {
currentPlayer = 'O';
} else {
currentPlayer = 'X';
}
// Reset the cursor position
row = 0;
col = 0;
sleep_ms(500); // Delay before switching players for a smoother experience
gpio_put(ledRed, currentPlayer == 'X'); // Turn on ledRed if currentPlayer is 'X'
gpio_put(ledGreen, currentPlayer == 'O'); // Turn on ledGreen if currentPlayer is 'O'
}
}
} else {
cout << "Cell already occupied. Try again." << endl;
sleep_ms(500); // Delay for smoother experience after an invalid move
}
displayBoard();
}
sleep_ms(100); // Debounce delay
}
}
};
int main() {
stdio_init_all();
TicTacToe game(16, 17, 19, 14, 15); // Initialize the game with GPIO pins
game.runGameLoop(); // Start the game loop
return 0;
}