Joran — Bom puzzel
Deze puzzel, gemaakt door Joran, is een bom puzzel waarbij spelers een kabel moeten doorknippen om een bom te ontmantelen. De puzzel maakt gebruik van een OLED scherm, 3 kabels en een buzzer.
#include <Wire.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
// https://github.com/espressif/esp-at
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display breedte, in pixels
#define SCREEN_HEIGHT 64 // OLED display hoogte, in pixels
#define OLED_RESET 16 // Reset pin voor OLED display
#define SCREEN_ADDRESS 0x3C // I2C adres voor OLED display
#define BUZZER_PIN 14 // Pin voor buzzer
#define KABEL_R 13 // Pin voor rood kabel
#define KABEL_G 12 // Pin voor groen kabel
#define KABEL_B 0 // Pin voor blauw kabel
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int countdown = 60;
bool isDefused = false;
bool isDetonated = false;
enum Color { RED, GREEN, BLUE };
Color cableColor;
enum Phase { COUNTDOWN, CABLE };
Phase phase = COUNTDOWN;
typedef struct {
Color color;
} Message;
void onReceive(uint8_t *mac, uint8_t *data, uint8_t len) {
Message incoming;
memcpy(&incoming, data, sizeof(incoming));
if (!isDefused && !isDetonated) {
cableColor = incoming.color;
phase = CABLE;
}
}
void defuse() {
display.clearDisplay();
String label = "DEFUSED!";
int16_t x1, y1;
uint16_t w, h;
display.setTextSize(2);
display.getTextBounds(label, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w) / 2, (SCREEN_HEIGHT - h) / 2);
display.print(label);
display.display();
noTone(BUZZER_PIN);
isDefused = true;
}
void detonate() {
display.clearDisplay();
String label = "DETONATED!";
int16_t x1, y1;
uint16_t w, h;
display.setTextSize(2);
display.getTextBounds(label, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w) / 2, (SCREEN_HEIGHT - h) / 2);
display.print(label);
display.display();
tone(BUZZER_PIN, 1500, 400);
delay(500);
tone(BUZZER_PIN, 800, 400);
isDetonated = true;
}
void setup() {
pinMode(OLED_RESET, OUTPUT);
digitalWrite(OLED_RESET, LOW);
delay(20);
digitalWrite(OLED_RESET, HIGH);
Wire.begin(4, 5);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(KABEL_R, INPUT);
pinMode(KABEL_G, INPUT);
pinMode(KABEL_B, INPUT);
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
for (;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (esp_now_init() != 0) {
for (;;);
}
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb(onReceive);
}
void loop() {
if (isDefused || isDetonated) return;
display.clearDisplay();
if (phase == COUNTDOWN) {
static unsigned long lastTick = 0;
if (millis() - lastTick >= 1000) {
lastTick = millis();
if (countdown > 0) {
countdown--;
} else {
detonate();
return;
}
}
int minuten = countdown / 60;
int seconden = countdown % 60;
String label = "COUNTDOWN";
int16_t x1, y1;
uint16_t w, h;
display.setTextSize(2);
display.getTextBounds(label, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w) / 2, 4);
display.print(label);
String timer = "";
if (minuten < 10) timer += "0";
timer += minuten;
timer += ":";
if (seconden < 10) timer += "0";
timer += seconden;
display.setTextSize(3);
display.getTextBounds(timer, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w) / 2, 26);
display.print(timer);
int barWidth = map(countdown, 0, 60, 0, 120);
display.drawRect(4, 56, 120, 6, SSD1306_WHITE);
display.fillRect(4, 56, barWidth, 6, SSD1306_WHITE);
if (countdown <= 10) {
tone(BUZZER_PIN, 1000, 80);
} else if (countdown % 10 == 0) {
tone(BUZZER_PIN, 800, 100);
}
} else if (phase == CABLE) {
static unsigned long lastCableCheck = 0;
if (millis() - lastCableCheck < 30) return;
lastCableCheck = millis();
const int pins[3] = {KABEL_R, KABEL_G, KABEL_B};
for (uint8_t c = 0; c < 3; c++) {
if (digitalRead(pins[c]) == HIGH) {
if (c == (int)cableColor) {
defuse();
} else {
detonate();
}
return;
}
}
}
display.display();
}