Mateo’s Final Project – Open the Box Game

The final post before freedom. Yay!

For my final project, I built a game with the final objective to open a locked box and get FREEE CANDY!!!!!!1!!!1!ONE! 😀

My game consisted in three main parts:

  1. The box
  2. The card reader
  3. The laptop

First, the box. I built it out of acryllic. It took forever to build. It was a bit nightmareish at times. BUT IT WAS WORTH IT. The box had four buttons numbered 1-4 to input passwords, four red LEDs to indicate password progression (i.e. two LEDs light up once two numbers have been punched in), an RGB LED to signal a wrong or right password, and a servo to lock the box. And, of course, a Trinket Pro microcontroller (because it is tinier and cuter than the RedBoard, and thus fits in better). A right password makes the servo move and allow the lid of the box to slide open.

Box in progress
Box in progress
Box in progress in progress
Box in progress in progress
Checking the buttons and LEDs
Checking the buttons and LEDs
Starting to wire up...
Starting to wire up…
RELEASE THE KRAKEN
RELEASE THE KRAKEN

But the box is not just as simple as that. Using serial communication, I added two functions to the box. First, I added a second “right” password that, instead of opening the box, would send information to the main program in the laptop to advance the game. Second, I turned the password “4444” (as well as any button press after the box has been opened) into a signal to reset the game for another player to start from the beginning.

THE FINISHED BOX
THE FINISHED BOX
BOX BOX BOX
BOX BOX BOX

Second, the card reader. It has a RFID shield to read cards, and a mystery button to inpute passwords in morse code (because I’m evil). Given my lack of a better button/time/acryllic glue/motivation, I built the reader using the plastic thingy that came with our RedBoard, a breadboard, and some acryllic to make it look nicer. All put together using hot glue YAY.

Building the reader...
Building the reader…
ROOM KEYS!(?)
ROOM KEYS!(?)

The card reader also uses serial communication for two purposes. First, it sends information on the cards that are being read to the laptop. Second, it sends dots and dashes when the morse code button is pressed in order for the main program to read the sequence as a message/password in Morse code. (BONUS: the thing actually beeps when using Morse Code yay!)

The card reader!
The card reader!

And finally, the laptop. It contains the Processing sketch that runs most of the game. The sketch shows a series of strings in the screen, which provide instructions and clues that eventually lead to the final password to open the box. The game is advanced when it receives different kinds of input by the player: entering text using the keyboard, entering a password in the box (which sends it to the sketch through serial), or entering a password using morse code. Additionally, when a card is read, additional clues or information are displayed in the screen if it’s already time to use them (else, the screen will show an “encrypted” file consisting in a string of random characters). The cards don’t actually hold any files. Rather, the program shows a “file” based on the card’s unique ID, which is read and sent serially to Processing.

The game running
The game running
Close-up of the screen
Close-up of the screen

For the text, I created a Type class in order to produce the “typing” effect of the text appearing on the screen. While not perfect, it kinda has the aesthetic of old computers. I later learnt that the text() function has the ability to wrap text around edges, which might have made the whole thing easier to code. Oops.

And that’s kind of it. From the technical point of view, there’s not much more to add. The rest of the work was actually thinking out what kind of clues and puzzles I’d present the users (so, the game design) and making the game as understandable as I could int he time I had. I’m happy that people actively enjoyed the project, despite being admittedly somewhat confusing at times. 😀

Here’s the code:

#include <Servo.h>

int led4 = 12;
int led3 = 13;
int led2 = A0;
int led1 = A1;
int ledR = 9;
int ledG = 10;
int ledB = 11;
int but1 = 8;
int but2 = 5;
int but3 = 4;
int but4 = 3;

boolean state1, state2, state3, state4;
boolean prev1, prev2, prev3, prev4;
int color = 0;

String code = {};
String pass1 = "1123";

Servo lock;

void setup() {
  // Define I/O
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(ledB, OUTPUT);
  pinMode(but1, INPUT);
  pinMode(but2, INPUT);
  pinMode(but3, INPUT);
  pinMode(but4, INPUT);
  lock.attach(6); // Attach lock servo to pin
  lock.write(0); //Lock box
  // Set up initial state of lock buttons
  state1 = digitalRead(but1);
  prev1 = state1;
  state2 = digitalRead(but2);
  prev2 = state2;
  state3 = digitalRead(but3);
  prev3 = state3;
  state4 = digitalRead(but4);
  prev4 = state4;
  Serial.begin(9600);
}

void loop() {
  // Read passcode:
  //Read buttons
  state1 = digitalRead(but1);
  state2 = digitalRead(but2);
  state3 = digitalRead(but3);
  state4 = digitalRead(but4);
  // If button changed (is pressed), add button's number to code
  if (state1 != prev1) {
    // Delay and re-read to sniff out false button presses!
    delay(100); //Wait a bit
    state1 = digitalRead(but1); //read the state again
    if (state1 != prev1) { //If the state is STILL different...
      code += "1"; //...you can rule out an accidental double-press!
    }
  }
  if (state2 != prev2) {
    delay(100);
    state2 = digitalRead(but2);
    if (state2 != prev2) {
      code += "2";
    }
  }
  if (state3 != prev3) {
    delay(100);
    state3 = digitalRead(but3);
    if (state3 != prev3) {
      code += "3";
    }
  }
  if (state4 != prev4) {
    delay(100);
    state4 = digitalRead(but4);
    if (state4 != prev4) {
      code += "4";
    }
  }
  // Turn # of LEDs equal to code's current length
  switch (code.length()) {
    case 0:
      digitalWrite(led1, LOW);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      break;
    case 1:
      digitalWrite(led1, HIGH);
      digitalWrite(led2, LOW);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      break;
    case 2:
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, LOW);
      digitalWrite(led4, LOW);
      break;
    case 3:
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      digitalWrite(led4, LOW);
      break;
    case 4:
      digitalWrite(led1, HIGH);
      digitalWrite(led2, HIGH);
      digitalWrite(led3, HIGH);
      digitalWrite(led4, HIGH);
      break;
  }
  // Set previous states to current states for next reading
  prev1 = state1;
  prev2 = state2;
  prev3 = state3;
  prev4 = state4;
  // Password check part. This includes serial communication!
  if (code.length() != 4) { // Lock by default if code is incomplete
    lock.write(0);
    switch (color) {
      case 0:
        digitalWrite(ledR, LOW);
        digitalWrite(ledG, LOW);
        digitalWrite(ledB, LOW);
        break;
      case 1:
        digitalWrite(ledR, LOW);
        digitalWrite(ledG, LOW);
        digitalWrite(ledB, HIGH);
        break;
    }
    if (code.length() > 4) {
      code.remove(0);
      color = 0;
      Serial.println("0000");
    }
  } else {
    if (code != "1431") { // If code is wrong, flash RGB LED red
      if (code == pass1) {
        digitalWrite(ledR, LOW);
        digitalWrite(ledG, LOW);
        digitalWrite(ledB, HIGH);
      } else {
        digitalWrite(ledR, HIGH);
        digitalWrite(ledG, LOW);
        digitalWrite(ledB, LOW);
      }
      Serial.println(code);
      code.remove(0); // Empty code
      delay(1000); // delay for feedback
    } else { // If code is right, turn RGB green and unlock
      digitalWrite(ledR, LOW);
      digitalWrite(ledG, HIGH);
      digitalWrite(ledB, LOW);
      lock.write(180);
    }
  }
  if (Serial.available() > 0) {
    String in = Serial.readString();
    if (in == "blue") {
      color = 1;
    }
  }
}
//RFID Libraries
#include <Wire.h>
#include <Adafruit_PN532.h>

// If using the breakout or shield with I2C, define just the pins connected
// to the IRQ and reset lines.  Use the values below (2, 3) for the shield!
#define PN532_IRQ   (2)
#define PN532_RESET (3)  // Not connected by default on the NFC Shield

// Use this line for a breakout or shield with an I2C connection:
Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);

//Global variables
//Booleans to register morse button state
boolean pressed = false;
boolean prevPressed = false;
long tick = 0; //tick is used to count length of beep

long lastID = 0; //Last ID read by RFID
long lastCard = 0;
const long morseID = 28321276;

void setup() {
  //Morse set up
  pinMode(12, INPUT); //Morse code goes in
  pinMode(6, OUTPUT); //Beep sounds yay
  Serial.begin(9600);
  //Set up RFID reader shield
  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }

  // configure board to read RFID tags
  nfc.SAMConfig();
}

void loop() {
  //RFID read
  int thisID;
  int success;
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  // Wait for an ISO14443A type cards (Mifare, etc.).  When one is found
  // 'uid' will be populated with the UID, and uidLength will indicate
  // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);

  if (success) {
    // Display some basic information about the card
    //    if (uidLength == 4)
    //    {
    // We probably have a Mifare Classic card ...
    unsigned long cardid = uid[0];
    cardid <<= 8;
    cardid |= uid[1];
    cardid <<= 8;
    cardid |= uid[2];
    cardid <<= 8;
    cardid |= uid[3];
    thisID = cardid;
    lastCard = cardid;
    if (thisID != lastID) {
      Serial.println(cardid); // print the card number
    }
    lastID = thisID;
    //    }
  }
  //Morse read
  // If the morse card is inserted:
  if (lastCard == morseID) {
    pressed = digitalRead(12); //Read morse button
    //Beep while pressed
    if (pressed == true) {
      tone(6, 440);
    } else {
      noTone(6);
    }

    //If this is a new press...
    if (pressed == true && prevPressed != pressed) {
      tick = millis(); //...start counting time
      //Else, if this is the end of a press...
    } else if (pressed == false && prevPressed != pressed) {
      //...stop counting and compare:
      if (millis() - tick > 250) { //Over 0.25 seconds = dash
        Serial.println("-"); //Send dash serially
      } else if (millis() - tick > 50) { //Else, over 0.05 = dot
        Serial.println("."); //Send dot serially
        //Presses shorter than 50ms are considered mistakes and are ignored
      }
    }
    prevPressed = pressed; //Store previous state of the button
  }
}
import gab.opencv.*;
import java.awt.Rectangle;

import processing.video.*;

import processing.serial.*;

import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;

Minim minim;
AudioOutput out;
Serial morse;
Serial box;
Capture capture;
OpenCV opencv;
Rectangle[] faces = {};

String random1, random2, random3;

int textSize = 24;
String welcome = "Hello, and welcome to my final Intro to Interactive Media project. "
  + "There's a box with candy next to the computer. If you can solve my puzzles and open it, "
  + "you may take a candy!\n\nOkay, are you ready?\n\n(You can input answers when the "
  + "screen is green using the keyboard and ENTER. Try answering \"yes\")";
String clue1 = "You can read the cards' contents using the card reader. Most of them "
  + "are encrypted, but you should find your first clue in one of 'em...\n\n(A blue screen "
  + "means you should input a password using the box's buttons.)";
String clue2 = "The Fibonacci sequence, very well. Solving puzzles might decrypt "
  + "your encrypted cards, leading you to the next clue.\n\nYay\n\nNow tell me... the "
  + "complement of green is...";
String clue3 = "You should have heard of this code. It's used quiiite often for "
  + "distress signals. But this time around you should pull an Ali Baba and ask "
  + "your Sesame to...\n\n(Answer is checked two seconds after last input)";
String clue4 = "You are almost there! The one last thing you need to know is that "
  + "the answer is the death of the witch.\n\n(Input your answer in the box to open it!)";
String[] text = {welcome, clue1, clue2, clue3, clue4};

String joan = "Joan of Arc\n(1412 - 1431)\n\nJoan of Arc is a heroine of France who led the French "
  + "against the English during the Hundred Years' war. Originally a peasant, she was eventually "
  + "canonized by the Catholic Church as a saint. This, however, happened centuries after her death, "
  + "as at the time she was considered heretic. The English captured her in 1430 and burnt her at the "
  + "stake one year later, just like a witch...";

char[] input = {};
char[] morseIn = {};
int stage = 0;
int cardClue = 0;
int morseTime = 0;
boolean green = false; // When true, user input is accepted
boolean sos = false;
int sosCount = 0;

PImage spiral;
PImage morseCode;
String spiralt = "The Golden Spiral is related to the mathematical constant Phi, which can also be found in a famous sequence.";
String colorClue = "The RGB color system is an additive system, which uses red, green and "
  + "blue as primary colors. The complements to those colors are the primary colors in "
  + "a substractive system: CMY correspond to cyan, m#$%@$% and yellow";
String cheat1 = "This person tried to cheat me by using their room key in my card reader. Meanie. :'c";
String cheat2 = "Pls stop cheating or I won't give any candy to you and I'll be sad kthxbai. :'c";
String pass1 = "1123";

ArrayList<Type> types = new ArrayList<Type>();

void setup() {
  fullScreen();
  // Set up audio
  minim = new Minim(this);
  out = minim.getLineOut();
  out.setTempo(120);
  // Set up serial ports
  morse = new Serial(this, "COM3", 9600);
  morse.bufferUntil('\n');
  box = new Serial(this, "COM4", 9600);
  box.bufferUntil('\n');
  // Set up text to be typed
  for (int q = 0; q < text.length; q ++) {
    types.add(new Type(text[q]));
  }
  // Set up images
  spiral = loadImage("GoldenSpiral.gif");
  morseCode = loadImage("morsecode.jpg");
  // Set up noise strings
  char[] randChar1 = {};
  for (int q = 0; q < 200; q ++) {
    randChar1 = append(randChar1, randomChar());
  }
  random1 = charToString(randChar1);
  char[] randChar2 = {};
  for (int q = 0; q < 200; q ++) {
    randChar2 = append(randChar2, randomChar());
  }
  random2 = charToString(randChar2);
  char[] randChar3 = {};
  for (int q = 0; q < 200; q ++) {
    randChar3 = append(randChar3, randomChar());
  }
  random3 = charToString(randChar3);
  // Set up easter egg capture
  capture = new Capture(this, 640, 480);
  capture.start();
  // set up easter egg OpenCV
  opencv = new OpenCV(this, capture);
  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);
}

void draw() {
  background(0);
  fill(255);
  strokeWeight(1);
  green = false;
  if (sos) {
    if (sosCount < 120) {
      background(random(0, 255), random(0, 255), random(0, 255));
      textSize(random(12, 72));
      text("1", random(0, width), random(0, height));
      text("4", random(0, width), random(0, height));
      text("3", random(0, width), random(0, height));
      text("1", random(0, width), random(0, height));
      text("1 4", random(0, width), random(0, height));
      text("4 3", random(0, width), random(0, height));
      text("3 1", random(0, width), random(0, height));
      text("1 4 3", random(0, width), random(0, height));
      text("4 3 1", random(0, width), random(0, height));
      text("1 4 3 1", random(0, width), random(0, height));
      sosCount ++;
    } else {
      sos = false;
      sosCount = 0;
    }
  } else {
    if (types.get(stage).trigger) {
      switch (stage) {
      case 0:
        background(0, 128, 0);
        green = true;
        for (int q = 0; q < input.length; q ++) {
          textSize(textSize);
          text(input[q], 40 + q*textSize, 350);
        }
        break;
      case 1:
        background(0, 0, 255);
        switch (cardClue) {
        case 0:
          break;
        case 1:
          textSize(16);
          text(spiralt, 200, 350, 500, 400);
          image(invert(spiral), 200, 400);
          break;
        case 2:
          textSize(16);
          text(random1, 200, 350, 500, 400);
          break;
        case 3:
          textSize(16);
          text(random2, 200, 350, 500, 400);
          break;
        case 4:
          textSize(16);
          text(random3, 200, 350, 500, 400);
          break;
        case 5:
          textSize(16);
          image(capture, width/2 -300, 350);
          opencv.loadImage(capture);
          Rectangle[] faces = opencv.detect();
          for (int i = 0; i < faces.length; i ++) {
            pushMatrix();
            translate(width/2 - 300, 350);
            sadFace(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
            popMatrix();
          }
          text(cheat1, 100, 350, 300, 450);
          text(cheat2, 100, 500, 300, 600);
          break;
        }
        break;
      case 2:
        background(0, 128, 0);
        green = true;
        for (int q = 0; q < input.length; q ++) {
          textSize(textSize);
          text(input[q], 40 + q*textSize, 350);
        }
        switch (cardClue) {
        case 0:
          break;
        case 1:
          textSize(16);
          text(spiralt, 200, 350, 500, 400);
          image(invert(spiral), 200, 400);
          break;
        case 2:
          textSize(16);
          text(random1, 200, 350, 500, 400);
          break;
        case 3:
          textSize(16);
          text(colorClue, 200, 450, 500, 400);
          colorChart(800, 450);
          break;
        case 4:
          textSize(16);
          text(random3, 200, 350, 500, 400);
          break;
        case 5:
          textSize(16);
          image(capture, width/2 -300, 350);
          opencv.loadImage(capture);
          Rectangle[] faces = opencv.detect();
          for (int i = 0; i < faces.length; i ++) {
            pushMatrix();
            translate(width/2 - 300, 350);
            sadFace(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
            popMatrix();
          }
          text(cheat1, 100, 350, 300, 450);
          text(cheat2, 100, 500, 300, 600);
          break;
        }
        break;
      case 3:
        switch (cardClue) {
        case 0:
          break;
        case 1:
          textSize(16);
          text(spiralt, 200, 350, 500, 400);
          image(invert(spiral), 200, 400);
          break;
        case 2:
          textSize(16);
          image(morseCode, 200, 400);
          break;
        case 3:
          textSize(16);
          text(colorClue, 200, 350, 500, 400);
          colorChart(800, 350);
          break;
        case 4:
          textSize(16);
          text(random3, 200, 350, 500, 400);
          break;
        case 5:
          textSize(16);
          image(capture, width/2 -300, 350);
          opencv.loadImage(capture);
          Rectangle[] faces = opencv.detect();
          for (int i = 0; i < faces.length; i ++) {
            pushMatrix();
            translate(width/2 - 300, 350);
            sadFace(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
            popMatrix();
          }
          text(cheat1, 100, 350, 300, 450);
          text(cheat2, 100, 500, 300, 600);
          break;
        }
        break;
      case 4:
        background(0, 0, 255);
        switch (cardClue) {
        case 0:
          break;
        case 1:
          textSize(16);
          text(spiralt, 200, 350, 500, 400);
          image(invert(spiral), 200, 400);
          break;
        case 2:
          textSize(16);
          image(morseCode, 200, 400);
          break;
        case 3:
          textSize(16);
          text(colorClue, 200, 350, 500, 400);
          colorChart(800, 350);
          break;
        case 4:
          textSize(16);
          text(joan, 200, 350, width - 200, height - 200);
          break;
        case 5:
          textSize(16);
          image(capture, width/2 -300, 350);
          opencv.loadImage(capture);
          Rectangle[] faces = opencv.detect();
          for (int i = 0; i < faces.length; i ++) {
            pushMatrix();
            translate(width/2 - 300, 350);
            sadFace(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
            popMatrix();
          }
          text(cheat1, 100, 350, 300, 450);
          text(cheat2, 100, 500, 300, 600);
          break;
        }
        break;
      }
    }
    strokeWeight(1);
    fill(255);
    types.get(stage).type(40, 40, textSize, 2);
    if (morseTime > 0) {
      morseTime --;
    } else {
      if (charToString(morseIn).equals("---.--..-.")) {
        stage = 4;
      } else if (charToString(morseIn).equals("...---...")) {
        sos = true;
      } else if (morseIn.length > 0) {
        background(255, 0, 0);
      }
      for (int q = morseIn.length - 1; q >= 0; q --) {
        morseIn = shorten(morseIn);
      }
    }
  }
}

void keyPressed() {
  if (green == false) {
    return;
  }
  if (key != BACKSPACE) {
    if (keyCode != 16 && key != ENTER) {
      input = append(input, key);
    } else if (key == ENTER) {
      switch (stage) {
      case 0:
        //println(charToString(input));
        if (trim(charToString(input)).equalsIgnoreCase("yes")) {
          stage = 1;
        }
        break;
      case 2:
        if (trim(charToString(input)).equalsIgnoreCase("magenta")) {
          stage = 3;
        }
      }
      for (int q = input.length - 1; q >= 0; q --) {
        input = shorten(input);
      }
    }
  } else if (input.length > 0) {
    input = shorten(input);
  }
}

String charToString(char[] c) {
  if (c.length <= 0) {
    String voidResult = " ";
    return voidResult;
  } else {
    String result = str(c[0]);
    for (int q = 1; q < c.length; q ++) {
      result = result.concat(str(c[q]));
    }
    return result;
  }
}

void captureEvent(Capture c) {
  c.read();
}
class Type {
  int counter;
  int typeCount;
  int length;
  String content;
  String originalContent;
  int rectCount = 0;
  boolean drawRect = true;
  boolean trigger = false;

  Type(String s) {
    typeCount = 0;
    counter = 0;
    content = s;
    length = s.length();
    originalContent = s;
  }
  void type(float x, float y, float size, int period) {
    float xPos = x;
    float yPos = y;
    textSize(size);
    for (int q = 0; q <= counter; q ++) {
      char c = content.charAt(q);
      if (c == '\n' || c == '\r') {
        xPos = x;
        yPos += size + 1;
        continue;
      }
      if (xPos + size < width - size) {
        text(c, xPos, yPos);
        xPos += size;
      } else {
        if (c != ' ' && content.charAt(q-1) != ' ') {
          text('-', xPos, yPos);
        }
        xPos = x;
        yPos += size + 1;
        text(c, xPos, yPos);
        xPos += size;
      }
    }
    if (drawRect) {
      noStroke();
      rect(xPos + 1, yPos - size, size - 2, size);
    }
    typeCount = (typeCount + 1) % period;
    rectCount = (rectCount + 1) % 15;
    if (rectCount == 0) {
      drawRect = !drawRect;
    }
    if (typeCount == 0) {
      if (counter < length - 1) {
        if (content.charAt(counter) != ' ' && content.charAt(counter) 
          != '\r' && content.charAt(counter) != '\n') {
          out.pauseNotes();
          out.playNote(0, 0.05, "C4");
          out.resumeNotes();
        }
        counter ++;
      } else {
        trigger = true;
      }
    }
  }
}
PImage invert(PImage im) {
  PImage im2 = createImage(im.width, im.height, ARGB);
  im2.loadPixels();
  for (int q = 0; q < im.pixels.length; q ++) {
    float r = 255 - red(im.pixels[q]);
    float g = 255 - green(im.pixels[q]);
    float b = 255 - blue(im.pixels[q]);
    float a = alpha(im.pixels[q]);
    im2.pixels[q] = color(r, g, b, a);
  }
  im2.updatePixels();
  return im2;
}

char randomChar() {
  char[] chars = {'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 
    'G', 'h', 'H', 'i', 'I', 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'O', 
    'p', 'P', 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T', 'u', 'U', 'v', 'V', 'w', 'W', 'x', 
    'X', 'y', 'Y', 'z', 'Z', ' ', '?', '!', '.', '-', '#', '0', '1', '2', '3', '4', '5', 
    '6', '7', '8', '9'};
  int ind = int(random(0, chars.length));
  return chars[ind];
}

void colorChart(float x, float y) {
  pushMatrix();
  translate(x, y);
  stroke(0);
  fill(255);
  rect(0, 0, 300, 200);
  noStroke();

  fill(255, 0, 0, 128);
  ellipse(75, 50, 75, 75);
  fill(0, 255, 255, 128);
  ellipse(100, 50, 75, 75);

  fill(0, 0, 255, 128);
  ellipse(200, 50, 75, 75);
  fill(255, 255, 0, 128);
  ellipse(225, 50, 75, 75);

  fill(0, 255, 0, 128);
  ellipse(138, 150, 75, 75);
  fill(255, 0, 255, 128);
  ellipse(162, 150, 75, 75);
  popMatrix();
}

void reset() {
  testStage = 0;
  stage = 0;
  cardClue = 0;
  green = false;
  for (Type type : types) {
    type.counter = 0;
    type.typeCount = 0;
    type.trigger = false;
  }
}

void sadFace(float x, float y, float w, float h) {
  stroke(255, 0, 0);
  strokeWeight(5);
  pushMatrix();
  translate(x, y);
  scale(w/60, h/60);
  line(20, 0, 20, 20);
  line(40, 0, 40, 20);
  line(0, 40, 60, 40);
  line(0, 40, 0, 60);
  line(60, 40, 60, 60);
  
  popMatrix();
}
void serialEvent(Serial port) {
  println("SERIAL");
  if (port == morse) { // Morse and RFID communication
    String in = port.readString();
    if (in.length() == 3 && stage >= 3) {
      morseIn = append(morseIn, in.charAt(0));
      morseTime = 120;
    } else if (trim(in).equals("1441256961")) { //Fibonacci
      cardClue = 1;
      //println(yay);
    } else if (trim(in).equals("28321276")) { //Morse
      cardClue = 2;
      //println(yay);
    } else if (trim(in).equals("3442456957")) { //Card 3 (green)
      cardClue = 3;
      //println(yay); //
    } else if (trim(in).equals("621153299")) { //Card 4 (white)
      cardClue = 4;
      //println(yay);
    } else {
      cardClue = 5;
    }
  } else if (port == box) { //Box communication
    String in = trim(port.readString());
    print(in + " - ");
    print(pass1);
    if (in.equals("0000") || in.equals("4444")) {
      reset();
    }
    if (in.equals(pass1)) {
      port.write("blue");
      stage = 2;
    }
  }
}

(And now, I’m free)

Leave a Reply