Keep talking and nobody explodes Docs

Joran — Binaire led puzzel

Deze puzzel, gemaakt door Joran, is een binaire led puzzel waarbij spelers een geheim getal moeten raden door middel van een potentiometer en een drukknop. De puzzel maakt gebruik van een 4-cijferig 7-segment display en 8 binaire leds om feedback te geven over de gekozen waarde.

Foto van de binaire led puzzel

    #include <WiFi.h>
    #include <esp_now.h>

    #define SR_DATA   4
    #define SR_LATCH  5
    #define SR_CLOCK  6

    #define SEG_D1  7
    #define SEG_D2  8
    #define SEG_D3  9
    #define SEG_D4  10

    const int BIN_PINS[8] = {35, 36, 37, 38, 39, 40, 41, 42};

    #define RGB_R  45
    #define RGB_G  48
    #define RGB_B  47

    #define SERVO_PIN 18

    #define POT_PIN  1
    #define BTN_PIN  14

    #define POT_MAX  4095

    const int LOCKED_ANGLE = 0;
    const int UNLOCKED_ANGLE = 90;

    uint8_t receiverMAC[] = {0x48, 0x3f, 0xda, 0x0c, 0x67, 0xbf};

    enum Color { RED, GREEN, BLUE };
    Color cableColor;

    char StartPos[4] = {'O', 'H', 'L', 'C'};

    typedef struct { 
      Color color; 
      bool reset;
    } Message;
    Message msg; 

    enum Phase { BINARY, DONE };
    Phase phase = BINARY;

    uint8_t selectedVal = 0;
    uint8_t secretCodes[3];
    uint8_t currentRound = 0;

    unsigned long stableStart = 0;
    bool wasStable = false;
    const unsigned long STABLE_DURATION = 2000;

    const uint8_t SEG_DIGITS[10] = {
      0b00111111,  // 0
      0b00000110,  // 1
      0b01011011,  // 2
      0b01001111,  // 3
      0b01100110,  // 4
      0b01101101,  // 5
      0b01111101,  // 6
      0b00000111,  // 7
      0b01111111,  // 8
      0b01101111,  // 9
    };

    const uint8_t L =  0b00111000;
    const uint8_t O =  0b00111111;
    const uint8_t C =  0b00111001;
    const uint8_t H =  0b01110110;

    const uint8_t SEG_BLANK = 0b00000000;
    const uint8_t SEG_DASH  = 0b01000000;

    uint8_t segBuf[4] = {SEG_BLANK, SEG_BLANK, SEG_BLANK, SEG_BLANK};

    void sendSegment(uint8_t data) {
      digitalWrite(SR_LATCH, LOW);
      shiftOut(SR_DATA, SR_CLOCK, MSBFIRST, data);
      digitalWrite(SR_LATCH, HIGH);
    }

    void refreshDisplay() {
      static uint32_t last = 0;
      static uint8_t digit = 0;
      if (micros() - last < 2000) return;
      last = micros();

      digitalWrite(SEG_D1, HIGH);
      digitalWrite(SEG_D2, HIGH);
      digitalWrite(SEG_D3, HIGH);
      digitalWrite(SEG_D4, HIGH);

      sendSegment(segBuf[digit]);

      switch (digit) {
        case 0: digitalWrite(SEG_D1, LOW); break;
        case 1: digitalWrite(SEG_D2, LOW); break;
        case 2: digitalWrite(SEG_D3, LOW); break;
        case 3: digitalWrite(SEG_D4, LOW); break;
      }
      digit = (digit + 1) & 0x03;
    }

    void showNumber(uint8_t val) {
      segBuf[0] = SEG_BLANK;
      segBuf[1] = (val >= 100) ? SEG_DIGITS[val / 100]       : SEG_BLANK;
      segBuf[2] = (val >= 10)  ? SEG_DIGITS[(val / 10) % 10] : SEG_BLANK;
      segBuf[3] = SEG_DIGITS[val % 10];
    }

    void showRx(char tx) {
      switch (tx) {
        case 'O':
          segBuf[0] = O; segBuf[1] = O; segBuf[2] = O; segBuf[3] = O;
          break;
        case 'H':
          segBuf[0] = H; segBuf[1] = H; segBuf[2] = H; segBuf[3] = H;
          break;
        case 'L':
          segBuf[0] = L; segBuf[1] = L; segBuf[2] = L; segBuf[3] = L;
          break;
        case 'C':
          segBuf[0] = C; segBuf[1] = C; segBuf[2] = C; segBuf[3] = C;
          break;
        default:
          segBuf[0] = SEG_BLANK;
          break;
      }
    }

    void showBinaryLEDs(uint8_t val) {
      for (int i = 0; i < 8; i++)
        digitalWrite(BIN_PINS[i], (val >> (7 - i)) & 1);
    }

    void setRGB(bool r, bool g, bool b) {
      digitalWrite(RGB_R, r);
      digitalWrite(RGB_G, g);
      digitalWrite(RGB_B, b);
    }

    void sendColor(Color cableColor) {
      msg.reset = false;
      msg.color = cableColor;
      esp_now_send(receiverMAC, (uint8_t *)&msg, sizeof(msg));
    }

    void setup() {
      Serial.begin(9600);

      pinMode(SR_DATA,  OUTPUT);
      pinMode(SR_CLOCK, OUTPUT);
      pinMode(SR_LATCH, OUTPUT);

      pinMode(SEG_D1, OUTPUT); digitalWrite(SEG_D1, HIGH);
      pinMode(SEG_D2, OUTPUT); digitalWrite(SEG_D2, HIGH);
      pinMode(SEG_D3, OUTPUT); digitalWrite(SEG_D3, HIGH);
      pinMode(SEG_D4, OUTPUT); digitalWrite(SEG_D4, HIGH);

      for (int i = 0; i < 8; i++) pinMode(BIN_PINS[i], OUTPUT);

      pinMode(RGB_R, OUTPUT);
      pinMode(RGB_G, OUTPUT);
      pinMode(RGB_B, OUTPUT);

      analogReadResolution(12);
      analogSetPinAttenuation(POT_PIN, ADC_11db);

      WiFi.mode(WIFI_STA);
      esp_now_init();
      esp_now_peer_info_t peer = {};
      memcpy(peer.peer_addr, receiverMAC, 6);
      peer.channel = 0;
      peer.encrypt = false;
      esp_now_add_peer(&peer);

      randomSeed(analogRead(0));
      for (int i = 0; i < 3; i++) secretCodes[i] = random(1, 256);
      cableColor = (Color)random(0, 3);

      showBinaryLEDs(secretCodes[0]);
      setRGB(false, false, false);
    }

    void loop() {
      refreshDisplay();

      if (Serial.available()) {
        char rx = Serial.read();
        if (rx == 'M') {
          sendColor(cableColor);
        }
      }
      
      bool btn = digitalRead(BTN_PIN);

      if (btn == HIGH) {
        msg.reset = true;
        msg.color = cableColor;
        esp_now_send(receiverMAC, (uint8_t *)&msg, sizeof(msg));
        msg.reset = false;
        Serial.write('R');

        currentRound = 0;
        phase = BINARY;
        wasStable = false;
        stableStart = 0;

        for (int i = 0; i < 3; i++) secretCodes[i] = random(1, 256);
        cableColor = (Color)random(0, 3);

        showBinaryLEDs(secretCodes[0]);
        delay(200);
      }

      if (phase == BINARY) {
        static int filtered = 0;

        int raw = analogRead(POT_PIN);
        filtered = (filtered * 7 + raw) / 8;

        int clamped = constrain(filtered, 0, POT_MAX);
        selectedVal = map(clamped, 0, POT_MAX, 0, 255);

        showNumber(selectedVal);

        uint8_t secret = secretCodes[currentRound];
        int margin = max(1, secret * 5 / 100);
        bool correct = abs(selectedVal - secret) <= margin;

        int specialMargin = 5;
        bool isSpecial = abs(selectedVal - 100) <= specialMargin;

        if (correct) {
          if (!wasStable) {
            stableStart = millis();
            wasStable = true;
          } else if (millis() - stableStart >= STABLE_DURATION) {
            currentRound++;

            if (currentRound >= 3) {
              char tx = StartPos[random(0, 4)];
              Serial.write(tx);
              showRx(tx);
              phase = DONE;
            } else {
              showBinaryLEDs(secretCodes[currentRound]);
              wasStable = false;
            }
          }
        } else {
          wasStable = false;
        }
      }
    }
          
Tinkercad schema voor de binaire puzzel