Learning Morse Code Through A Quiz

For this week project I took inspiration from my one of my previous weekly assignments where I made a device where a user could record a Morse code message and could play it back.

One issue with that project is that a user must know Morse code first. I personally don’t know Morse code but I find the idea to be pretty cool.

For my assignment this week I made a setup where you could interact with processing via the buttons on the breadboard to input a dashes and dot and you could press enter to check if your input was correct.

The user would press the blue button to input a dot and the yellow button to input a dash. The corresponding would be displayed on the processing window. Once the user is satisfied with the input they can press the red button to check if the input is correct. If the input is correct a green light would flash on the breadboard, if not a red light would flash. Once the enter button is pressed a new letter is displayed and the input is cleared.

 

Circuit Diagram

 

import processing.serial.*;

Serial port;

int[][] morseCode = {
  {1, 2}, //a
  {2, 1, 1, 1}, //b
  {2, 1, 2, 1}, //c
  {2, 1, 1}, //d
  {1}, //e
  {1, 1, 2, 1}, //f
  {2, 2, 1}, //g
  {1, 1, 1, 1}, //h
  {1, 1}, //i
  {1, 2, 2, 2}, //j
  {2, 1, 2}, //k
  {1, 2, 1, 1}, //l
  {2, 2}, //m
  {2, 1}, //n
  {2, 2, 2}, //o
  {1, 2, 2, 1}, //p
  {2, 2, 1, 2}, //q
  {1, 2, 1}, //r
  {1, 1, 1}, //s
  {2}, //t
  {1, 1, 2}, //u
  {1, 1, 1, 2}, //v
  {1, 2, 2}, //w
  {2, 1, 1, 2}, //x
  {2, 1, 2, 2}, //y
  {2, 2, 1, 1} //z
};


int currentAlphabet;
ArrayList<Integer> input = new ArrayList<Integer>();
int recInput = -1;
String inputStr = "";
/*
the ascii for uppercase alphahets range from 65[A] to 90[Z]
 */

void setup() {
  size(600, 600);
  //println(morseCode.length);
  generateNewLetter();
  //printArray(Serial.list());
  String portname = Serial.list()[0];
  port = new Serial(this, portname, 9600);
  println(portname);
}

void draw() {
  background(167);
  displayLetter();
  displayInput();
}

void generateNewLetter() {
  currentAlphabet = floor(random(26));
}

void displayLetter() {
  // (char)(currentAlphabet+65) -> this will give the letter based on current alphabet index
  pushStyle();
  fill(0);
  textAlign(CENTER);
  textSize(200);
  text((char)(currentAlphabet+65), width/2, height/2);
  popStyle();
}

void displayInput() {
  pushStyle();
  fill(0);
  textAlign(CENTER);
  textSize(72);
  text(inputStr, width/2, height/2+200);
  popStyle();
}

void serialEvent(Serial port) {
  recInput = port.read();
  if (recInput == 1) {
    input.add(recInput);
    inputStr+=" *";
  } else if (recInput==2) {
    input.add(recInput);
    inputStr+=" -";
  } else if (recInput == 3)
  {
    if (checkCorrect()) {
      port.write(101);
    } else if (!checkCorrect()) {
      port.write(100);
    }
    inputStr = "";
    input.clear();
    generateNewLetter();
    println("enter was pressed");
  }
}

boolean checkCorrect() {
  boolean correct = true;
  if (morseCode[currentAlphabet].length == input.size()) {
    for (int i=0; i<morseCode[currentAlphabet].length; i++) {
      if (morseCode[currentAlphabet][i] != input.get(i)) {
        correct = false;
        break;
      }
    }
  } else {
    correct = false;
  }
  println(correct);
  return correct;
}
int led1 = 3;
int led2 = 2;
int enter = 8;
int dot = 9;
int dash = 10;
int buttonDelay = 400;
int wrong = 7;
int correct = 6;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(led1,OUTPUT);
  pinMode(led2,OUTPUT);
  pinMode(enter,INPUT);
  pinMode(dot,INPUT);
  pinMode(dash,INPUT);
  pinMode(wrong,OUTPUT);
  pinMode(correct,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(dot)==1){
    // send a 1 to processing
    Serial.write(1);
    digitalWrite(led1,HIGH);
    delay(buttonDelay);
    digitalWrite(led1,LOW);
  }
  
  else if(digitalRead(dash)==1){
    // send a 2 to processing
    Serial.write(2);
    digitalWrite(led1,HIGH);
    digitalWrite(led2,HIGH);
    delay(buttonDelay);
    digitalWrite(led1,LOW);
    digitalWrite(led2,LOW);
  }
  
  else if(digitalRead(enter)==1){
    Serial.write(3);
    delay(buttonDelay);
  }

  if (Serial.available()>0){
    int data = Serial.read();
    if (data == 100){
      digitalWrite(wrong,HIGH);
      delay(100);
      digitalWrite(wrong,LOW);
    } else if(data == 101){
      digitalWrite(correct,HIGH);
      delay(100);
      digitalWrite(correct,LOW);
    }
  }
}

/* 
 *  1 for dot 
 *  2 for dash
 *  3 for enter
 */

Final Project Proposal – Aayush & Suzan

Idea:

To create an interactive Dollhouse. 

 

Implementation: 

Every room in the dollhouse will have a variety of either physical interactions (lights, sounds), virtual tasks (that will be displayed on the computer), or a mixture of both. The goal of the game is to be able to interact with the dollhouse, but also to finish all the tasks set in place. The user will be able to complete the tasks on processing and this will be reflected on the dollhouse. We would also like to integrate a display on the dollhouse to display the progress as well display a message when the game is won.

 

Timeline:

Week 1:

  1. Build dollhouse
  2. Structure- have the tasks decided
  3. Arduino and processing stuff

 

Week 2:

  1. Tasks design (processing)
  2. Physical things are in the dollhouse
  3. Have the tasks done

 

Week 3:

  1. Connecting things
  2. User experimentation
  3. Fine tuning

 

Obstacles:

Finding a dollhouse

LDT – Light Dependent Theremin

When I was thinking about what to make for this week’s assignment I was came across a clip from The Big Bang Theory where Sheldon was playing the Theremin.

I theremin is the musical instrument that makes sound based on how electromagnetic fields produced by two antennae are altered by the hand movements between the two.

To mimic this I initially tried to use a Ultrasonic sensor to alter the sound. While this worked it only altered the sound based on the distance of the object[hand] from the sensor, the sound was altered based on only one direction.

I then used a LDR to do the same thing. This allowed me to change the sound by moving a light source around the LDR. This allowed me control the sounds by movement of the light source both horizontally and vertically.

I also added a button that multiplies the value of the photoresistor by 2 when pushed once and then the function gets disabled when pushed again. This yields a siren like effect when the button is repeatedly pushed.

int ldrPin = A0;
int playButton = 7;

bool multiplyFrequency = false;
int prevButtonState = LOW;

void setup() {
  Serial.begin(9600);
  pinMode(ldrPin, INPUT);
  pinMode(playButton, INPUT);
}

void loop() {
  changeState();
  Serial.println(multiplyFrequency);
  //  int ultSonData = getUltraSonicData();
  int ldrData = getLDRData();
  //  int transformed = transformData(related);
  if (multiplyFrequency) {
    tone(4, ldrData * 1.5);
  } else {
    tone(4, ldrData);
  }

}

float getLDRData() {
  return floor(analogRead(ldrPin));
}

float changeState() {
  //  Serial.println(digitalRead(playButton));
  if (prevButtonState == LOW && digitalRead(playButton) == HIGH) {
    multiplyFrequency = !multiplyFrequency;
  }
  prevButtonState = digitalRead(playButton);
}

LDT

 

Parking Sensor

For this week project I took inspiration from the problem that a lot of people face while parking. This being that it can be really difficult to park close to a wall especially for new drivers. Newer cars are often fitted parking sensors which makes beeping sounds to alert the drivers about there distance from an object. Older cars however do not have this feature so it can often be a challenge to park cars especially for newer drivers.

For my adaptation of the parking sensor I used an ultrasonic sensor to the determine the distance of the sensor to an object in front of it. Then using the equation of a line I determine the rate at which the led should blink. The led will blink with an interval of 800ms if the object is more than 25cm away or it will blink with an interval of 100ms if the object is less than 5cm away. The interval between 5cm and 25cm will be calculated using the equation of the line given below:

interval = 35*distance -75

Parking Sensor Planning Document

A button can be used to put the device in parking mode. When the device goes into parking mode the ultrasonic sensor is activated and sound waves are emitted. The time taken for these sound waves to come back determines the distance. The distance is then used to calculate the interval.

 

 

// echo produces a pulse when reflected signal is received
// the reflected signal is the one that is sent by the trig pin
int trigPin = 10;
int echoPin = 9;
int statusLedPin = 2;
int prevState = LOW;
int button = 4;
int warningPin = 5;
float distance = 10;
bool parking = false;
int delayMS = 0;
int interval = 500;
unsigned long prevTime = 0;
int warningState = LOW;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(statusLedPin, OUTPUT);
  pinMode(button, INPUT);
  pinMode(warningPin, OUTPUT);

}

void loop() {
  changeState();
  parkingState();
  if (parking) {
    distance = getDistance();
    calculateDelay();
    blinkLed();
    //    Serial.println(delayMS);
  }
  if (!parking && warningState == HIGH) {
    warningState = LOW;
    digitalWrite(warningPin, warningState);
  }
}

float getDistance() {
  digitalWrite(trigPin, LOW); // no signal is sent
  delayMicroseconds(2);

  digitalWrite(trigPin, HIGH); // after 2ms a signal is sent
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW); // signal is not sent after 10 ms

  // read the time taken for the pulse to return
  float duration = pulseIn(echoPin, HIGH);

  // calculate the distance
  return duration * 0.034 / 2;
}

void changeState() {
  if (digitalRead(button) == HIGH && prevState == LOW) {
    //    if (parking) {
    //      parking = false;
    //    } else if (!parking) {
    //      parking = true;
    //    }

    //refactor
    parking = !parking;
  }
  prevState = digitalRead(button);
}

void parkingState() {
  if (parking) {
    digitalWrite(statusLedPin, HIGH);
    //    digitalWrite(warningPin, LOW);
  } else if (!parking) {
    digitalWrite(statusLedPin, LOW);
    //    digitalWrite(warningPin, HIGH);
  }
}

void calculateDelay() {
  if (distance >= 5 && distance <= 25) {
    delayMS = (int) 35 * distance - 75;
  } else if (distance < 5) {
    delayMS = 100;
  } else if (distance > 25) {
    delayMS = 800;
  }
}

void blinkLed() {
  Serial.println("calling");
  unsigned long currTime = millis();
  if (currTime - prevTime >= delayMS) {
    prevTime = currTime;
    if (warningState == LOW) {
      warningState = HIGH;
    } else {
      warningState = LOW;
    }
    digitalWrite(warningPin, warningState);
  }
}

Circuit Diagram

Morse Code

For my project this week, I decided to make a communication system using a series of LEDs and buttons and the ability for you to record your own message in

wait for it

….

MORSE CODE

and then play it back as many times as you’d like.

When the Arduino first starts up, the Arduino will flash SOS denoted by:

…—…

and then will wait for actions.

You can record your own message by pressing the blue button. When red led lights up it means that it will record a message when you push buttons. When you push the red button it will flash two green leds and will record a dash, when you push the yellow button it will flash one green led and will record a dot.

You can stop the recording by pushing the blue button, the red led will turn off.

You can play back the message that you just recorded pushing the green button. This will turn on the blue led indicating that you are now in playback mode and will flash the message you just recorded.

You can push the green button as many times as you want to playback the record message.

// use static array to store the recorded codes
int message[500];
int messageSize = 0;
int sos[9] = {0, 0, 0, 1, 1, 1, 0, 0, 0};
int playSos = true;
//pins
int dashPin = 12;
int dotPin = 11;
int recordStopPin = 10;
int playPin = 9;

//one led is dot
//two leds are dash
int led1Pin = 3;
int led2Pin = 2;
int recordPin = 4;
int playingLedPin = 5;

//flags
bool record = false;
bool isPlaying = false;


void setup() {
  Serial.begin(9600);
  pinMode(dashPin, INPUT);
  pinMode(dotPin, INPUT);
  pinMode(recordStopPin, INPUT);
  pinMode(playPin, INPUT);
  pinMode(led1Pin, OUTPUT);
  pinMode(led2Pin, OUTPUT);
  pinMode(recordPin, OUTPUT);
  pinMode(playingLedPin, OUTPUT);
//  play(sos, 9);/
}

void loop() {
  readPin();
  if (record) {
    digitalWrite(recordPin, HIGH);
  } else {
    digitalWrite(recordPin, LOW);
  }
  if (isPlaying) {
    digitalWrite(playingLedPin, HIGH);
    play(message, messageSize);
  } else {
    digitalWrite(playingLedPin, LOW);
  }

  if (playSos) {
    play(sos, 9);
    playSos = false;
  }
}

// register a dash
void registerDash() {
  addDigit(1);
}

// register a dot
void registerDot() {
  addDigit(0);
}

// add the digit to the array
void addDigit(int add) {
  message[messageSize] = add;
  Serial.println(message[messageSize]);
  messageSize++;
}

//
void readPin() {
  if (digitalRead(dashPin) == HIGH && !isPlaying) {
    if (record) {
      registerDash();
    }
    digitalWrite(led1Pin, HIGH);
    digitalWrite(led2Pin, HIGH);
    delay(500);
    digitalWrite(led1Pin, LOW);
    digitalWrite(led2Pin, LOW);
  }
  if (digitalRead(dotPin) == HIGH && !isPlaying) {
    if (record) {
      registerDot();
    }
    digitalWrite(led1Pin, HIGH);
    delay(500);
    digitalWrite(led1Pin, LOW);
  }

  if (digitalRead(recordStopPin) == HIGH && !isPlaying) { //set recording state
    Serial.println("record/stop");
    record = !record;
    delay(500);
  }

  if (digitalRead(playPin) == HIGH && !record) {
    Serial.println("play");
    isPlaying = !isPlaying;
    delay(500);
  }
}

int play(int arr[], int arrSize) {
  for (int i = 0; i < arrSize; i++) {
    if (arr[i] == 1) {
      digitalWrite(led1Pin, HIGH);
      digitalWrite(led2Pin, HIGH);
      delay(500);
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
    }
    if (arr[i] == 0) {
      digitalWrite(led1Pin, HIGH);
      delay(500);
      digitalWrite(led1Pin, LOW);
    }
    delay(500);
  }
  isPlaying = false;
  return 0;
}

//notes
// -1 is invalid
// 0 is a dot
// 1 is a dash
// first button is for registering a dash
// second button is for registering a dot
// third button is to record
// forth button is to play the saved recording

Circuit Diagram

Fight The Pandemic

From my last about the midterm until now, time for submission I had to change a few things. The biggest change was how the game would operate. Initially the plan was to have the shooter in the middle of the screen and have a pointer that would change location based on the location of the mouse in the window, however I changed this to have the shooter moving from side to side as a not to have the user/player switch between the mouse and the keyboard for now the player can play the entirely from the keyboard.

Objective of the game

Try to get as many points as possible while keeping the number of cases as low as possible within 2 minutes/

Game Operation

The keys used for the operation of the game are:

1,2,3,m, space bar and the left and right arrow keys.

The space bar will shoot the fighting tool that is currently selected, this can seen in the shooter icon. Keys 1,2 and 3 can be used to switch between the fighting tools when you’re in “fight” mode. Keys 1,2 and 3 can be used to buy more fighting tools when you are in buy mode. You can switch modes by pressing the m button.

The difference between the fighting tool is number of points you get when you shoot the virus down and the speed of the fighting tool.

Speed of Handwash < Speed of face mask < Speed of face shield.

Shooting the virus down with a handwash will get you 1 points, shooting it down with facemask will get you 3 points and the shield will get you 5 points.

You can use the points to buy more tools. Buying more handwash will cost 1 point, face masks cost 2 points/mask, and face shields cost 3 points/shield.

The number of cases will go up if the virus goes below the window.

 

import processing.sound.*;

//create new game
Game game;

// arrayList to store corona virus images
ArrayList <CoronaVirus> coronaList;
ArrayList <Fighter> activeFighters;

//sound files
SoundFile error;
SoundFile scaryBg;
SoundFile collision;
SoundFile newCase;

//image
PImage virus;

// misc vars
String errorMessage = "";

void setup() {
  size(1280, 720);
  game = new Game(); //init game
  coronaList = new ArrayList<CoronaVirus>(0);
  activeFighters = new ArrayList<Fighter>(0);
  for (int i=0; i<4; i++) {
    coronaList.add(new CoronaVirus());
  }
  virus = loadImage("virus.png");
  error = new SoundFile(this, "error.mp3");
  scaryBg = new SoundFile(this, "scaryBg.mp3");
  collision = new SoundFile(this, "collide.mp3");
  newCase = new SoundFile(this, "dead.mp3");
}

void draw() {
  if (game.state==-2) {
    startScreen();
  }
  else if (game.state==0 || game.state==1) {
    background(211, 211, 211); // clear background to avoid trails
    game.drawGameStats(); // show the game statistics
    game.shooter(); // draw the shooter
    displayError(); //display error messages
    displayCost(); // display cost of buying
    playBGMusic(); // play background music
    updateCorona(); // update the position and display the virus
    moveFighters(); //move the fighting tools on the screen
    checkCollisions(); //check for collision
    checkCoronaPosition(); // check for off screen viruses
    checkFighterPosition(); // check for off screen fighting tool
    newViruses(); // generate new viruses
    game.moveShooter(); // move the shooter
    game.updateTime(); // countdown time
  }
  else if (game.state==-1) {
    gameOver();
  }
}
import processing.sound.*;

//create new game
Game game;

// arrayList to store corona virus images
ArrayList <CoronaVirus> coronaList;
ArrayList <Fighter> activeFighters;

//sound files
SoundFile error;
SoundFile scaryBg;
SoundFile collision;
SoundFile newCase;

//image
PImage virus;

// misc vars
String errorMessage = "";

void setup() {
  size(1280, 720);
  game = new Game(); //init game
  coronaList = new ArrayList<CoronaVirus>(0);
  activeFighters = new ArrayList<Fighter>(0);
  for (int i=0; i<4; i++) {
    coronaList.add(new CoronaVirus());
  }
  virus = loadImage("virus.png");
  error = new SoundFile(this, "error.mp3");
  scaryBg = new SoundFile(this, "scaryBg.mp3");
  collision = new SoundFile(this, "collide.mp3");
  newCase = new SoundFile(this, "dead.mp3");
}

void draw() {
  if (game.state==-2) {
    startScreen();
  }
  else if (game.state==0 || game.state==1) {
    background(211, 211, 211); // clear background to avoid trails
    game.drawGameStats(); // show the game statistics
    game.shooter(); // draw the shooter
    displayError(); //display error messages
    displayCost(); // display cost of buying
    playBGMusic(); // play background music
    updateCorona(); // update the position and display the virus
    moveFighters(); //move the fighting tools on the screen
    checkCollisions(); //check for collision
    checkCoronaPosition(); // check for off screen viruses
    checkFighterPosition(); // check for off screen fighting tool
    newViruses(); // generate new viruses
    game.moveShooter(); // move the shooter
    game.updateTime(); // countdown time
  }
  else if (game.state==-1) {
    gameOver();
  }
}
class Fighter {
  int type = -1; // 0 is handwash, 1 is mask, 2 is shield
  int speed = -1;
  int positionX = -1;
  int positionY = -1;
  PImage img;

  //methods
  //update position
  void updatePosition() {
    positionY -= speed;
    showFighter();
  }
  void fighterImage() {
    //println(type);
    switch(type) {
    case 0: 
      { // handwash
        img = loadImage("handwash.png");
        speed = 3;
        break;
      }
    case 1:
      { // facemask
        img = loadImage("mask.png");
        speed = 5;
        break;
      }
    case 2:
      { // faceshield
        img = loadImage("shield.png");
        speed = 7;
        break;
      }
    }
  }

  void showFighter() {
    image(img, positionX, positionY, 30, 30);
  }
}
class Game {
  // attributes
  int points = 0;
  int cases = 0;
  int state = -2; // 0->shooting | 1-> buying | -1 -> gameOver | -2-> game not started
  int fightingTool = 0; // 0-handwash, 1-mask, 2-shield
  int time = 120;
  PImage maskImg = loadImage("mask.png");
  PImage handwashImg = loadImage("handwash.png");
  PImage shieldImg = loadImage("shield.png");
  int timeDisplay = 0;
  int shooterPosition = width/2;
  int shooterDirection = 0;
  float shooterSpeed = 2;
  
  // fighting tools
  // handwash attr
  int handwash = 20;
  
  // facemask attr
  int masks = 14;
  
  // faceshield attr
  int shields = 6;
  
  

  //methods
  void incrementPoints(int type) {
    if (type == 0) {
      points += 1;
    } else if (type == 1) {
      points += 3;
    } else if (type == 2) {
      points += 5;
    }
  }
  
  void incrementCases() {
    cases+=1;
  }

  void incrementMasks() {
    masks+=1;
  }

  void decrementMasks() {
    masks-=1;
  }

  void incrementShields() {
    shields+=1;
  }

  void decrementShields() {
    shields-=1;
  }

  void incrementHandwash() {
    handwash+=1;
  }

  void decrementHandwash() {
    handwash-=1;
  }
  
  void decrementFighters(){
    switch(fightingTool){
      case 0:{
        decrementHandwash();
        break;
      }
      case 1:{
        decrementMasks();
        break;
      }
      case 2:{
        decrementShields();
        break;
      }
    }
  }

  void changeState() {
    //println("changing state");
    if (state==0) {
      state=1;
    } else if (state==1) {
      state=0;
    }
  }
  void updateTime() {
    if (time==0) {
      state=-1;
    }
    if (frameCount%60==0 && state!=-1) {
      time-=1;
      if (timeDisplay==0) {
        timeDisplay = 1;
      } else if (timeDisplay==1) {
        timeDisplay=0;
      }
    }
    if (points==0 && handwash==0 && masks==0 && shields==0){
      state=-1;
    }
  }

  void drawGameStats() {
    textSize(12);
    color(0, 0, 0);
    imageMode(CENTER);
    
    pushStyle();
    //draw handwash
    image(handwashImg, 70, 30, 30, 30); //150,30,30,30
    text(handwash+" x", 25, 30);//110,30

    // draw mask
    image(maskImg, 150, 30, 30, 30);
    text(masks+" x", 110, 30);

    // draw faceshield
    image(shieldImg, 230, 30, 30, 30);
    text(shields+" x", 190, 30);
    popStyle();
    
    //display time
    pushStyle();
    textSize(30);
    if (timeDisplay==1) {
      fill(0, 0, 0);
      text(time, width-100, height-30);
    } else if (timeDisplay==0) {
      fill(255, 255, 0);
      text(time, width-100, height-30);
    }
    popStyle();

    // game mode
    pushStyle();
    int rectWidth = 100;
    int rectHeight = 30;
    int cornerRadius = 10;
    noFill();
    rect(width/2-rectWidth/2, 20, rectWidth, rectHeight, cornerRadius, cornerRadius, cornerRadius, cornerRadius);
    if (state==0) {
      pushStyle();
      textAlign(CENTER);
      textSize(25);
      fill(255, 255, 0);
      text("FIGHT", width/2, 45);
      popStyle();
    } else if (state==1) { //display buy
      pushStyle();
      textAlign(CENTER);
      textSize(25);
      fill(0, 255, 0);
      text("BUY", width/2, 45);
      popStyle();
    } else if (state==-1) { //display gameover
      pushStyle();
      textAlign(CENTER);
      textSize(18);
      fill(255, 0, 0);
      text("Game Over", width/2, 43);
      popStyle();
    }

    popStyle();

    //display points
    pushStyle();
    fill(0, 0, 0);
    textSize(25);
    text(points+" points", width-300, 45);
    text(cases+" cases", width-150, 45);
    popStyle();
  }
  void drawFightingTool(int x, int y, int imgWidth, int imgHeight) {
    pushStyle();
    imageMode(CENTER);
    if (fightingTool==0) { // draw handwash
      image(handwashImg, x, y, imgWidth, imgHeight);
    } else if (fightingTool == 1) { //draw mask
      image(maskImg, x, y, imgWidth, imgHeight);
    } else if (fightingTool == 2) { //draw shield
      image(shieldImg, x, y, imgWidth, imgHeight);
    }
    popStyle();
  }

  void changeFightingTool(int tool) {
    fightingTool = tool;
    //println(fightingTool);
  }

  void shooter() {
    pushStyle();
    fill(255, 255, 255);
    circle(shooterPosition, height, 100);
    game.drawFightingTool(shooterPosition, height-20, 40, 40);
    popStyle();
  }

  void moveShooter() {
    if (shooterSpeed<=2) {
      shooterDirection=0;
      shooterSpeed=2.1;
    }
    if (shooterSpeed>2) {
      shooterPosition += shooterDirection*shooterSpeed;
    }
  }
}
// to interact with game
void keyPressed() {
  //println(keyCode);
  switch(keyCode) {
  case 32: 
    { // space bar pressed need to create a new fighter add to list and reduce the number from game class
      if (game.fightingTool==0 && game.handwash>0) {//check number of handwash
        Fighter tempFighter = new Fighter();
        tempFighter.type = game.fightingTool;
        tempFighter.positionX = game.shooterPosition;
        tempFighter.positionY = height-30;
        tempFighter.fighterImage();
        activeFighters.add(tempFighter);
        game.decrementFighters();
      } else if (game.fightingTool==1 && game.masks>0) {//check number of masks
        Fighter tempFighter = new Fighter();
        tempFighter.type = game.fightingTool;
        tempFighter.positionX = game.shooterPosition;
        tempFighter.positionY = height-30;
        tempFighter.fighterImage();
        activeFighters.add(tempFighter);
        game.decrementFighters();
      } else if (game.fightingTool==2 && game.shields>0) {//check number of shields
        Fighter tempFighter = new Fighter();
        tempFighter.type = game.fightingTool;
        tempFighter.positionX = game.shooterPosition;
        tempFighter.positionY = height-30;
        tempFighter.fighterImage();
        activeFighters.add(tempFighter);
        game.decrementFighters();
      }
      break;
    }
  case 37:
    { //move left
      game.shooterDirection = -1;
      if (game.shooterSpeed<10) {
        game.shooterSpeed*=1.1;
      }
      break;
    }
  case 39:
    { //move right
      game.shooterDirection = 1;
      if (game.shooterSpeed<10) {
        game.shooterSpeed*=1.1;
      }
      break;
    }
  case 49:
    { //handwash
      if (game.state==0) {
        game.changeFightingTool(0);
      } else if (game.state==1) { //buy more handwash
        if (game.points>=1) { //check if you have enough points
          game.points-=1;
          game.handwash+=1;
        } else {
          triggerErrorSound();
          errorMessage = "Not Enough Points";
        }
      }
      break;
    }
  case 50:
    { //facemask
      if (game.state==0) {
        game.changeFightingTool(1);
      } else if (game.state==1) { //buy more masks
        if (game.points>=2) { //check if you have enough points
          game.points-=2;
          game.masks+=1;
        } else {
          triggerErrorSound();
          errorMessage = "Not Enough Points";
        }
      }
      break;
    }
  case 51: 
    { //faceshield
      if (game.state==0) {
        game.changeFightingTool(2);
      } else if (game.state==1) { //buy more handwash
        if (game.points>=3) { //check if you have enough points
          game.points-=3;
          game.shields+=1;
        } else {
          triggerErrorSound();
          errorMessage = "Not Enough Points";
        }
      }
      break;
    }
  case 77:
    {
      game.changeState();
      break;
    }
  default:
    {
      triggerErrorSound();
      errorMessage = "Invalid Control";
      break;
    }
  }
}

void keyReleased() {
  if (keyCode==37 || keyCode==39) {
    game.shooterSpeed = 0.8;
  }
}

void flashMessage(String msg, color c, int size, int hOffset) {
  pushStyle();
  fill(c);
  textSize(size);
  text(msg, 10, height-hOffset);
  popStyle();
}

void triggerErrorSound() {
  if (!error.isPlaying()) {
    error.play();
  }
}

void updateCorona() {
  for (int i=0; i<coronaList.size(); i++) {
    coronaList.get(i).updatePosition(height);
    coronaList.get(i).dispVirus();
  }
}

void displayError() {
  if (error.isPlaying()) // // display error message
  {
    color errorColor = color(255, 0, 0); // color of error message
    flashMessage(errorMessage, errorColor, 15, 25); // display error message
  }
}

void displayCost() {
  if (game.state==1) { // display cost of buying more items
    String msg = "Handwash 1  Facemask 2  Faceshield 3"; // message string
    color c = color(53, 50, 56); // color of message
    flashMessage(msg, c, 18, 10); // display message
  }
}

void playBGMusic() {
  if (!scaryBg.isPlaying()) { // play bgMusic
    scaryBg.play();
  }
}

void moveFighters() {
  //activeFighters
  for (int i=0; i<activeFighters.size(); i++) {
    activeFighters.get(i).updatePosition();
  }
}

void checkCollisions() {
  //println("checking collision");                        
  // two for loops. Check as virus against each fighter
  // if collision rem both fighter and virus from arraylist
  // increment point accordingly
  // if fighter above screen remove from array list
  // if virus below screen increment cases and rem from arraylist
  for (int i=0; i<coronaList.size(); i++) {
    println(coronaList.size());
    CoronaVirus tC = coronaList.get(i);
    int size = tC.size;
    //println(size);
    for (int j=0; j<activeFighters.size(); j++) {
      Fighter tF = activeFighters.get(j);
      if (tF.positionX>tC.positionX && tF.positionX<tC.positionX+size) { // this mean the fighter is within the image
        if (tF.positionY>tC.positionY && tF.positionY<tC.positionY+size) { // this means the fighter is within the image
          coronaList.remove(i);
          activeFighters.remove(j);
          game.incrementPoints(tF.type);
          if (!collision.isPlaying()){
            collision.play();
          }
          game.points+=1;
        }
      }
    }
  }
}

void checkCoronaPosition(){
  for(int i=0;i<coronaList.size();i++){
    CoronaVirus tC = coronaList.get(i);
    if (tC.positionY>height){
      game.cases+=1;
      if(!newCase.isPlaying()){
        newCase.play();
      }
      coronaList.remove(i);
    }
  }
}

void checkFighterPosition(){
  for(int i=0;i<activeFighters.size();i++){
    Fighter tF = activeFighters.get(i);
    if (tF.positionY<0){
      activeFighters.remove(i);
    }
  }
}

void newViruses(){
  if (frameCount%7==0 && frameCount%9==0 && frameCount%4==0){
    coronaList.add(new CoronaVirus());
  }
}

void gameOver(){
  // this should display the previous game stats
  background(110,125,171);
  int size = 50;
  pushStyle();
  textSize(24);
  int moveItemsHorizontal = 100;
  image(game.handwashImg,width/2-120+moveItemsHorizontal,height/2-240,size,size);
  text(game.handwash,width/2-80+moveItemsHorizontal,height/2-230);
  
  image(game.maskImg,width/2-120+moveItemsHorizontal,height/2-160,size,size);
  text(game.masks,width/2-80+moveItemsHorizontal,height/2-150);
  
  image(game.shieldImg,width/2-120+moveItemsHorizontal,height/2-80,size,size);
  text(game.masks,width/2-80+moveItemsHorizontal,height/2-70);
  
  textSize(32);
  textAlign(CENTER);
  text("Points "+game.points,width/2,height/2+30);
  text("Cases "+game.cases,width/2,height/2+80);
  popStyle();
  restartButton();
  
}

void restartButton(){
  int buttonYPosition = 200;
  int rectWidth = 250;
  int rectHeight = 70;
  pushStyle();
  rectMode(CENTER);
  fill(9,129,74);
  if (mouseX>width/2-rectWidth/2 && mouseX<width/2+rectWidth/2 && mouseY>height/2+buttonYPosition-rectHeight/2 && mouseY<height/2+buttonYPosition+rectHeight/2){
    fill(9,160,74);
    if (mousePressed){
      resetGame();
      fill(9,100,74);
    }
  }
  rect(width/2,height/2+buttonYPosition,rectWidth,rectHeight,30);
  textAlign(CENTER);
  fill(0,0,0);
  textSize(40);
  text("RESTART",width/2,height/2+buttonYPosition+15);
  popStyle();
}

void resetGame(){
  game = new Game();
  coronaList = new ArrayList<CoronaVirus>(0);
  activeFighters = new ArrayList<Fighter>(0);
  game.state = 0;
  for (int i=0; i<4; i++) {
    coronaList.add(new CoronaVirus());
  }
}

void startScreen(){
  background(110,125,171);
  image(virus,20,20,500,500);
  instructions();
  startButton();
}

void startButton(){
  int moveButton = 85;
  int buttonYPosition = 200;
  int rectWidth = 250;
  int rectHeight = 70;
  pushStyle();
  rectMode(CENTER);
  fill(9,129,74);
  if (mouseX>width/2-rectWidth/2 && mouseX<width/2+rectWidth/2 && mouseY>height/2+buttonYPosition-rectHeight/2+moveButton && mouseY<height/2+buttonYPosition+rectHeight/2+moveButton){
    fill(9,160,74);
    if (mousePressed){
      game.state=0;
      fill(9,100,74);
    }
  }
  rect(width/2,height/2+buttonYPosition+moveButton,rectWidth,rectHeight,30);
  textAlign(CENTER);
  fill(0,0,0);
  textSize(40);
  text("START",width/2,height/2+buttonYPosition+15+moveButton);
  popStyle();
}

void instructions(){
  // Title
  pushStyle();
  String title = "Pandemic";
  fill(178,103,0);
  stroke(178,103,0);
  strokeWeight(3);
  textAlign(CENTER);
  textSize(48);
  text(title,width/2,60);
  popStyle();
  
  //objective heading
  pushStyle();
  String objective = "Objective";
  fill(0,0,0);
  textAlign(LEFT);
  textSize(32);
  text(objective,width/2,150);
  popStyle();
  
  //objective text
  pushStyle();
  String objectiveText = "Try to get your points as high as possible while keeping the number of the cases as low as possible";
  fill(0,0,0);
  textAlign(LEFT);
  textSize(18);
  text(objectiveText,width/2+50,180, width/2-70,250);
  popStyle();
  
  //instruction heading
  pushStyle();
  String instruction = "Instructions";
  fill(0,0,0);
  textAlign(LEFT);
  textSize(32);
  text(instruction,width/2,280);
  popStyle();
  
  //objective text
  String line1 = "1. Move the shooter across the screen by using the left and right arrow keys.\n";
  String line2 = "2. The icon shown in the shooter will be what you will be shooting down the virus with.\n";
  String line3 = "3. Shooting the virus down with different tools will yield different points.\n";
  String line4 = "4. The tools which yield greater points are also more expensive to acquire.\n";
  String line5 = "5. You can choose the tool that you’re fighting with by pressing 1,2 or 3. 1 will select the handwash, 2 will select facemask and 3 will select a face shield.\n";
  String line6 = "6. You can acquire more tools by pressing m to go into buying mode and then pressing 1,2 or 3 to acquire more tools. A hand wash will cost 1 point, a face mask will cost 2 points and a face shield will cost 3 points.\n";
  String line7 = "7. Number of cases will increase is the virus goes below the screen.";
  pushStyle();
  String instructionText = line1+line2+line3+line4+line5+line6+line7;
  fill(0,0,0);
  textAlign(LEFT);
  textSize(15);
  text(instructionText,width/2+50,300, width/2-70,700);
  popStyle();
}
Planning Page 1
Planning Page 2
Planning Page 3
Planning Page 4
Planning Page 5
Planning Page 6
Planning Page 7
Planning Page 8
Planning Page 9

 

Aayush Deo Midterm Project

 

Midterm Project Update

The game is about fighting COVID-19 by the use of your fighting tools [handwash, facemask, and faceshield] the COVID-19 cells will fall from the top of the screen and if you shoot them, you get points but the number of fighting tools decrease. If the cells reaches the bottom of the screen the number of cases go up. The objective of the game is to keep the number of cases as low as possible.

For the midterm project the progress so far has been planning the game on paper. As seen below. As of right now on processing the code consists of a game class file and a main file.

The game class file will encapsulate all the game state and will be responsible for displaying the game stats and and updating them. The game class attributes are:

  1. points
  2. cases
  3. handwash
  4. masks
  5. shields
  6. state
  7. fightTool
  8. time
  9. And the icons

The game class methods are:

  1. increment points
  2. reduce points
  3. increment cases
  4. increment masks
  5. decrement masks
  6. increment shields
  7. decrement shields
  8. increment handwash
  9. decrement handwash
  10. change state
  11. update time
  12. drawGameStats

The icons for use in the game were downloaded from flaticon as seen below

 

class Game {
  // attributes
  int points = 0;
  int cases = 0;
  int handwash = 20;
  int masks = 14;
  int shields = 6;
  int state = 0; // 0->shooting 1-> buying -1 -> gameOver
  int fightingTool = 0; // 0-handwash, 1-mask, 2-shield
  int time = 120;
  PImage maskImg = loadImage("mask.png");
  PImage handwashImg = loadImage("handwash.png");
  PImage shieldImg = loadImage("shield.png");
  int timeDisplay = 0;


  //methods
  void incrementPoints() {
    if (fightingTool == 0) {
      points += 1;
    } else if (fightingTool == 1) {
      points += 3;
    } else if (fightingTool == 2) {
      points += 5;
    }
  }
  void reducePoints(int fightingTool) {
    if (state==1) {
      if (fightingTool == 1) {
      }
    }
  }
  void incrementCases() {
    cases+=1;
  }

  void incrementMasks() {
    masks+=1;
  }

  void decrementMasks() {
    masks-=1;
  }

  void incrementShields() {
    shields+=1;
  }

  void decrementShields() {
    shields-=1;
  }

  void incrementHandwash() {
    handwash+=1;
  }

  void decrementHandwash() {
    handwash-=1;
  }

  void changeState() {
    if (state==0) {
      state=1;
    } else if (state==1) {
      state=0;
    }
  }
  void updateTime() {
    if (time==0) {
      state=-1;
    }
    if (frameCount%60==0 && state!=-1) {
      time-=1;
      if (timeDisplay==0) {
        timeDisplay = 1;
      } else if (timeDisplay==1) {
        timeDisplay=0;
      }
    }
  }

  void drawGameStats() {
    color(0, 0, 0);
    imageMode(CENTER);

    // draw mask
    image(maskImg, 70, 30, 30, 30);
    text(masks+" x", 25, 30);

    //draw handwash
    image(handwashImg, 150, 30, 30, 30);
    text(handwash+" x", 110, 30);

    // draw faceshield
    image(shieldImg, 230, 30, 30, 30);
    text(shields+" x", 190, 30);

    //display time
    pushStyle();
    textSize(30);
    if (timeDisplay==1) {
      fill(0, 0, 0);
      text(time, width-100, height-30);
    } else if (timeDisplay==0) {
      fill(255, 255, 0);
      text(time, width-100, height-30);
    }
    popStyle();

    // game mode
    pushStyle();
    int rectWidth = 100;
    int rectHeight = 30;
    int cornerRadius = 10;
    noFill();
    rect(width/2-rectWidth/2, 20, rectWidth, rectHeight, cornerRadius, cornerRadius, cornerRadius, cornerRadius);
    if (state==0) {
      pushStyle();
      textAlign(CENTER);
      textSize(25);
      fill(255, 0, 0);
      text("FIGHT", width/2, 45);
      popStyle();
    }

    popStyle();
    
    //display points
    pushStyle();
    fill(0,0,0);
    textSize(25);
    text(points+" points", width-300,45);
    text(cases+" cases", width-150,45);
    popStyle();
  }
}

 

Pixel Manipulation – Week 5

For this week assignment I was completely out of ideas. So I decided to manipulate the pixel of an image. I load the picture and then in different functions I manipulate each individual pixel of the image.

There are five different manipulations that can take place:
Inverting the RGB values of each pixel
Inverting the R values of each pixel
Inverting the G values of each pixel
Inverting the B values of each pixel
Swapping the pixels in the array
Exagerating the each RGB value with the same random number

Each of the different functions are mapped to keys 1-6 on the keyboard and pressing any other key would reload the original image.

Original Image- Sweihan

Pressing different keys in different combinations will yield different outcomes.

Advanced Implementation

I tried to add another level of complexity to the sketch by inverting the pixels which in a circular distance of the mouse cursor.

I was able to figure the logic on paper but the logic when translated to code was not.

Logic Page 1
Logic Page Two

 

I would like to pursue this further and implement this logic

 

PImage img;
int counter = 0;
int KeyCode = -1;

void setup() {
  size(1280, 720);
  img = loadImage("scene.jpg");
  image(img, 0, 0, width, height);
  //noLoop();
}

void draw() {
  //if (mouseX>0 && mouseX<width && mouseY>0 && mouseY<height) {
  //  negativeMousePosition();
  //}
}

void keyPressed() {
  float sinVal = radians(180);
  println(sin(sinVal),cos(radians(180)));
  if (keyCode==49) { //1
    invertRGB();
    KeyCode = 49;
  } else if (keyCode==50) { //2
    invertR();
    KeyCode = 50;
  } else if (keyCode==51) { //3
    invertG();
    KeyCode = 51;
  } else if (keyCode==52) { //4
    invertB();
    KeyCode = 52;
  } else if (keyCode==53) { //5
    swapPixels();
    KeyCode = 53;
  } else if (keyCode == 54) { //6
    exagerate();
    KeyCode = 54;
  } else { //anything else
    drawOriginal();
    KeyCode = -1;
  }
}

//void mouseDragged(){
//  negativeMousePosition();
//}

void invertRGB() {
  //img = loadImage("scene.jpg");
  //image(img, 0, 0, width, height);
  loadPixels();
  for (int i=0; i<width*height; i++) {
    int r = (int)red(pixels[i]); //get red value
    int g = (int) green(pixels[i]); // get green value
    int b = (int) blue(pixels[i]); //get blue value
    color c = color(255-r, 255-g, 255-b); // take the complement of the rgb values
    pixels[i] = c; //set the new color value
  }
  updatePixels(); //update the pixels on screen
}

void invertR() {
  //img = loadImage("scene.jpg");
  //image(img, 0, 0, width, height);
  loadPixels();
  for (int i=0; i<width*height; i++) {
    int r = (int)red(pixels[i]); //get red value
    int g = (int) green(pixels[i]); // get green value
    int b = (int) blue(pixels[i]); //get blue value
    color c = color(255-r, g, b); // take the complement of the rgb values
    pixels[i] = c; //set the new color value
  }
  updatePixels(); //update the pixels on screen
}

void invertG() {
  //img = loadImage("scene.jpg");
  //image(img, 0, 0, width, height);
  loadPixels();
  for (int i=0; i<width*height; i++) {
    int r = (int)red(pixels[i]); //get red value
    int g = (int) green(pixels[i]); // get green value
    int b = (int) blue(pixels[i]); //get blue value
    color c = color(r, 255-g, b); // take the complement of the rgb values
    pixels[i] = c; //set the new color value
  }
  updatePixels(); //update the pixels on screen
}

void invertB() {
  //img = loadImage("scene.jpg");
  //image(img, 0, 0, width, height);
  loadPixels();
  for (int i=0; i<width*height; i++) {
    int r = (int)red(pixels[i]); //get red value
    int g = (int) green(pixels[i]); // get green value
    int b = (int) blue(pixels[i]); //get blue value
    color c = color(r, g, 255-b); // take the complement of the rgb values
    pixels[i] = c; //set the new color value
  }
  updatePixels(); //update the pixels on screen
}

void drawOriginal() {
  image(img, 0, 0, width, height);
}

void swapPixels() {
  //img = loadImage("scene.jpg");
  //image(img, 0, 0, width, height);
  loadPixels();
  //println(pixels[1]);
  //println(pixels[width*height-2]);

  for (int i=0; i<(width*height)/2; i++) {
    int temp;
    temp = pixels[i];
    pixels[i] = pixels[width*height-1-i];
    pixels[width*height-1-i] = temp;
  }

  updatePixels();
  //println(pixels[1]);
}

void exagerate() {
  //img = loadImage("scene.jpg");
  //image(img, 0, 0, width, height);
  loadPixels();
  for (int i=0; i<width*height; i++) {
    int r = (int)red(pixels[i]); //get red value
    int g = (int) green(pixels[i]); // get green value
    int b = (int) blue(pixels[i]); //get blue value
    int randomR = (int) random(255);
    int randomG = (int) random(255);
    int randomB = (int) random(255);
    color c = color((r+randomR), (g+randomG), (b+randomB)); // take the complement of the rgb values
    pixels[i] = c; //set the new color value
  }
  updatePixels(); //update the pixels on screen
}

 

Cardio Time

For this week’s assignment I decided to use that was being collected by the running app that I am using to track my running progress. The app records the distance per run, walking pace, running pace and the average pace.

For this assignment I took the average pace per run [given in minutes/km] and point plotted it against the days.

The data was between 0 and 9 so I have to get that data in the range such that I could plot it on the screen. For this I used the following formula
data*(maxDrawableHeight)/9.

This gave me the height of the points from the axis but since the drawing points are given from top left corner going down I inverted this by subtracting this from the drawable height.

 

Table data;
float[] numericData;
float [] plotData;
int numCols;
int axisOffset = 100;
void setup() {
  size(1000, 500);
  loadData();
  dataTransformation();
  drawAxes();
  drawGrid();
  printLabels();
  plotPoints();
  noLoop();
}

void draw() {
}

void drawAxes() {
  axisOffset = 50;
  pushStyle();
  strokeWeight(2);
  //y axis
  line(axisOffset, 0, axisOffset, height-axisOffset);
  //x-axis
  line(0+axisOffset, height-axisOffset, width, height-axisOffset);
  popStyle();
}

void loadData() {
  data = loadTable("data.csv");
  TableRow row = data.getRow(0);
  numCols = row.getColumnCount();
  numericData = new float[numCols];
  for (int i=0; i<numCols; i++) {
    numericData[i] = Float.parseFloat(row.getString(i));
  }
  //println();
}

void printData() {
  for (int i=0; i<numericData.length; i++)
  {
    print(numericData[i] + " | ");
  }
  println();
}

void drawGrid()
{
  // data will be in the range of 0 < 9*(height-axisOffset)
  pushStyle();
  stroke(0,0,0,40);
  // for drawing Horizontal grid lines
  float xLineGap = (height-axisOffset)/9;
  for (float y=height-axisOffset; y>=0; y=y-xLineGap){
    line(axisOffset,y,width,y);
  }
  //println(numCols);
  float yLineGap = (width-axisOffset)/numCols;
  for (float x=axisOffset+yLineGap;x<=width; x+=yLineGap)
  {
    line(x,0,x,height-axisOffset);
  }
  popStyle();
}

void dataTransformation(){
  // data will be in the range of 0 < 9*(height-axisOffset)
  //transform the data
  plotData = new float[numCols];
  for(int i=0;i<numCols;i++)
  {
    plotData[i] = numericData[i]*(height-axisOffset)/9;
  }
  //println(plotData);
}

void plotPoints(){
  float yLineGap = (width-axisOffset)/numCols;
  for(int i=0;i<numCols;i++){
    strokeWeight(6);
    float yCoord = height-(plotData[i]+axisOffset+yLineGap);
    //println(plotData[i]);
    point(axisOffset+yLineGap+(yLineGap)*i,yCoord);
  }
}

void printLabels(){
  //title
  fill(0,0,0);
  textSize(20);
  textAlign(CENTER);
  String title = "Graph Of Average Pace [minutes/km] Against Run Days";
  text(title,width/2, height-(axisOffset/5));
  
  
  //x-axis labels
  float yLineGap = (width-axisOffset)/numCols;
  for(int i=0;i<numCols;i++)
  {
    text(i+1,axisOffset+yLineGap+(yLineGap)*i, height-(axisOffset*3/5));
  }
  
  //y-axis labels
  float xLineGap = (height-axisOffset)/9;
  int text = 0;
  for(float y=height-axisOffset; y>=0; y=y-xLineGap)
  {
    text(text,axisOffset-10,y);
    text++;
    //println(text);
  }
    
  for (float y=height-axisOffset; y>=0; y=y-xLineGap){
    line(axisOffset,y,width,y);
  }
}

 

Back To Childhood: Tic-Tac-Toe

For this weeks assignment I decided to recreate a game that I played alot with my siblings when power was out during hurricanes seasons in a digital. I decided to make the game tic-tac-toe however instead of uses X’s and  O’s I decided that each piece will be a square box that it will be filled in each of the spots. The reason for this was utilize the entire canvas that processing provide.

I utilized a snapping motion to determine where the player was currently

was and the piece would be put should the player click the mouse button.

For the object oriented portion of the game all of the game logic is encapsulated in a game class. The game class uses a 2D-array to store the “pieces” either as a 0 for red, 1 for green or a -1 for empty. This array is used during the entire time that the game is in session to render the pieces as well do various logic work. For instance, if the value is not -1 then the piece should not be played. The game class also used this array to check the winning condition of the game.\\

void setup() {
  size(1000, 1000);
}
//global variables
float boxWidth = 1000/3;
Game myGame = new Game();
int turn = 0; //0 is red, 1 is green
boolean gameRunning = true;
String gameWonBy = "";
int piecesIn = 0;


void draw() {
  background(255, 255, 255);
  if (gameRunning == true)
  {
    cursorHover();
  }

  board();
  myGame.colorPieces();
  myGame.checkWin();
  pushStyle();
  textSize(32);
  textAlign(CENTER);
  //fill(255, 255, 255);
  fill(0, 0, 0);
  if (gameWonBy == "Red") {
    text("This game was won by red", width/2, height/2);
    //println("should display text");
  } else if (gameWonBy == "Green") {
    text("This game was won by green", width/2, height/2);
    //println("should display text");
  } else if (gameWonBy == "Tie") {
    text("This game ended in a tie", width/2, height/2);
    //println("should display text");
  }
  popStyle();
}

//functions
void board() {
  pushStyle();
  strokeWeight(3);
  //first vertical line
  line(width/3, 0, width/3, height);
  //second vertical line
  line(2* width/3, 0, 2*width/3, height);

  //first horizontal line
  line(0, height/3, width, height/3);
  //second horizontal line
  line(0, 2*height/3, width, 2*height/3);
  popStyle();
}

void cursorHover() {
  //make the light green/red box over the position
  if (turn%2==0)
  {
    fill(255, 0, 0, 180);
  } else if (turn%2==1) {
    fill(0, 255, 0, 180);
  }
  //origin of the hover box
  int[] origin = getIndices();
  //draw the position
  rect(origin[1]*boxWidth, origin[0]*boxWidth, boxWidth, boxWidth);
}

void mouseClicked() {
  myGame.updatePosition(getIndices());
  //myGame.printPositions();
}

int[] getIndices() {
  int[] indices = new int[2];
  //x is index 0, y is index 1
  indices[0] = floor(mouseY/boxWidth);
  indices[1] = floor(mouseX/boxWidth);
  return indices;
}




//classes
class Game {
  int[][] positions = new int[3][3];
  Game() {
    for (int i=0; i<positions.length; i++) {
      for (int j=0; j<positions[i].length; j++) {
        positions[i][j]=-1;
      }
    }
  }
  void updatePosition(int[] indices) {
    if (gameRunning)
    {
      if (positions[indices[0]][indices[1]] == -1) {
        positions[indices[0]][indices[1]] = turn%2;
        turn=turn+1;
        piecesIn+=1;
      }
    }
  }

  void printPositions() {
    for (int i=0; i<positions.length; i++) {
      for (int j=0; j<positions[i].length; j++) {
        //print(positions[i][j]+" ");
      }
      //println();
    }
    //println();
  }

  void colorPieces() {
    for (int i=0; i<positions.length; i++) {
      for (int j=0; j<positions[i].length; j++) {
        //if position is 0 then color the position red
        if (positions[j][i]==0) {
          pushStyle();
          fill(255, 0, 0);
          rect(i*boxWidth, j*boxWidth, boxWidth, boxWidth);
          popStyle();
        } 
        //if position is 1 then color the position green
        else if (positions[j][i]==1) {
          pushStyle();
          fill(0, 255, 0);
          rect(i*boxWidth, j*boxWidth, boxWidth, boxWidth);
          popStyle();
        }
      }
    }
  }

  void checkWin() {
    //tie check
    if (piecesIn == 9 && gameRunning==true) {
      gameRunning = false;
      gameWonBy = "Tie";
      //println("Tie");
    }
    //row check
    for (int i=0; i<3; i++) {
      if (positions[i][0]==0 && positions[i][1]==0 && positions[i][2]==0) {
        gameRunning = false;
        gameWonBy = "Red";
        //println("gameWonBy Red");
      } else if (positions[i][0]==1 && positions[i][1]==1 && positions[i][2]==1) {
        gameRunning = false;
        gameWonBy = "Green";
        //println("gameWonBy Green");
      }
    }
    // column check
    for (int i=0; i<3; i++) {
      if (positions[0][i]==0 && positions[1][i]==0 && positions[2][i]==0) {
        gameRunning = false;
        gameWonBy = "Red";
        //println("gameWonBy Red");
      } else if (positions[0][i]==1 && positions[1][i]==1 && positions[2][i]==1) {
        gameRunning = false;
        gameWonBy = "Green";
        //println("gameWonBy Green");
      }
    }

    // diagonal check y=-x
    if (positions[0][0]==0 && positions[1][1]==0 && positions[2][2]==0) {
      gameRunning = false;
      gameWonBy = "Red";
      //println("gameWonBy Red");
    } else if (positions[0][0]==1 && positions[1][1]==1 && positions[2][2]==1) {
      gameRunning = false;
      gameWonBy = "Green";
      //println("gameWonBy Green");
    }

    // diagonal check y=x
    if (positions[0][2]==0 && positions[1][1]==0 && positions[2][0]==0) {
      gameRunning = false;
      gameWonBy = "Red";
      //println("gameWonBy Red");
    } else if (positions[0][2]==1 && positions[1][1]==1 && positions[2][0]==1) {
      gameRunning = false;
      gameWonBy = "Green";
      //println("gameWonBy Green");
    }
  }
}