Keep talking and nobody explodes Docs

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.

Foto van de bom puzzel

    #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();
    }
          
Tinkercad schema voor de bom puzzel