Project Title: How well can you binary?

 

Basic setup + loading screen

Normal test_smol

Video showing a run through of the piece

GOOD result_smol

Video showing a run through of the piece fast enough to be judged as “good”

AND fail_smol

Video showing what happens if you try to press both buttons

Leah taking the “How well can you binary?” test

User experience

Super secret wiring contained in the podium: Arduino connected to buttons and the “AND” logic gate breadboard setup.

 

Simple narrative description:

There is a podium with two buttons on it in front of a projection. When the user presses a button the “test” begins, asking the user to choose between two different options. If the user tries to press both buttons at once a loud buzzer goes off and the projection flashes “AND is not an option.” Each time the user answers a question a ticking noise gets faster. After the last question the test/projection tells the user if they were “BAD” or “GOOD” based on how fast they were able to answer the questions.

Process Images:

Tiny test of the two buttons to arduino setup

Layout of various tasks mid-process

Early code testing the two button input before adding to main body of code

Figuring out how to add sound

Adding sound to the basic question setup

Testing the code before the buttons arrived using mouse+ keyboard inputs

Process Reflection: 

Surprisingly for me the easier aspect of the project was the technical parts. In the past I have struggled the most with the coding and the wiring of the piece but I think I did an okay job giving myself a project that was relatively approachable for someone with my level of experience. It was difficult enough coding-wise where I definitely learned something (I’ve never used Processing before) but not so difficult that I saw it as a major challenge.

I think the biggest hurdle that I had to tackle was conceptual: how do I make sure my piece is meaningful? Or maybe: how do I make sure what I imagined as being “good” about the project comes through? This, for me, was more of a design problem than anything else.  I wanted to make sure the piece had an element of absurdity while still making the message meaningful, and I didn’t know if there was any way to test whether or not I had crossed that line until I actually presented the thing. I think something akin to the 90% critique we are going to have for the next project would have helped me resolve this problem/these doubts before the final presentation. I think what was interesting to find out during the final critique was how people wanted to explore the piece more in terms of figuring out the different outcomes (ie rushing through the questions to get to the “you are…GOOD” outcome) as opposed to focusing on the meaning behind the questions themselves. I wonder if there is some element of the “game” that could have been changed to focus more thoroughly on the conceptual meaning behind the piece.

Elements such as messing with the question format and making the podium a binary in and of itself, suggestions I received during the critique from our guest critics, definitely might have improved this aspect of the “game.” In the end I learned that the design of the thing (the appearance of the interface, how it moved between questions, what the podium looked like) for me at least, ended up being the biggest hurdle, and something I needed more feedback on, than the technical problems I expected to struggle with more. In the future I need to focus more on getting the technical stuff out of the way earlier so that I can have people interact with the piece earlier on in order to incorporate design feedback to the functionality of the piece before the final critique.

Arduino Code:

/*
How well can you binary?
Kirman Hanson

- The code reads the input coming from the buttons and through the "AND" gate circuit (set to the 8,7, and 4 pins on the arduino)
and sends the information to the processing code as either a "0", "2", "3", or "4" depending on the input.

- code is based on the basic "digital button" sketch provided with the arduino

*/

// constants won't change. They're used here to set pin numbers:
const int leftButtonPin = 8;     // the number of the left pushbutton pin
const int rightButtonPin = 7;  // the number of the right pushbutton pin
const int andPin = 4;

// variables will change:
int leftButtonState = 0;         // variable for reading the left pushbutton status
int rightButtonState = 0;       // variable for reading the right pushbutton status
int andState = 0;


void setup() {
  // initialize the pushbuttons + AND gate pin as inputs:
  pinMode(leftButtonPin, INPUT);
  pinMode(rightButtonPin, INPUT);
  pinMode (andPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  // read the state of the pushbutton value:
  leftButtonState = digitalRead(leftButtonPin);
  rightButtonState = digitalRead(rightButtonPin);
  andState = digitalRead(andPin);

  if (andState == HIGH) {           // if the and gate is activated...
    Serial.write(3);                //send a 3 to Processing
    Serial.write(0);
    //delay (500);
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  }
  else if (leftButtonState == HIGH) { //send a 4 to processing if the left button is pressed
    delay(100);                       // delays help prevent the code from sending out "double presses"
    Serial.write(4);
    Serial.write(0);
    //Serial.print("left");           // these are commented out but used them to test the button input
    //Serial.print("off");
    delay(500);   
  } 
  else if (rightButtonState == HIGH) { // send a 2 to processing if the right button is pressed
    delay(100);
    Serial.write(2);
    Serial.write(0);
    //Serial.print("right");
   // Serial.print("off");
   delay (500);
    }
  else {
    Serial.write(0);                  // if nothing is happening send 0 to Processing
  }
   delay(50);                            // Wait 50 milliseconds

Processing Code:

/*
How well can you binary?
Kirman Hanson
Code draws up the interface for the game/test of the piece and 
it changes the interface in response to the button presses as inputs being
read by the arduino code.

Basic structure for code is based off the basic "serial read" example
that comes with Processing

Zach + classmates helped with troubleshooting, Erin with the design elements
*/
import processing.serial.*;
import processing.sound.*;
Serial myPort;  // Create object from Serial class
int buttonVal;      // Data received from the serial port
PFont f, qFont, andFont, startFont;
StringList qInventory, firstAInventory, secondAInventory;
int qCount = 0;
boolean andTrigger = false;  // this bool is used to trigger the "AND" state (ie the buzzer)
boolean leftHighlight = false;
boolean rightHighlight = false;
boolean buttonPressed = false;
boolean flickerLoad = false;
int warningStart = 100000;
SoundFile ticker, endBeep, endBeep2, wrongNoise;
float tickerRate = 2.0;
String tickerFile = "tick2.0.wav";
float amp = 0;
float questionStart;
float timeToAnswer;
float totalTime;
boolean endStart = false;
float endTime;

void setup() {
  // draws the basic interface
  size(1400,900);
  f = createFont("KohinoorDevanagari-Bold", 40);
  qFont = createFont("KohinoorDevanagari-Regular", 54);
  andFont = createFont("KohinoorDevanagari-Bold", 90);
  startFont = createFont("KohinoorDevanagari-Regular", 30);
  // all "inventories" are string lists containing the questions and/or answers. Change as you wish.
  qInventory = new StringList("The lights are...", "It is...", "I am...", "I am...","The sky is...", "I am a student", "I am in a ___ mood", "I am...", "I am only good at...", "I am a...", "I ___ therefore I am", "I am good at making decisions", "I am...", "Carngie Mellon is...", "I am a...", "I am...", "I am...", "I am...", "I am...", "I am...");
  firstAInventory = new StringList("on", "cold", "inside", "left-handed", "up", "yes", "good", "being", "art", "good person","think", "yes", "strong", "ethical", "success", "lucky", "not fun", "spiritual", "natural", "on");
  println(firstAInventory.size()); // helps to diagnose whether you have enough answers for your questions
  secondAInventory = new StringList("off", "hot", "outside", "right-handed", "down", "no", "bad", "becoming", "science", "bad person", "feel", "no", "weak", "unethical", "failure", "hard-working", "fun", "rational", "unnatural", "off");
  ticker = new SoundFile(this, tickerFile); 
  ticker.loop(1,amp); // initializes the "ticking" noise
  println(qInventory.size()); 
  println(secondAInventory.size());
  // button input
  String portName = Serial.list()[4];
  myPort = new Serial(this, portName, 9600);
}
void draw() {
  background(255);
  fill(0);
  textAlign(CENTER);
  
  if ( myPort.available() > 0) {  // If data is available,
    buttonVal = myPort.read();         // read it and store it in val
  }
 
 if (buttonPressed == false){ // tests whether or not the button has been pressed
     background(255);
     amp = 0; // if not ticker is silent
  if (buttonVal == 4 || buttonVal == 2){ //gets the interface out of "start" mode
    buttonPressed = true;
    println("button pressed now true");
    amp = 0.05; // ticker is now able to be heard
    }
  else if (second()%2 == 0){ // sets up the "start mode", uses modulus to "blink" the text
    fill(0);
    textFont(startFont);
    text("How well can you binary?", width/2, height*0.333);
    // every 2 seconds flip the bool in order to create "flicker" effect
    if (flickerLoad == false){ 
      //println("flipped to true");
      delay(10);
      flickerLoad = true;
      delay(10);
      }
    else if(flickerLoad==true){
    flickerLoad = false;
    }
   }
    else if(flickerLoad == true){
    fill(0);
    textFont(qFont);
    text("PRESS ANY BUTTON TO START", width/2, height/2);
  }
} 

  else if (buttonVal == 3) { // if the arduino sends out a 3,triggers the "AND" state
    println("and triggered");
    fill(255);
    warningStart = millis();
    if (millis() - warningStart < 1200){ //only displays for 1.2 seconds
      andTrigger = true;
    //play dramatic tone here
      }
    else {
      andTrigger = false; // automatically ends after 1.2 seconds
    }
  }
    
else if ((buttonVal == 4 || buttonVal== 2)&& buttonVal!=3 && endStart == false) {
    //moves onto next question + triggers end state if we are at the end of the list of questions
    delay(100);
    qCount +=1; // the q count counts the number of questions answered
    andTrigger = false;
    println("tickerRate", tickerRate);
    if (qCount < qInventory.size()) {
      tickerRateIncrease(buttonVal); //increases the speed of the ticker everytime question is answered
      }
    else { // triggers the "end game" function once at end of the questions
       endTime = millis();
       ticker.stop();
       endBeep = new SoundFile(this, "endbeep.mp3");
       endBeep2 = new SoundFile(this, "endbeep_extra.wav");
       endBeep.playFor(2.0);
       endStart = true;
       println("endStart set to true");
      }
  }
 
  else if (qCount < qInventory.size()) { //displays the different questions so long as there are questions left
    background(255);
    textFont(qFont);
    text(qInventory.get(qCount), width* 0.5, height*0.333);
    textFont(f);
    //set up highlights when button pressed
    if (leftHighlight==true && millis()- questionStart < 300 && andTrigger==false){
      println("left Highlight", leftHighlight);
      rectMode(CENTER);
      fill(0);
      rect(width*0.333, height*0.666, 200, 80);
      fill(255);
      text(firstAInventory.get(qCount), width*0.333, height*0.666);//retrieves the correstpodning answer from the list
      println(qCount);
      }
    else if (rightHighlight==true && millis()- questionStart < 300 && andTrigger==false){
      println("right highlight", rightHighlight);
      rectMode(CENTER);
      fill(0);
      rect(width*0.666, height*0.666, 200, 80);
      fill(255);
      text(secondAInventory.get(qCount), width*0.666, height*0.666);//retrieves the correstpodning answer from the list
      println(qCount);
      } 
     else{
       // "normal" question display
       fill(0);
       text(secondAInventory.get(qCount), width*0.666, height*0.666);
       text(firstAInventory.get(qCount), width*0.333, height*0.666);
       //if neither is picked don't highlight it
       rightHighlight = false; 
       leftHighlight = false;
     }
    }
  // this function sets up the "AND" state
  if (millis() - warningStart < 1200 && andTrigger==true){
        wrongNoise = new SoundFile(this, "wrong.wav");
        wrongNoise.play();
        delay(90);
        fill(255,0,0);
        background(255);
        textFont(andFont);
        text("AND is not an option", width/2, height/2);
      }  
  // this sequence is the end state
  if (endStart == true){
    println("end state");
    ticker.stop();

    if (endStart==true && millis()-endTime < 2500){
      println("end game displayed");
      textFont(andFont);
      text("END GAME", width/2, height/2);
      println("endTime", endTime);
      println("endStart", endStart);
      println("millis-endTime", millis()-endTime);
      println("millis", millis());
    }
    if (millis()-endTime < 8000 && millis()-endTime >= 2500){
      println("calculating score displayed");
      textFont(qFont);
      text("Calculating results...", width/2, height/2);
    }
    if (endStart==true && millis()-endTime < 10000 && millis()-endTime >= 8000){
      println("you are...");
      textFont(qFont);
      text("You are...", width/2, height/2);
    }
    if (endStart==true && millis()-endTime < 12000 && millis()-endTime >= 10000 && totalTime <= 30000){
      textFont(andFont);
      background(0,255,0);
      fill(255);
      text("GOOD", width/2, height/2);
    }
    if (endStart==true && millis()-endTime < 12000 && millis()-endTime >= 10000 && totalTime > 30000){
      textFont(andFont);
      background(255,0,0);
      text("BAD", width/2, height/2);
    }
    if(endStart == true && millis()-endTime >= 14000){
      println("went to no loop");
      println(endTime);
      text("", width/2, height/2);
      fill(0);
      noLoop();
    }
  }
 }
void tickerRateIncrease(int buttonVal) { //this function controls the ticker rate
      println("click");
     if (buttonVal == 4){
       leftHighlight = true;
     }
     if (buttonVal== 2){
       rightHighlight = true;
     }
     //increase rate + loudness
     tickerRate -= 0.1;
     amp += 0.05;
     // endstate calculations
     timeToAnswer = millis() - questionStart;
     totalTime += timeToAnswer;
     questionStart = millis();
     //changing rates
     String rateString = nf(tickerRate, 1, 1);
     println("new ticker rate", tickerRate);
     String[] tickerParts = new String[3]; 
        tickerParts[0] = "tick"; 
        tickerParts[1] = rateString; 
        tickerParts[2] = ".wav"; 
     String tickerFile = join(tickerParts, ""); //sets up new ticker file name to be retrieved
    ticker.stop();
    ticker = new SoundFile(this, tickerFile);
    ticker.cue(0.3);
    ticker.loop(1,amp);//plays new, faster, ticker file
}