/*
Uno Link 4
created 10.19.2023 -q
*/
#include <Adafruit_NeoPixel.h>
#define NUMPIXELS 49
#define PIN 2
#define BTN_R 3
#define BTN_D 4
#define BTN_L 5
#define PLAYR_1 1
#define PLAYR_2 2
#define MAX_COL 6
#define MAX_ROW 5
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ800);
uint32_t empty = strip.Color(255, 255, 255);
uint32_t blu = strip.Color(0, 0, 255);
uint32_t red = strip.Color(0, 255, 0);
uint32_t off = strip.Color(0, 0, 0);
uint32_t currentPlayer = blu;
int16_t cur_bright = 255;
byte playerUp = PLAYR_1;
byte dropPosistion = 3;
byte gameMode = 0;
byte WinLeds[4];
byte GameGrid[7][6] = {
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0}
};
byte LedGrid[7][6] = {
{7, 14, 21, 28, 35, 42},
{8, 15, 22, 29, 36, 43},
{9, 16, 23, 30, 37, 44},
{10, 17, 24, 31, 38, 45},
{11, 18, 25, 32, 39, 46},
{12, 19, 26, 33, 40, 47},
{13, 20, 27, 34, 41, 48}
};
byte btnPins[3] = {5, 4, 3};
unsigned long debouncers[3];
byte lastButtons[3] = {1, 1, 1};
int dropToo = 0;
byte dropStep = 0;
unsigned long lastStep;
int dropSpeed = 100;
int blinkSpeed = 250;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("ready..");
pinMode(BTN_L, INPUT_PULLUP);
pinMode(BTN_D, INPUT_PULLUP);
pinMode(BTN_R, INPUT_PULLUP);
strip.begin();
for (int i = 0; i < NUMPIXELS; i++) {
strip.setPixelColor(i, empty);
}
strip.setPixelColor(dropPosistion, blu);
strip.show();
for (int col = 0; col < 7; col++) {
for (int row = 0; row < 6; row++) {
GameGrid[col][row] = 0;
}
}
}
void loop() {
unsigned long now = millis();
if (gameMode == 0) {
for (int i = 0; i < 3; i++) {
if (now - debouncers[i] >= 50) {
byte btn = digitalRead(btnPins[i]);
if (btn != lastButtons[i]) {
lastButtons[i] = btn;
debouncers[i] = now;
if (btn == LOW) {
switch (i) {
case 0: if (dropPosistion > 0) {
dropPosistion--;
strip.setPixelColor(dropPosistion, currentPlayer);
strip.setPixelColor(dropPosistion + 1, empty);
strip.show();
}
break;
case 1: if (CanDrop(dropPosistion) > 0) {
dropToo = CanDrop(dropPosistion);
GameGrid[dropPosistion][dropToo - 2] = playerUp;
lastStep = now;
dropStep = 0;
gameMode = 1;
} else {
dropToo = CanDrop(dropPosistion);
} break;
case 2: if (dropPosistion < 6) {
dropPosistion++;
strip.setPixelColor(dropPosistion, currentPlayer);
strip.setPixelColor(dropPosistion - 1, empty);
strip.show();
} break;
}
}
}
}
}
} else if (gameMode == 1) {
//dropping..
if (now - lastStep >= dropSpeed) {
lastStep = now;
strip.setPixelColor(dropPosistion + (dropStep * 7), currentPlayer);
if (dropStep > 0)
strip.setPixelColor(dropPosistion + ((dropStep - 1) * 7), empty);
strip.show();
dropStep++;
if (dropStep == dropToo) {
//check for a winning drop..
if (DropWins(dropToo - 2)) {
Serial.println("Winner");
dropStep = 0;
dropToo = 11;
gameMode = 2;
return;
}
gameMode = 0;
if (currentPlayer == blu) currentPlayer = red; else currentPlayer = blu;
if (playerUp == PLAYR_1) playerUp = PLAYR_2; else playerUp = PLAYR_1;
strip.setPixelColor(dropPosistion, currentPlayer);
strip.show();
}
}
} else if (gameMode == 2) {
if (now - lastStep >= blinkSpeed) {
lastStep = now;
for (int i = 0; i < 4; i++) {
if (dropStep == 0) {
strip.setPixelColor(WinLeds[i], currentPlayer);
} else {
strip.setPixelColor(WinLeds[i], empty);
}
}
strip.show();
dropStep++;
if (dropStep > 1) dropStep = 0;
dropToo--;
if (dropToo == 0) {
gameMode = 0;
ResetGame();
}
}
}
}
void ResetGame() {
//clear leds..
for (int i = 0; i < NUMPIXELS; i++) {
strip.setPixelColor(i, empty);
}
strip.show();
//clear gamegrid
for (int col = 0; col < 7; col++) {
for (int row = 0; row < 6; row++) {
GameGrid[col][row] = 0;
}
}
//set next player up..
dropPosistion = 3;
if (currentPlayer == blu) currentPlayer = red; else currentPlayer = blu;
if (playerUp == PLAYR_1) playerUp = PLAYR_2; else playerUp = PLAYR_1;
strip.setPixelColor(dropPosistion, currentPlayer);
strip.show();
}
bool DropWins(int drop) {
bool result = false;
byte col = dropPosistion;
byte row = drop;
result = CheckCol(col);
if (!result) result = CheckRow(row);
if (!result) result = CheckDiag(col, row);
return (result);
}
bool CheckCol(int col) {
bool result = false;
byte cnt = 0;
for (int i = 0; i < 6; i++)
{
if (GameGrid[col][i] == playerUp) {
if (cnt < 4) WinLeds[cnt] = LedGrid[col][i];
cnt++;
} else if (cnt < 4) cnt = 0;
}
if (cnt > 3) result = true;
return (result);
}
bool CheckRow(int row) {
bool result = false;
byte cnt = 0;
for (int i = 0; i < 7; i++)
{
if (GameGrid[i][row] == playerUp) {
if (cnt < 4) WinLeds[cnt] = LedGrid[i][row];
cnt++;
} else if (cnt < 4) cnt = 0;
}
if (cnt > 3) result = true;
return (result);
}
bool CheckDiag(int col, int row) {
bool result = false;
int startCol, startRow, count;
//top left..
if (col > row) {
startCol = col - row;
startRow = 0;
} else {
startCol = 0;
startRow = row - col;
}
int rowStep = 0;
for (int c = startCol; c < MAX_COL + 1; c++) {
if (GameGrid[c][startRow + rowStep] == playerUp) {
if (count < 4) WinLeds[count] = LedGrid[c][startRow + rowStep];
count++;
} else if (count < 4) count = 0;
rowStep++;
}
//top right
if (count < 4) {
count = 0;
startCol = row + col;
if (startCol > MAX_COL) {
startCol = MAX_COL;
startRow = row - ((col + row) - startCol);
}
else
startRow = 0;
int rowStep = 0;
for (int c = startCol; c > -1; c--) {
if (GameGrid[c][startRow + rowStep] == playerUp) {
if (count < 4) WinLeds[count] = LedGrid[c][startRow + rowStep];
count++;
} else if (count < 4) count = 0;
rowStep++;
}
}
if (count > 3) result = true;
return (result);
}
int CanDrop(byte col) {
int result = -1;
for (int i = 0; i < 6; i++) {
if (GameGrid[col][i] != 0) {
byte val = GameGrid[col][i];
break;
} else result = i;
}
if (result > -1) result += 2;
return (result);
}