#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);
const int BUTTON_ROWS = 3;
const int BUTTON_COLS = 3;
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'},
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
const int PLAYER_NONE = 0;
const int PLAYER_1 = 1;
const int PLAYER_2 = 2;
int board[BUTTON_ROWS][BUTTON_COLS];
int currentPlayer;
bool gameOver;
int P1_points = 0;
int P2_points = 0;
void setup() {
lcd.begin(20, 4);
lcd.backlight();
lcd.print("Welcome To Tic-Tac-Toe");
delay(2000);
lcd.clear();
currentPlayer = PLAYER_1;
gameOver = false;
resetBoard();
updateDisplay();
}
void loop() {
char keypress = customKeypad.getKey();
if (keypress == 'D') { // Reset scores with 'D'
P1_points = 0;
P2_points = 0;
updateDisplay();
}
if (keypress == '0') {
setup();
}
if (!gameOver) {
if (keypress >= '1' && keypress <= '9') {
int number = keypress - '1';
int i = number / 3;
int j = number % 3;
if (board[i][j] == PLAYER_NONE) {
board[i][j] = currentPlayer;
updateDisplay();
int result = checkWinCondition();
if (result == PLAYER_1) {
P1_points++;
gameOver = true;
lcd.setCursor(0, 4);
lcd.print("Player 1 wins!");
} else if (result == PLAYER_2) {
P2_points++;
gameOver = true;
lcd.setCursor(0, 4);
lcd.print("Player 2 wins!");
} else if (result == -1) {
gameOver = true;
lcd.setCursor(0, 4);
lcd.print("It's a draw!");
}
switchPlayers();
}
delay(200); // Button Rebound
}
}
}
void resetBoard() {
for (int i = 0; i < BUTTON_ROWS; i++) {
for (int j = 0; j < BUTTON_COLS; j++) {
board[i][j] = PLAYER_NONE;
}
}
}
void updateDisplay() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Player ");
lcd.print(currentPlayer == PLAYER_1 ? "1" : "2");
lcd.setCursor(0, 1);
for (int i = 0; i < BUTTON_ROWS; i++) {
lcd.setCursor(0, i + 1);
for (int j = 0; j < BUTTON_COLS; j++) {
lcd.print("|");
lcd.print(symbolForPlayer(board[i][j]));
}
lcd.print("|");
}
lcd.setCursor(15, 1);
lcd.print("Pts");
lcd.setCursor(15, 2);
lcd.print(P1_points);
lcd.setCursor(15, 3);
lcd.print(P2_points);
}
char symbolForPlayer(int player) {
if (player == PLAYER_1) {
return 'X';
} else if (player == PLAYER_2) {
return 'O';
}
return ' ';
}
void switchPlayers() {
currentPlayer = (currentPlayer == PLAYER_1) ? PLAYER_2 : PLAYER_1;
}
int checkWinCondition() {
for (int i = 0; i < BUTTON_ROWS; i++) {
if (board[i][0] != PLAYER_NONE && board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
return board[i][0];
}
}
for (int j = 0; j < BUTTON_COLS; j++) {
if (board[0][j] != PLAYER_NONE && board[0][j] == board[1][j] && board[1][j] == board[2][j]) {
return board[0][j];
}
}
if (board[0][0] != PLAYER_NONE && board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
return board[0][0];
}
if (board[0][2] != PLAYER_NONE && board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
return board[0][2];
}
for (int i = 0; i < BUTTON_ROWS; i++) {
for (int j = 0; j < BUTTON_COLS; j++) {
if (board[i][j] == PLAYER_NONE) {
return 0; // Game is still ongoing
}
}
}
return -1; // It's a draw
}