Dice-roller for Monopoly

For this week’s assignment I wanted to make a dice-roller for monopoly – As in, an object that you shake as if you’re shaking dice and that triggers the dice roll in the monopoly I had previously made in processing. This proved to be challenging.

I wanted to make the roller as compact and sturdy as possible, since it will be subject to shaking and I didn’t want anything to come lose, so I started with this circuit:

I used an arduino maker1000 because of it’s small size. The shaking was detected using a tilt sensor. Everything is soldered on in one unit so it was easy to hold and shake and everything would still be stable. However, no matter how hard I tried, the maker1000 would not communicate with processing. So I switched to a redboard.

Here’s the video of how it works:

The code:

Arduino:

const int tiltPin = 6;
const int ledPin = 10;

int tiltState;             // the current reading from the input pin
int lastTiltState = LOW;   // the previous reading from the input pin
int counter = 0;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 20;

void setup() {
  // put your setup code here, to run once:
  pinMode(tiltPin, INPUT);
  pinMode(ledPin, OUTPUT);
  Serial.begin(9600);
  digitalWrite(ledPin, HIGH);
  Serial.write(0);
}

void loop() {
  if (Serial.available() > 0) {
    int inByte = Serial.read();

    if (counter <= 20) {
      digitalWrite(ledPin, HIGH);
      Serial.write(0);
    } else {
      counter = 0;
      digitalWrite(ledPin, LOW);
      Serial.write(1);
      delay(2000);

    }
    int reading = digitalRead(tiltPin);
    if (reading != lastTiltState) {
      lastDebounceTime = millis();
    }

    if ((millis() - lastDebounceTime) > debounceDelay) {
      if (reading != tiltState) {
        tiltState = reading;
        counter++;
      }
    }
    //  Serial.print(reading);
    //  Serial.print(" || ");
    //  Serial.println(counter);
    lastTiltState = reading;
  }
  // put your main code here, to run repeatedly:


}

Processing:

import processing.serial.*;
//0 name, 1 type, 2 owner, 3 cost, 4 rent, 5 xcoordinate, 6 ycoordinate
// types: 0 = income tax, 1 = normal, 2 = railroad, 3 = utilities, 4 = community chest and chance, 5 = jail and free parking, 6 = go,7 = supertax
String[][] places = {
  {"Go", "6", "Bank", " ", "-200", "750", "750"}, // 0
  {"Old kent road", "1", "Bank", "60", "6", "660", "750"}, // 1
  {"Community chest", "4", "Bank", " ", "0", "595", "750"}, // 2
  {"White chapel road", "1", "Bank", "60", "6", "530", "750"}, //3
  {"Income tax", "0", "Bank", " ", "200", "465", "750"}, // 4
  {"Kings cross station", "2", "Bank", "200", "25", "400", "750"}, // 5
  {"The angel islington", "1", "Bank", "100", "10", "335", "750"}, // 6
  {"Chance", "4", "Bank", " ", "0", "270", "750"}, // 7
  {"Euston Road", "1", "Bank", "100", "10", "205", "750"}, // 8
  {"Pentonville Road", "1", "Bank", "120", "12", "140", "750"}, // 9
  {"Jail", "5", "Bank", " ", "0", "50", "750"}, // 10
  {"Pall Mall", "1", "Bank", "140", "14", "50", "660"}, // 11
  {"Electric Company", "3", "Bank", "150", "15", "50", "595"}, // 12
  {"Whitehall", "1", "Bank", "140", "14", "50", "530"}, // 13
  {"Northumberland Avenue", "1", "Bank", "160", "16", "50", "465"}, // 14
  {"Marylebone station", "2", "Bank", "200", "25", "50", "400"}, // 15
  {"Bow street", "1", "Bank", "180", "18", "50", "335"}, // 16
  {"Community chest", "4", "Bank", " ", "0", "50", "270"}, // 17
  {"Marlborough street", "1", "Bank", "180", "18", "50", "205"}, // 18
  {"Vine street", "1", "Bank", "200", "20", "50", "130"}, // 19
  {"Free Parking", "5", "Bank", " ", "0", "50", "50"}, // 20
  {"Strand", "1", "Bank", "220", "22", "140", "50"}, // 21
  {"chance", "4", "Bank", " ", "0", "205", "50"}, // 22
  {"Fleet street", "1", "Bank", "220", "22", "270", "50"}, // 23
  {"Trafalgar square", "1", "Bank", "240", "24", "335", "50"}, // 24
  {"Fenchurch st station", "2", "Bank", "200", "25", "400", "50"}, // 25
  {"Leicester square", "1", "Bank", "260", "26", "465", "50"}, // 26
  {"Coventry street", "1", "Bank", "260", "26", "530", "50"}, // 27
  {"Waterworks", "3", "Bank", "150", "15", "595", "50"}, // 28
  {"Piccadilly", "1", "Bank", "280", "28", "660", "50"}, // 29
  {"Jail", "5", "Bank", " ", "0", "750", "50"}, // 30
  {"Regent street", "1", "Bank", "300", "30", "750", "130"}, // 31
  {"Oxford street", "1", "Bank", "300", "30", "750", "205"}, // 32
  {"Community chest", "4", "Bank", " ", "0", "750", "270"}, // 33
  {"Bond street", "1", "Bank", "320", "32", "750", "335"}, // 32
  {"Marylebone station", "2", "Bank", "200", "25", "750", "400"}, // 15
  {"Chance", "4", "Bank", " ", "0", "750", "465"}, // 33
  {"Park lane", "1", "Bank", "350", "32", "750", "530"}, // 32
  {"Supertax", "7", "Bank", " ", "200", "750", "595"}, 
  {"Mayfair", "1", "Bank", "400", "40", "750", "660"}, 

};

int toRoll;
int prevToRoll;
boolean allowRoll = true;
int circlesize = 10;
int turn = 0;
int diceroll;
PImage bg;
boolean first = true;
boolean proceed = false;

// colors: red or blue
Player p1 = new Player("red", int(places[0][5]), int(places[0][6]), 10);
Player p2 = new Player("blue", int(places[0][5]), int(places[0][6]), -10);
Serial myPort;


void setup() {
  printArray(Serial.list());
  String portname=Serial.list()[2];
  println(portname);
  myPort = new Serial(this, portname, 9600);
  //myPort.clear();
  //myPort.bufferUntil('\n');


  first = false;
  size(800, 800);
  bg = loadImage("board.jpg");
  background(0);
  fill(255);
  textSize(16);
  text("Welcome to mehnopoly. It's almost monopoly, but seriously lower your expectations.", 20, 50);
  text("The game is for two players. or You can play against yourself if you can't find friends. I dont judge.", 20, 100);
  text("You win by making your opponent go bankrupt. Go nuts!", 20, 150);
  text("Press S to start the game", 20, 200);
  textSize(12);
  text("Fun Fact: Monopoly was originally created as a statement against capitalism.", 20, 250);
}

void draw() {
  if (proceed==true ){
    refresh();
    allowRoll = false;
    diceroll = rollDice();
    handleRoll();
    proceed=false;
  }
  if (first) {
    textSize(24);
    fill(255, 127, 0);
    text("Player 1 has "+p1.money+" left", 150, 200);
    text("Player 2 has "+p2.money+" left", 150, 250);
    text("Player 1's turn", 150, 300);
    text("Press R to roll dice", 150, 350);
  }
}
int keycounter = 0;




class Player {
  int money, xpos, ypos, rails, utilities, offset, placecount, propertyamount;
  int[] properties = new int[50];
  String col;
  Player (String n, int xp, int yp, int off) {
    col = n;
    placecount = 0;
    money = 1500;
    offset = off;
    xpos = xp;
    ypos = yp;
    rails = 0;
    utilities = 0;
    propertyamount = 0;
  }

  void display() {
    strokeWeight(2);
    stroke(255, 255, 255);
    if (col == "red")fill(255, 0, 0);
    if (col == "blue")fill(0, 0, 255);
    ellipse(xpos+offset, ypos, circlesize, circlesize);
  }
  void updatePos() {
    xpos = int(places[placecount][5]);
    ypos = int(places[placecount][6]);
  }
}

int rollDice() {
  return round(random(2, 12));
  //return 7;
}

void checkLanded(Player x) {
  textSize(24);
  fill(255, 127, 0);
  text("You rolled "+diceroll+" and landed on: "+places[x.placecount][0], 150, 200);
  if (int(places[x.placecount][1]) == 5 || int(places[x.placecount][1]) == 6)text("Press E to end turn", 150, 250);
  // if income tax
  if (int(places[x.placecount][1]) == 0) {
    fill(255, 127, 0);
    text("You pay 200 for income tax", 150, 250);
    x.money-=200;
    text("You now have: "+str(x.money)+" left", 150, 300);
    text("Press E to end turn", 150, 350);

    // if purchasable
  } else if (int(places[x.placecount][1]) == 1 || int(places[x.placecount][1]) == 2 || int(places[x.placecount][1]) == 3) {
    // if owner is bank
    if (places[x.placecount][2] == "Bank") {
      fill(255, 127, 0);
      text("Property isn't owned, what would you like to do?", 150, 250);
      text("Press B to buy for "+places[x.placecount][3]+" or press E to end turn", 150, 300);
      // if owner is not bank
    } else {
      // if it's a normal purchasable
      if (int(places[x.placecount][1]) == 1) {
        if (turn == 0 && places[x.placecount][2] == "Player2")handleRent(p1, p2, int(places[x.placecount][4]));
        if (turn == 1 && places[x.placecount][2] == "Player1")handleRent(p2, p1, int(places[x.placecount][4]));
        // if railroad
      } else if (int(places[x.placecount][1]) == 2) {
        int rent;
        if (turn == 1 && places[x.placecount][2] == "Player1") {
          rent = checkRailRent(p1);
          handleRent(p2, p1, rent);
        } else if (turn == 0 && places[x.placecount][2] == "Player2") {
          rent = checkRailRent(p2);
          handleRent(p1, p2, rent);
        }
        // if utilities
      } else if (int(places[x.placecount][1]) == 3) {
        int rent = 0;
        if (turn == 0 && places[x.placecount][2] == "Player2") {
          if (p2.utilities == 1)rent= 7*diceroll;
          if (p2.utilities == 2)rent= 15*diceroll;
          handleRent(p1, p2, rent);
        } else if (turn == 1 && places[x.placecount][2] == "Player1") {
          if (p1.utilities == 1)rent= 7*diceroll;
          if (p1.utilities == 2)rent= 15*diceroll;
          handleRent(p2, p1, rent);
        }
      }
    }
    // super tax
  } else if (int(places[x.placecount][1]) == 7) {
    fill(255, 127, 0);
    text("You pay 100 for super tax", 150, 250);
    x.money-=200;
    text("You now have: "+str(x.money)+" left", 150, 300);
    text("Press E to end turn", 150, 350);
    //community chest and chance
  } else if (int(places[x.placecount][1]) == 4) {
    int r = round(random(1, 3));
    if (!(r == 2)) {
      text("Jeff Bezos felt generous today, he gave you 100!", 150, 250);
      text("Assuming 1 = $100,000 , this amounts to", 150, 300);
      text("a whooping 0.0001% of his net worth", 150, 350);
      text("press E to end turn", 150, 400);
      x.money += 100;
    } else {
      text("You did some contractual work on one of", 150, 250);
      text("Trump's properties! He paid you a 1000!", 150, 300);
      text("Just kidding, he didn't pay you at all.", 150, 350);
      text("In fact you paid a 100 for materials.", 150, 400);
      text("press E to end turn", 150, 450);
      x.money -= 100;
    }
  }
  checkWin();
}

void checkWin() {
  if (p1.money < 0) {
    refresh();
    fill(255, 127, 0);
    text("P2 has won", 150, 200);
    noLoop();
  }
  if (p2.money < 0) {
    refresh();
    fill(255, 127, 0);
    text("P1 has won", 150, 200);
    noLoop();
  }
}

void endTurn() {
  refresh();
  fill(255, 127, 0);
  text("Player 1 has "+p1.money+" left", 150, 200);
  text("Player 2 has "+p2.money+" left", 150, 250);
  if (turn == 0) {
    fill(255, 127, 0);
    text("Player 1's turn has ended. Player 2's turn", 150, 300);
    turn = 1;
  } else {
    fill(255, 127, 0);
    text("Player 2's turn has ended. Player 1's turn", 150, 300);
    turn = 0;
  }
  text("Press R to roll or I for a list of your properties,", 150, 350);
  allowRoll = true;
  checkWin();
}


void refresh() {
  background(bg);
  p1.display();
  p2.display();
  fill(0);
  rect(100, 100, 600, 600);
}

void buy(Player x) {
  fill(255, 127, 0);
  if (places[x.placecount][2] == "Bank") {
    x.money -= int(places[x.placecount][3]);
    x.properties[p1.propertyamount] = x.placecount;
    x.propertyamount++;
    text(places[x.placecount][0]+" has been purchased", 150, 200);

    if (turn == 0) places[x.placecount][2] = "Player1";
    if (turn == 1) places[x.placecount][2] = "Player2";
    if (int(places[x.placecount][1]) == 2) {
      x.rails += 1;
      text("You now have "+x.rails+" railroads", 150, 250);
      text("Press E to end turn", 150, 300);
    } else if (int(places[x.placecount][1]) == 3) {
      x.utilities += 1;
      text("You now have "+x.utilities+" utilities", 150, 250);
      text("Press E to end turn", 150, 300);
    } else {
      text("Press E to end turn", 150, 250);
    }
  }
  checkWin();
}

int checkRailRent(Player x) {
  if (x.rails == 1) return x.rails*25;
  if (x.rails == 2) return x.rails*25;
  if (x.rails == 3) return 100;
  if (x.rails == 4) return 200;
  return 0;
}

void handleRent(Player renter, Player rentee, int rent) {
  renter.money -= rent;
  rentee.money += rent;
  fill(255, 127, 0);
  text("Property is owned, you have paid "+rent+" in rent", 150, 250);
  text("You have "+renter.money+" left", 150, 300);
  text("Press E to end turn", 150, 350);
  checkWin();
}

void handleRoll() {
  if (turn == 0) {
    if (p1.placecount + diceroll >= 40) {
      p1.placecount = p1.placecount+diceroll - 40;
      p1.money += 200;
    } else {
      p1.placecount+= diceroll;
    }
    p1.updatePos();
    refresh();
    checkLanded(p1);
  } else {
    if (p2.placecount + diceroll >= 40) {
      p2.placecount = p2.placecount+diceroll - 40;
      p2.money += 200;
    } else {
      p2.placecount+= diceroll;
    }
    p2.updatePos();
    refresh();
    checkLanded(p2);
  }
}

void serialEvent(Serial myPort) {
  int x = myPort.read();
  println(x);
  if (x == 1 && allowRoll) {
    proceed=true;
  }
  //toRoll = myPort.read();
  //println(toRoll);
  myPort.write(0);
}
void keyPressed() {
  //keycounter++;
  //if (keycounter == 1) first = true;
  //if (keycounter == 2) first = false;

  if (key =='s')refresh();
  //refresh();
  // Roll dice phase
  if ((key == 'r' || key == 'R')&&allowRoll) {
    allowRoll = false;
    diceroll = rollDice();
    handleRoll();
  }
  if ((key == 'b' || key =='B')&& !allowRoll) {
    refresh();
    if (turn == 0) {
      buy(p1);
    } else {
      buy(p2);
    }
  }

  if ((key == 'e' || key == 'E')&& !allowRoll) {
    refresh();
    endTurn();
  }

  if ((key == 'i' || key == 'I') && allowRoll) {
    fill(255, 127, 0);
    if (turn == 0) { 
      int ycounter = 200;
      for (int i = 0; i<p1.propertyamount; i++, ycounter+=50) {
        text(places[p1.properties[i]][0], 150, ycounter);
      }
    }
    if (turn == 1) {
      int ycounter = 200;
      for (int i = 0; i<p2.propertyamount; i++, ycounter+=50) {
        text(places[p2.properties[i]][0], 150, ycounter);
      }
    }
  }
}

 

Computing

Computing started as just a way to crunch numbers. Computers even used to be people who would do certain mathematical tasks. However, once mechanized and then electronic computing was invented, a whole new horizon was unlocked for ‘computers’. Our use of computers went way beyond just mathematics, in fact computing is now essential in our everyday lives. Everything we do involved a computer in one way or another, for better or for worse. While the benefits of computers are clear, there certainly isn’t a lack of drawbacks either. Due to our excessive use and dependance on computers, we are losing our privacy due to tracking of the massive amounts to data we give to the computers. Furthermore, we are becoming more attached to the digital world than ever, which affects our lives and relationships.

Basically, to me, a computer is an extremely powerful tool, and whether that tool works to your advantage or not is completely dependent on how you use it.

Digitize Everything

The author mentioned facebook being the most popular internet site in the world. With companies like facebook and google which are extremely useful and very widely utilized by the world, and are also free to use, then you become not the customer of those sites but the products. The way these companies turn a profit is by selling your data, that they have amassed plenty of by y0u using their services, to advertisers. This has become increasingly apparent in the past month when it was discovered that this data mining by advertisers was used to influence the 2016 US presidential elections. This is the problem, when it is this easy to collect data in our digital age, especially data about people, we lose privacy.

Women’s share of the workforce

First of all, for data visualization, you need data. So I had previously downloaded and scrubbed a database from the United Nations containing data for women’s share of the workforce in a 189 countries from 1985 to 2006. The list of countries included in the database can be found here: https://github.com/AdhamChakohi/IntrotoIm/blob/master/list%20of%20countries.txt

The original database can be found here: http://data.un.org/Data.aspx?d=GenderStat&f=inID%3a107

I had previously ran the database through a python script to clean it up and remove the unnecessary data, and also add the average and medians across the years for each country. Here’s the python script:

# gets median and average for each country
def hasNumbers(inputString):
    return any(char.isdigit() for char in inputString)

def getStats(file, country):
    country = country.lower()
    fp = open(file, 'r')
    listSum = 0
    counter = 0
    medianList = []
    for i in fp:
        i = i.strip().split(',')
        if i[0][1:-1].lower() == country:
            print(i)
            medianList.append(float(i[5][1:-1]))
            counter += 1
            listSum += float(i[5][1:-1])
    mid = findMiddle(medianList)
    return round(listSum/counter,1), mid

# finds the middle of the list for the purpose of finding the median
def findMiddle(x):
    mid = float(len(x))/2
    if mid%2 == 0:
        return (x[int(mid)]+x[int(mid-1)])/2
    else:
        return x[int(mid-.5)]

def main():
    file_name = "dataset.csv"
    fp = open(file_name,'r')
    target = file_name[:-4]+"_out.csv"
    t = open(target,'w')
    lines_read,lines_written = 0,0
    t.write('country,year,percentage,average across the years,median\n')
    
    for i in fp:
        current = i.strip().split(",")
        # print(current[0])
        if any(j.isdigit() for j in i) and not hasNumbers(current[0][1:-1]):
            #the [1:-1] indexes are the remove the quotation marks that the data entries come in
            average, median = getStats(file_name,current[0][1:-1])
            written = current[0][1:-1]+","+current[2][1:-1]+","+current[5][1:-1]+","+str(average)+","+str(median)+"\n"
            # print(written)
            t.write(written)

main()

This is code that I have written months ago, and I just found out I had a bug that was removing the data for around 50 countries from the database, so I fixed that. Moving on, the data visualization:

I made this sort of applet, that visualizes women’s share of the workforce for the country that is entered, and with the ability to scroll through the different years available by pressing the left and right keys. There are a 100 squares displayed, the red squares representing female workers, and blue representing the male workers.

more pictures:

The code :

String countryInput = "Palestinian Territory Occupied";

Table table;
float[][] stats = new float[22][3];
int counter = 0;
int pointer = 0;

void setup() {
  size(800, 800);
  table = loadTable("dataset_out.csv", "header,csv");
  for (TableRow row : table.rows()) {
    String country = trim(row.getString("country"));
    if (country.equals(countryInput)) {
      float year = row.getFloat("year");
      float percentage = row.getFloat("percentage");
      float median = row.getFloat("median");
      stats[counter][0] = year;
      stats[counter][1] = percentage;
      stats[counter][2] = median;
      counter++;
    }
  }
  rectMode(CENTER);
}


void draw() {
  int count2 = 0;
  int percent = round((stats[pointer%22][1]/100)*100);

  //println(stats[pointer][1],count2,conv);
  background(0);
  fill(255,0,0);
  rect(20,20,20,20);
  fill(0,0,255);
  rect(20,50,20,20);
  fill(255, 255, 255);
  textAlign(LEFT);
  textSize(16);
  text("Female",40,27);
  text("Male",40,57);
  textSize(20);
  textAlign(RIGHT);
  text("Median across the years: "+str(round(stats[pointer%22][2]))+"%",750,40);
  textAlign(CENTER);
  textSize(36);
  text(str(round(stats[pointer%22][0])), 380, 700);
  text(countryInput, 380, 100);
  stroke(10);
  text("\u2190", 200,700);
  text("\u2192", 560,700);
  for (int i = 200; i<600; i+=40) { 
    for (int j = 200; j<600; j+=40) {
      if (count2<=percent) {
        fill(255, 0, 0);
      } else {
        fill(0, 0, 255);
      }
      stroke(0);
      rect(i, j, 20, 20);

      count2++;
    }
  }
}

void keyPressed() {
  println(pointer);
  if (key==CODED) {
    if (keyCode == LEFT) {
      pointer++;
    } else if (keyCode == RIGHT) {
      if (pointer == 0) {
        pointer = 21;
      } else {
        pointer--;
      }
    }
  }
}

All the files can be downloaded from here:

https://github.com/AdhamChakohi/IntrotoIm

Mehnopoly

Disclaimer: The frustrations in the post are overblown for comedic purposes. Also I’m pretty sick and it’s 2:40 am.

For this week’s weekly assignment, the devil haunted me and told me to recreate monopoly. Kids, never listen to the devil. I only started realizing my mistake after it was too late.

So half way through this project that ended up being 350 lines of code by the way, while coding in bed blowing my nose every 5 seconds, I decided to compile a short list of other things I could’ve been doing with my life, and here it is, in no particular order:

  • Work on my social life
  • Work on my paper on the strong force
  • Procrastinate the paper on the strong force
  • Netflix

But, I digress. Perhaps my extreme unwillingness to write the paper on the strong force pushed me to write 350 lines of code for a weekly assignment. Back to the topic at hand:

Mehnopoly:

It’s mehnopoly because it’s like monopoly, but meh. Let’s go ahead and get what this game is missing out of the way first:

  • No jail system, jail currently acts like free parking
  • no houses and hotels
  • it’s limited to two players
  • chance and community chests only have 2 cards, +100 and -100.

You perform actions using the keyboard, and the game will direct you.

anyways, without further ado, Mehnopoly:

and the code that is so messy that god himself has given up on it:

//0 name, 1 type, 2 owner, 3 cost, 4 rent, 5 xcoordinate, 6 ycoordinate
// types: 0 = income tax, 1 = normal, 2 = railroad, 3 = utilities, 4 = community chest and chance, 5 = jail and free parking, 6 = go,7 = supertax
String[][] places = {
  {"Go", "6", "Bank", " ", "-200", "750", "750"}, // 0
  {"Old kent road", "1", "Bank", "60", "6", "660", "750"}, // 1
  {"Community chest", "4", "Bank", " ", "0", "595", "750"}, // 2
  {"White chapel road", "1", "Bank", "60", "6", "530", "750"}, //3
  {"Income tax", "0", "Bank", " ", "200", "465", "750"}, // 4
  {"Kings cross station", "2", "Bank", "200", "25", "400", "750"}, // 5
  {"The angel islington", "1", "Bank", "100", "10", "335", "750"}, // 6
  {"Chance", "4", "Bank", " ", "0", "270", "750"}, // 7
  {"Euston Road", "1", "Bank", "100", "10", "205", "750"}, // 8
  {"Pentonville Road", "1", "Bank", "120", "12", "140", "750"}, // 9
  {"Jail", "5", "Bank", " ", "0", "50", "750"}, // 10
  {"Pall Mall", "1", "Bank", "140", "14", "50", "660"}, // 11
  {"Electric Company", "3", "Bank", "150", "15", "50", "595"}, // 12
  {"Whitehall", "1", "Bank", "140", "14", "50", "530"}, // 13
  {"Northumberland Avenue", "1", "Bank", "160", "16", "50", "465"}, // 14
  {"Marylebone station", "2", "Bank", "200", "25", "50", "400"}, // 15
  {"Bow street", "1", "Bank", "180", "18", "50", "335"}, // 16
  {"Community chest", "4", "Bank", " ", "0", "50", "270"}, // 17
  {"Marlborough street", "1", "Bank", "180", "18", "50", "205"}, // 18
  {"Vine street", "1", "Bank", "200", "20", "50", "130"}, // 19
  {"Free Parking", "5", "Bank", " ", "0", "50", "50"}, // 20
  {"Strand", "1", "Bank", "220", "22", "140", "50"}, // 21
  {"chance", "4", "Bank", " ", "0", "205", "50"}, // 22
  {"Fleet street", "1", "Bank", "220", "22", "270", "50"}, // 23
  {"Trafalgar square", "1", "Bank", "240", "24", "335", "50"}, // 24
  {"Fenchurch st station", "2", "Bank", "200", "25", "400", "50"}, // 25
  {"Leicester square", "1", "Bank", "260", "26", "465", "50"}, // 26
  {"Coventry street", "1", "Bank", "260", "26", "530", "50"}, // 27
  {"Waterworks", "3", "Bank", "150", "15", "595", "50"}, // 28
  {"Piccadilly", "1", "Bank", "280", "28", "660", "50"}, // 29
  {"Jail", "5", "Bank", " ", "0", "750", "50"}, // 30
  {"Regent street", "1", "Bank", "300", "30", "750", "130"}, // 31
  {"Oxford street", "1", "Bank", "300", "30", "750", "205"}, // 32
  {"Community chest", "4", "Bank", " ", "0", "750", "270"}, // 34
  {"Bond street", "1", "Bank", "320", "32", "750", "335"}, // 35
  {"Marylebone station", "2", "Bank", "200", "25", "750", "400"}, // 36
  {"Chance", "4", "Bank", " ", "0", "750", "465"}, // 37
  {"Park lane", "1", "Bank", "350", "32", "750", "530"}, // 38
  {"Supertax", "7", "Bank", " ", "200", "750", "595"}, //39
  {"Mayfair", "1", "Bank", "400", "40", "750", "660"}, //40

};

boolean allowRoll = true;
int circlesize = 10;
int turn = 0;
int diceroll;
PImage bg;
boolean first = true;

// colors: red or blue
Player p1 = new Player("red", int(places[0][5]), int(places[0][6]), 10);
Player p2 = new Player("blue", int(places[0][5]), int(places[0][6]), -10);


void setup() {
  first = false;
  size(800, 800);
  bg = loadImage("board.jpg");
  background(0);
  fill(255);
  textSize(16);
  text("Welcome to mehnopoly. It's almost monopoly, but seriously lower your expectations.", 20, 50);
  text("The game is for two players. or You can play against yourself if you can't find friends. I dont judge.", 20, 100);
  text("You win by making your opponent go bankrupt. Go nuts!", 20, 150);
  text("Press S to start the game", 20, 200);
  textSize(12);
  text("Fun Fact: Monopoly was originally created as a statement against capitalism.", 20, 250);
  
}

void draw() {
  if (first) {
    textSize(24);
    fill(255, 127, 0);
    text("Player 1 has "+p1.money+" left", 150, 200);
    text("Player 2 has "+p2.money+" left", 150, 250);
    text("Player 1's turn",150,300);
    text("Press R to roll dice",150,350);
  }
}
int keycounter = 0;
void keyPressed() {
  keycounter++;
  if (keycounter == 1) first = true;
  if (keycounter == 2) first = false;
  refresh();
  // Roll dice phase
  if ((key == 'r' || key == 'R')&&allowRoll) {
    allowRoll = false;
    diceroll = rollDice();
    if (turn == 0) {
      if (p1.placecount + diceroll >= 40) {
        p1.placecount = p1.placecount+diceroll - 40;
        p1.money += 200;
      } else {
        p1.placecount+= diceroll;
      }
      p1.updatePos();
      refresh();
      checkLanded(p1);
    } else {
      if (p2.placecount + diceroll >= 40) {
        p2.placecount = p2.placecount+diceroll - 40;
        p2.money += 200;
      } else {
        p2.placecount+= diceroll;
      }
      p2.updatePos();
      refresh();
      checkLanded(p2);
    }
  }
  if ((key == 'b' || key =='B')&& !allowRoll) {
    refresh();
    if (turn == 0) {
      buy(p1);
    } else {
      buy(p2);
    }
  }

  if ((key == 'e' || key == 'E')&& !allowRoll) {
    refresh();
    endTurn();
  }

  if ((key == 'i' || key == 'I') && allowRoll) {
    fill(255, 127, 0);
    if (turn == 0) { 
      int ycounter = 200;
      for (int i = 0; i<p1.propertyamount; i++, ycounter+=50) {
        text(places[p1.properties[i]][0], 150, ycounter);
      }
    }
    if (turn == 1) {
      int ycounter = 200;
      for (int i = 0; i<p2.propertyamount; i++, ycounter+=50) {
        text(places[p2.properties[i]][0], 150, ycounter);
      }
    }
  }

  
}



class Player {
  int money, xpos, ypos, rails, utilities, offset, placecount, propertyamount;
  int[] properties = new int[50];
  String col;
  Player (String n, int xp, int yp, int off) {
    col = n;
    placecount = 0;
    money = 1500;
    offset = off;
    xpos = xp;
    ypos = yp;
    rails = 0;
    utilities = 0;
    propertyamount = 0;
  }

  void display() {
    strokeWeight(2);
    stroke(255, 255, 255);
    if (col == "red")fill(255, 0, 0);
    if (col == "blue")fill(0, 0, 255);
    ellipse(xpos+offset, ypos, circlesize, circlesize);
  }
  void updatePos() {
    xpos = int(places[placecount][5]);
    ypos = int(places[placecount][6]);
  }
}

int rollDice() {
  return round(random(1, 12));
  //return 7;
}

void checkLanded(Player x) {
  textSize(24);
  fill(255, 127, 0);
  text("You rolled "+diceroll+" and landed on: "+places[x.placecount][0], 150, 200);
  if (int(places[x.placecount][1]) == 5 || int(places[x.placecount][1]) == 6)text("Press E to end turn", 150, 250);
  // if income tax
  if (int(places[x.placecount][1]) == 0) {
    fill(255, 127, 0);
    text("You pay 200 for income tax", 150, 250);
    x.money-=200;
    text("You now have: "+str(x.money)+" left", 150, 300);
    text("Press E to end turn", 150, 350);

    // if purchasable
  } else if (int(places[x.placecount][1]) == 1 || int(places[x.placecount][1]) == 2 || int(places[x.placecount][1]) == 3) {
    // if owner is bank
    if (places[x.placecount][2] == "Bank") {
      fill(255, 127, 0);
      text("Property isn't owned, what would you like to do?", 150, 250);
      text("Press B to buy for "+places[x.placecount][3]+" or press E to end turn", 150, 300);
      // if owner is not bank
    } else {
      // if it's a normal purchasable
      if (int(places[x.placecount][1]) == 1) {
        if (turn == 0 && places[x.placecount][2] == "Player2")handleRent(p1, p2, int(places[x.placecount][4]));
        if (turn == 1 && places[x.placecount][2] == "Player1")handleRent(p2, p1, int(places[x.placecount][4]));
        // if railroad
      } else if (int(places[x.placecount][1]) == 2) {
        int rent;
        if (turn == 1 && places[x.placecount][2] == "Player1") {
          rent = checkRailRent(p1);
          handleRent(p2, p1, rent);
        } else if (turn == 0 && places[x.placecount][2] == "Player2") {
          rent = checkRailRent(p2);
          handleRent(p1, p2, rent);
        }
        // if utilities
      } else if (int(places[x.placecount][1]) == 3) {
        int rent = 0;
        if (turn == 0 && places[x.placecount][2] == "Player2") {
          if (p2.utilities == 1)rent= 7*diceroll;
          if (p2.utilities == 2)rent= 15*diceroll;
          handleRent(p1, p2, rent);
        } else if (turn == 1 && places[x.placecount][2] == "Player1") {
          if (p1.utilities == 1)rent= 7*diceroll;
          if (p1.utilities == 2)rent= 15*diceroll;
          handleRent(p2, p1, rent);
        }
      }
    }
    // super tax
  } else if (int(places[x.placecount][1]) == 7) {
    fill(255, 127, 0);
    text("You pay 100 for super tax", 150, 250);
    x.money-=200;
    text("You now have: "+str(x.money)+" left", 150, 300);
    text("Press E to end turn", 150, 350);
    //community chest and chance
  } else if (int(places[x.placecount][1]) == 4){
    int r = round(random(1,3));
    if (!(r == 2)){
      text("Jeff Bezos felt generous today, he gave you 100!",150,250);
      text("Assuming 1 = $100,000 , this amounts to",150,300);
      text("a whooping 0.0001% of his net worth",150,350);
      text("press E to end turn",150,400);
      x.money += 100;
    } else {
      text("You did some contractual work on one of",150,250);
      text("Trump's properties! He paid you a 1000!",150,300);
      text("Just kidding, he didn't pay you at all.",150,350);
      text("In fact you paid a 100 for materials.",150,400);
      text("press E to end turn",150,450);
      x.money -= 100;
    }
  }
  checkWin();
}

void checkWin() {
  if (p1.money < 0) {
    refresh();
    fill(255, 127, 0);
    text("P2 has won", 150, 200);
    noLoop();
  }
  if (p2.money < 0) {
    refresh();
    fill(255, 127, 0);
    text("P1 has won", 150, 200);
    noLoop();
  }
}

void endTurn() {
  refresh();
  fill(255, 127, 0);
  text("Player 1 has "+p1.money+" left", 150, 200);
  text("Player 2 has "+p2.money+" left", 150, 250);
  if (turn == 0) {
    fill(255, 127, 0);
    text("Player 1's turn has ended. Player 2's turn", 150, 300);
    turn = 1;
  } else {
    fill(255, 127, 0);
    text("Player 2's turn has ended. Player 1's turn", 150, 300);
    turn = 0;
  }
  text("Press R to roll or I for a list of your properties,", 150, 350);
  allowRoll = true;
  checkWin();
}


void refresh() {
  background(bg);
  p1.display();
  p2.display();
  fill(0);
  rect(100, 100,600,600);
}

void buy(Player x) {
  fill(255, 127, 0);
  if (places[x.placecount][2] == "Bank") {
    x.money -= int(places[x.placecount][3]);
    x.properties[p1.propertyamount] = x.placecount;
    x.propertyamount++;
    text(places[x.placecount][0]+" has been purchased", 150, 200);

    if (turn == 0) places[x.placecount][2] = "Player1";
    if (turn == 1) places[x.placecount][2] = "Player2";
    if (int(places[x.placecount][1]) == 2) {
      x.rails += 1;
      text("You now have "+x.rails+" railroads", 150, 250);
      text("Press E to end turn", 150, 300);
    } else if (int(places[x.placecount][1]) == 3) {
      x.utilities += 1;
      text("You now have "+x.utilities+" utilities", 150, 250);
      text("Press E to end turn", 150, 300);
    } else {
      text("Press E to end turn", 150, 250);
    }
  }
  checkWin();
}

int checkRailRent(Player x) {
  if (x.rails == 1) return x.rails*25;
  if (x.rails == 2) return x.rails*25;
  if (x.rails == 3) return 100;
  if (x.rails == 4) return 200;
  return 0;
}

void handleRent(Player renter, Player rentee, int rent) {
  renter.money -= rent;
  rentee.money += rent;
  fill(255, 127, 0);
  text("Property is owned, you have paid "+rent+" in rent", 150, 250);
  text("You have "+renter.money+" left", 150, 300);
  text("Press E to end turn", 150, 350);
  checkWin();
}

and if you, for god knows why, want to play this game, download the files from here:

https://drive.google.com/drive/folders/1DT1VFHHmSjgRkDnd0ARSmf6qXTmpuHpj?usp=sharing

Note: I haven’t rigorously tested the game, proceed at your own risk .

 

Random Squares!

For this project I chose a piece of graphic art from recodeproject.com, the website that Pierre suggested. This is actually my third attempt at recreating a picture, as the first two times I would get about 40 lines of code in and then decide that to accurately recreate the picture would just be too difficult.

Here’s the art that I found:

and Here’s what my program creates:

 

Here’s the code:

 

void setup() {
  size(800, 800);
  noFill();
  mousePressed();
}

void draw() {
}
void mousePressed() {
  background(255);
  int[] small = {20, 5};
  int[] medium = {50, 3};
  int[] large = {100, 3};
  for (int i = 0; i<int(random(100, 300)); i++) {
    int t = millis()%11;
    if (t < 5) {
      strokeWeight(small[1]);
      rect(int(random(0, width-small[0])), int(random(0, height-small[0])), small[0], small[0],3);
    } else if(t >= 5 && t<=9) {
      strokeWeight(medium[1]);
      rect(int(random(0, width-medium[0])), int(random(0, height-medium[0])), medium[0], medium[0],3);
    } else {
      strokeWeight(large[1]);
      rect(int(random(0, width-large[0])), int(random(0, height-large[0])), large[0], large[0],3);
    }
  }
  for (int i = 0; i<height-large[0]; i+=int(random(40,60))) {
    for (int j = 0; j<width-large[0]; j++) {
      if (int(random(1, 100)) == 5) {
        strokeWeight(small[1]);
        rect(j, i, small[0], small[0], 3);
      }
      if (int(random(1, 500)) == 5) {
        strokeWeight(medium[1]);
        rect(j, i, medium[0], medium[0], 3);
      }
      if (int(random(1, 700)) == 5) {
        strokeWeight(small[1]);
        rect(j, i, large[0], large[0], 3);
      }
    }
  }
  for (int i=0; i<width-large[0]; i+=int(random(40,60))) {
    for (int j = 0; j<height-large[0]; j++) {
      if (int(random(1, 100)) == 5) {
        strokeWeight(small[1]);
        rect(i, j, small[0], small[0], 3);
      }
      if (int(random(1, 500)) == 5) {
        strokeWeight(medium[1]);
        rect(i, j, medium[0], medium[0], 3);
      }
      if (int(random(1, 700)) == 5) {
        strokeWeight(large[1]);
        rect(i, j, large[0], large[0], 3);
      }
    }
  }
  
  
  
}

 

EDIT: I just updated the post. I initially didn’t notice in the picture that a lot of the squares, while seemingly randomly placed, are actually placed in a horizontal or vertical lines. So i added some logic to place some of the squares in horizontal and vertical lines.

Self portrait

My artistic abilities are, let’s just say extremely lacking. So I drew the best cartoon-looking me and decided to add some interactivity to make up for it.

To make the eyes track the cursor, I used the arctan example from processing. It uses the arctan function to calculate the angle for each eye and rotates it accordingly. And in continuation of the trend of my previous projects, there’s a scream incorporated into it when you click on the face.

code:

import ddf.minim.*;

Minim minim;
AudioPlayer player;
Eye left, right;

void setup() {
  size(400, 400);
  noStroke();
  left = new Eye(135, 150, 40);
  right = new Eye(265, 150, 40);
  minim = new Minim(this);
  player = minim.loadFile("screaming.mp3");
}

void draw() {
  background(100, 100, 100);
  fill(206, 150, 124);
  strokeWeight(1);

  ellipse(200, 200, 280, 350);

  //Hair
  line(200, 10, 200, 30);
  line(190, 10, 200, 30);
  line(180, 10, 200, 30);
  line(170, 10, 200, 30);

  //nose:
  ellipse(200, 210, 30, 30);

  // smile/frown
  if (player.isPlaying()) {
    fill(0, 0, 0);
    ellipse(200, 290, 80, 80);
    fill(204, 71, 71);
    ellipse(200, 305, 40, 40);
  } else {
    arc(200, 270, 80, 80, 0, PI);
  }
  noFill();
  //arc(200, 290, 80, 80, PI, TWO_PI);


  //glasses:
  stroke(0, 0, 0);
  strokeWeight(4);
  rect(100, 115, 70, 70);
  rect(230, 115, 70, 70);
  line(170, 150, 230, 150);
  line(100, 150, 73, 130);
  line(300, 150, 327, 130);

  //new eyes:
  left.update(mouseX, mouseY);
  right.update(mouseX, mouseY);
  left.display();
  right.display();
}

void mousePressed() {
  float x = sqrt(sq(mouseX-200)+sq(mouseY-200));
  if (x<=173) {
    player.rewind();
    player.play();
  }
}

class Eye {
  int x, y;
  int size;
  float angle = 0.0;

  Eye(int tx, int ty, int ts) {
    x = tx;
    y = ty;
    size = ts;
  }

  void update(int mx, int my) {
    angle = atan2(my-y, mx-x);
  }

  void display() {
    pushMatrix();
    translate(x, y);
    fill(255);
    ellipse(0, 0, size, size);
    rotate(angle);
    fill(0);
    ellipse(size/4, 0, size/2, size/2);
    popMatrix();
  }
}

and the screaming file:

Making Interactive Art: Set the Stage, Then Shut Up and Listen

I fully agree with what the author is saying in this reading. I believe good design does not need to be explained, it talks for itself! For example, you shouldn’t have to consult a manual to operate a blender or a shaver, you should be able to figure out how to do that without explanation. There have been too many times when a song has been ruined for me because the artist explained the meaning behind the song and it didn’t align with what I had thought the song meant!

The Stressed Out College Student

This project is a representation of the state of a stressed out college student, say during midterms or finals. If you touch it, this is what happens:

Here is a picture of the internals:

It is basically an Arduino with an mp3 shield controlling the speaker, reading from an SD card, and a motor shield stacked on top of it to control the motor. The motor shield was needed in order to change the direction of rotation of the motor in order to produce the ‘shaking’ effect. And out of the motor shield is a wire sticking out and taped to the box in order to measure capacitance, which is how I’m detecting touch.

Here’s the code:

#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <SPI.h>
#include <Adafruit_VS1053.h>
#include <SD.h>
#include "pins_arduino.h"

// These are the pins used for the music maker shield
#define SHIELD_RESET  -1      // VS1053 reset pin (unused!)
#define SHIELD_CS     7      // VS1053 chip select pin (output)
#define SHIELD_DCS    6      // VS1053 Data/command select pin (output)
#define CARDCS 4     // Card chip select pin
#define DREQ 3       // VS1053 Data request, ideally an Interrupt pin

// initialize mp3 shield
Adafruit_VS1053_FilePlayer musicPlayer = Adafruit_VS1053_FilePlayer(SHIELD_RESET, SHIELD_CS, SHIELD_DCS, DREQ, CARDCS);

// initialize motor shield
Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x60);
Adafruit_DCMotor *wheels = AFMS.getMotor(2);

int delayval = 100;
const int touchPin = A1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  AFMS.begin();
  //  wheels->setSpeed(255);
  //  wheels->run(FORWARD);
  //  wheels->run(RELEASE);
  if (! musicPlayer.begin()) { // initialise the music player
    Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
    while (1);
  }
  Serial.println(F("VS1053 found"));
  if (!SD.begin(CARDCS)) {
    Serial.println(F("SD failed, or not present"));
    while (1);  // don't do anything more
  }
  musicPlayer.setVolume(1, 1);
  musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT);
  //  Serial.println("playing music");
  //  musicPlayer.playFullFile("track001.mp3");
  //  printDirectory(SD.open("/"), 0);
}


void loop() {
  int capacitance = readCapacitivePin(touchPin);
  Serial.println(capacitance);
  if (capacitance > 5) {
    if (!musicPlayer.playingMusic) {
      musicPlayer.startPlayingFile("scream.mp3");
    }
    wheels->run(FORWARD);
    wheels->setSpeed(255);
    delay(delayval);
    wheels->run(BACKWARD);
    wheels->setSpeed(255);
    delay(delayval);
    wheels->run(FORWARD);
    wheels->setSpeed(255);
    delay(delayval);
    wheels->run(BACKWARD);
    wheels->setSpeed(255);
    delay(delayval);
    wheels->run(FORWARD);
    wheels->setSpeed(255);
    delay(delayval);
    wheels->run(BACKWARD);
    wheels->setSpeed(255);
    delay(delayval);
  } else {
    wheels->run(RELEASE);
  }
  delay(1);
}

uint8_t readCapacitivePin(int pinToMeasure) {
  // Variables used to translate from Arduino to AVR pin naming
  volatile uint8_t* port;
  volatile uint8_t* ddr;
  volatile uint8_t* pin;
  // Here we translate the input pin number from
  //  Arduino pin number to the AVR PORT, PIN, DDR,
  //  and which bit of those registers we care about.
  byte bitmask;
  port = portOutputRegister(digitalPinToPort(pinToMeasure));
  ddr = portModeRegister(digitalPinToPort(pinToMeasure));
  bitmask = digitalPinToBitMask(pinToMeasure);
  pin = portInputRegister(digitalPinToPort(pinToMeasure));
  // Discharge the pin first by setting it low and output
  *port &= ~(bitmask);
  *ddr  |= bitmask;
  delay(1);
  uint8_t SREG_old = SREG; //back up the AVR Status Register
  // Prevent the timer IRQ from disturbing our measurement
  noInterrupts();
  // Make the pin an input with the internal pull-up on
  *ddr &= ~(bitmask);
  *port |= bitmask;

  // Now see how long the pin to get pulled up. This manual unrolling of the loop
  // decreases the number of hardware cycles between each read of the pin,
  // thus increasing sensitivity.
  uint8_t cycles = 17;
  if (*pin & bitmask) {
    cycles =  0;
  }
  else if (*pin & bitmask) {
    cycles =  1;
  }
  else if (*pin & bitmask) {
    cycles =  2;
  }
  else if (*pin & bitmask) {
    cycles =  3;
  }
  else if (*pin & bitmask) {
    cycles =  4;
  }
  else if (*pin & bitmask) {
    cycles =  5;
  }
  else if (*pin & bitmask) {
    cycles =  6;
  }
  else if (*pin & bitmask) {
    cycles =  7;
  }
  else if (*pin & bitmask) {
    cycles =  8;
  }
  else if (*pin & bitmask) {
    cycles =  9;
  }
  else if (*pin & bitmask) {
    cycles = 10;
  }
  else if (*pin & bitmask) {
    cycles = 11;
  }
  else if (*pin & bitmask) {
    cycles = 12;
  }
  else if (*pin & bitmask) {
    cycles = 13;
  }
  else if (*pin & bitmask) {
    cycles = 14;
  }
  else if (*pin & bitmask) {
    cycles = 15;
  }
  else if (*pin & bitmask) {
    cycles = 16;
  }

  // End of timing-critical section; turn interrupts back on if they were on before, or leave them off if they were off before
  SREG = SREG_old;

  // Discharge the pin again by setting it low and output
  //  It's important to leave the pins low if you want to
  //  be able to touch more than 1 sensor at a time - if
  //  the sensor is left pulled high, when you touch
  //  two sensors, your body will transfer the charge between
  //  sensors.
  *port &= ~(bitmask);
  *ddr  |= bitmask;

  return cycles;
}