#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
const int buttons[9] = {2,3,4,5,6,7,8,9,10};
int board[9];
void drawBoard() {
display.clearDisplay();
display.drawLine(42, 0, 42, 64, WHITE);
display.drawLine(84, 0, 84, 64, WHITE);
display.drawLine(0, 21, 128, 21, WHITE);
display.drawLine(0, 43, 128, 43, WHITE);
for (int i = 0; i < 9; i++) {
int x = (i % 3) * 42 + 21;
int y = (i / 3) * 21 + 11;
if (board[i] == 1) {
display.drawLine(x-8, y-8, x+8, y+8, WHITE);
display.drawLine(x-8, y+8, x+8, y-8, WHITE);
} else if (board[i] == 2) {
display.drawCircle(x, y, 9, WHITE);
}
}
display.display();
}
bool checkWin(int p) {
int wins[8][3] = {
{0,1,2},{3,4,5},{6,7,8},
{0,3,6},{1,4,7},{2,5,8},
{0,4,8},{2,4,6}
};
for (int i=0;i<8;i++) {
if (board[wins[i][0]]==p && board[wins[i][1]]==p && board[wins[i][2]]==p) return true;
}
return false;
}
bool movesLeft() {
for (int i=0;i<9;i++) if (board[i]==0) return true;
return false;
}
// CPU imbatible: estrategia minimax
int minimax(int depth, bool isCPU) {
if (checkWin(1)) return 10 - depth;
if (checkWin(2)) return depth - 10;
if (!movesLeft()) return 0;
int best = isCPU ? -1000 : 1000;
for (int i=0;i<9;i++) {
if (board[i]==0) {
board[i] = isCPU ? 1 : 2;
int score = minimax(depth+1, !isCPU);
board[i] = 0;
if (isCPU) {
best = max(best, score);
} else {
best = min(best, score);
}
}
}
return best;
}
int bestMove() {
int bestVal = -1000;
int move = -1;
for (int i=0;i<9;i++) {
if (board[i]==0) {
board[i] = 1;
int moveVal = minimax(0, false);
board[i] = 0;
if (moveVal > bestVal) {
move = i;
bestVal = moveVal;
}
}
}
return move;
}
void setup() {
for (int i=0;i<9;i++) pinMode(buttons[i], INPUT_PULLUP);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) for(;;);
display.clearDisplay();
for (int i=0;i<9;i++) board[i]=0;
drawBoard();
}
void loop() {
// Leer botones
for (int i=0;i<9;i++) {
if (digitalRead(buttons[i]) == LOW && board[i]==0) {
board[i] = 2; // Jugador marca O
drawBoard();
if (checkWin(2)) { delay(2000); resetGame(); return; }
if (!movesLeft()) { delay(2000); resetGame(); return; }
int cpu = bestMove();
if (cpu != -1) board[cpu] = 1; // CPU marca X
drawBoard();
if (checkWin(1)) { delay(2000); resetGame(); return; }
if (!movesLeft()) { delay(2000); resetGame(); return; }
}
}
}
void resetGame() {
for (int i=0;i<9;i++) board[i]=0;
drawBoard();
}