// ============================================================ // explode.ino — Bomb Detector // // Place a piece on either promotion rank (row 0 or row 7) // and that square counts down to detonation. // 8 blinks: slow → exponentially faster, like a bomb fuse. // The square stays lit red at the end. // Pieces placed on any other row are ignored. // Only the triggered square ever lights up — nothing else. // // Place another piece on a back rank to trigger again. // ============================================================ #include // ── Hardware ───────────────────────────────────────────────── #define LED_PIN 1 #define LED_COUNT 64 #define BRIGHTNESS 150 #define SER_PIN 45 #define RCLK_PIN 47 #define SRCLK_PIN 46 const int ROW_PINS[8] = {42, 41, 40, 39, 38, 37, 36, 35}; Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_RGBW + NEO_KHZ800); // ── Sensor state ────────────────────────────────────────────── bool sensor[8][8], sensorPrev[8][8]; bool exploded[8][8]; // squares currently glowing red after a countdown // ── Hardware helpers ────────────────────────────────────────── void setColumn(int col) { digitalWrite(RCLK_PIN, LOW); for (int i = 7; i >= 0; i--) { digitalWrite(SRCLK_PIN, LOW); digitalWrite(SER_PIN, (i == col) ? HIGH : LOW); digitalWrite(SRCLK_PIN, HIGH); } digitalWrite(RCLK_PIN, HIGH); } void clearCols() { digitalWrite(RCLK_PIN, LOW); for (int i = 0; i < 8; i++) { digitalWrite(SRCLK_PIN, LOW); digitalWrite(SER_PIN, LOW); digitalWrite(SRCLK_PIN, HIGH); } digitalWrite(RCLK_PIN, HIGH); } void readSensors() { for (int c = 0; c < 8; c++) { setColumn(c); delayMicroseconds(10); for (int r = 0; r < 8; r++) sensor[r][c] = (digitalRead(ROW_PINS[r]) == LOW); } clearCols(); } // ── Red color — strip is physically GRBW so swap R↔G ───────── #define RED strip.Color(0, 255, 0, 0) // ── Blink intervals (ms) — exponential decay, 8 steps ──────── // 2 slow, then ripping faster each time const int BLINK_MS[8] = { 450, 380, 260, 170, 110, 70, 40, 20 }; // ── Countdown and hold on a single pixel ───────────────────── void detonate(int row, int col) { int px = row * 8 + col; for (int i = 0; i < 8; i++) { // ON strip.setPixelColor(px, RED); strip.show(); delay(BLINK_MS[i]); // OFF (skip the last off so it stays lit) if (i < 7) { strip.setPixelColor(px, 0); strip.show(); delay(BLINK_MS[i]); } } // Leave the square lit red while the piece is still there strip.setPixelColor(px, RED); strip.show(); exploded[row][col] = true; } // ── Setup ───────────────────────────────────────────────────── void setup() { pinMode(SER_PIN, OUTPUT); pinMode(RCLK_PIN, OUTPUT); pinMode(SRCLK_PIN, OUTPUT); for (int i = 0; i < 8; i++) pinMode(ROW_PINS[i], INPUT_PULLUP); strip.begin(); strip.setBrightness(BRIGHTNESS); strip.clear(); strip.show(); memset(exploded, 0, sizeof(exploded)); readSensors(); memcpy(sensorPrev, sensor, sizeof(sensor)); } // ── Loop ────────────────────────────────────────────────────── void loop() { readSensors(); for (int r = 0; r < 8; r++) { for (int c = 0; c < 8; c++) { // Piece removed from an exploded square — clear the light if (exploded[r][c] && !sensor[r][c]) { strip.setPixelColor(r * 8 + c, 0); strip.show(); exploded[r][c] = false; } // New piece placed on a back rank — trigger countdown if (sensor[r][c] && !sensorPrev[r][c] && (r == 0 || r == 7)) { detonate(r, c); readSensors(); memcpy(sensorPrev, sensor, sizeof(sensor)); return; } } } memcpy(sensorPrev, sensor, sizeof(sensor)); delay(20); }