Skip to content

Instantly share code, notes, and snippets.

@zuk
Created August 29, 2012 16:31
Show Gist options
  • Select an option

  • Save zuk/3515280 to your computer and use it in GitHub Desktop.

Select an option

Save zuk/3515280 to your computer and use it in GitHub Desktop.
rock_paper_awesome
#include <stdio.h>
#define SERIAL_BAUDRATE 9600
#define MILLISECONDS_PER_FRAME 30
// the pins that control the brightness of RED, GREEN, and BLUE LEDs respectively
#define R 9
#define G 10
#define B 11
// pins that receive input for ROCK, PAPER, and SCISSOR
#define PIN_ROCK 3
#define PIN_PAPER 4
#define PIN_SCISSORS 5
// PROTOCOL
// >> incoming messages from node over serialport
#define PROT_ONLINE '@' // you are now online
#define PROT_OFFLINE '#' // you are now offline
#define PROT_NEW_GAME 'N' // sent by node to indicate that we're starting a new game
#define PROT_THEY_CHOSE_ROCK 'R'
#define PROT_THEY_CHOSE_PAPER 'P'
#define PROT_THEY_CHOSE_SCISSORS 'S'
#define PROT_WAITING_FOR_YOU ':'
#define PROT_WAITING_FOR_THEM ';'
#define PROT_YOU_WON '+'
#define PROT_YOU_LOST '-'
#define PROT_TIE '='
// << outgoing messages to node over serialport
#define PROT_ARDUINO_READY '~' // sent to daemon to signal that the arduino is ready
#define PROT_YOU_CHOSE_ROCK 'r'
#define PROT_YOU_CHOSE_PAPER 'p'
#define PROT_YOU_CHOSE_SCISSORS 's'
#define PROT_READY_FOR_NEW_GAME 'n' // sent to daemon to signal that the arduino is ready for a new game
// states
#define STATE_OFFLINE 0
#define STATE_WAITING_FOR_EITHER_CHOICE 1
#define STATE_WAITING_FOR_YOUR_CHOICE 2
#define STATE_WAITING_FOR_THEIR_CHOICE 3
#define STATE_WAITING_FOR_GAME_OVER_CONFIRMATION 4
// LED modes
#define LED_MODE_STEADY 0
#define LED_MODE_FADE 1
#define LED_MODE_BLINK 2
#define LED_MODE_PULSATE 3
char state = STATE_OFFLINE;
char yourChoice = NULL;
char theirChoice = NULL;
// set to true once the choice has been reset -- used to prevent double-triggering when button is held down
bool choiceWasReset = false;
long frameCount = 0;
byte cR, cG, cB; // current values of the red, green, and blue LEDs
byte tR, tG, tB; // target values of the LEDs (when fading/blinking/pulsating)
int rR, rG, rB = 0; // rate at which the LEDs should change per frame (has different meaning for fading, pulsating, and blinking)
byte mR, mG, mB = LED_MODE_STEADY; // the current mode for each LED (steady, fading, blinking, pulsating, etc.)
void setup() {
pinMode(R, OUTPUT);
pinMode(G, OUTPUT);
pinMode(B, OUTPUT);
digitalWrite(PIN_ROCK, LOW);
digitalWrite(PIN_PAPER, LOW);
digitalWrite(PIN_SCISSORS, LOW);
pinMode(PIN_ROCK, INPUT);
pinMode(PIN_PAPER, INPUT);
pinMode(PIN_SCISSORS, INPUT);
setRGB(0,0,0);
Serial.begin(SERIAL_BAUDRATE);
Serial.print(PROT_ARDUINO_READY); // tell the daemon that we're ready
}
void loop() {
if (millis() % MILLISECONDS_PER_FRAME == 0) {
rgbFrame();
frameCount++;
// TODO: use interrupt timer for this instead
// (see http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/
// and http://www.arduino.cc/playground/code/timer1)
}
if (state == STATE_WAITING_FOR_EITHER_CHOICE || state == STATE_WAITING_FOR_YOUR_CHOICE) {
if (digitalRead(PIN_ROCK) == HIGH)
youChose(PROT_YOU_CHOSE_ROCK);
else if (digitalRead(PIN_PAPER) == HIGH)
youChose(PROT_YOU_CHOSE_PAPER);
else if (digitalRead(PIN_SCISSORS) == HIGH)
youChose(PROT_YOU_CHOSE_SCISSORS);
} else if (state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION) {
if (digitalRead(PIN_ROCK) == LOW && yourChoice == PROT_YOU_CHOSE_ROCK
|| digitalRead(PIN_PAPER) == LOW && yourChoice == PROT_YOU_CHOSE_PAPER
|| digitalRead(PIN_SCISSORS) == LOW && yourChoice == PROT_YOU_CHOSE_SCISSORS) {
choiceWasReset = true;
}
if (choiceWasReset && (digitalRead(PIN_ROCK) == HIGH || digitalRead(PIN_PAPER) == HIGH || digitalRead(PIN_SCISSORS))) {
choiceWasReset = false;
readyForNewGame();
}
}
if (Serial.available() > 0) {
in(Serial.read());
}
}
// called for each incoming character from the serialport
void in(char c) {
switch (c) {
case PROT_ONLINE:
online();
break;
case PROT_OFFLINE:
offline();
break;
case PROT_THEY_CHOSE_ROCK:
case PROT_THEY_CHOSE_PAPER:
case PROT_THEY_CHOSE_SCISSORS:
theyChose(c);
break;
case PROT_WAITING_FOR_YOU:
waitingForYou();
break;
case PROT_WAITING_FOR_THEM:
waitingForThem();
break;
case PROT_YOU_WON:
youWin();
break;
case PROT_YOU_LOST:
youLose();
break;
case PROT_TIE:
tie();
break;
case PROT_NEW_GAME:
tie();
break;
}
}
// called when online
void online() {
pulsate(25, 150, &tG, &rG, &mG);
state = STATE_WAITING_FOR_EITHER_CHOICE;
}
// called when offline
void offline() {
pulsate(20, 150, &tR, &rR, &mR);
state = STATE_OFFLINE;
}
// called when you chose rock, paper, or scissors
void youChose(char choice) {
yourChoice = choice;
switch(choice) {
case PROT_YOU_CHOSE_ROCK:
setR(255);
break;
case PROT_YOU_CHOSE_PAPER:
setG(255);
break;
case PROT_YOU_CHOSE_SCISSORS:
setB(255);
break;
}
Serial.print(choice);
}
// called when they chose rock, paper, or scissors
void theyChose(char choice) {
theirChoice = choice;
}
// called when waiting for you to make a choice
void waitingForYou() {
setG(0);
blink(255, 10, &tG, &rG, &mG);
}
// called when waiting for them to make a choice
void waitingForThem() {
setB(0);
pulsate(255, 250, &tB, &rB, &mB);
}
void youWin() {
pulsate(255, 5, &tG, &rG, &mG);
state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION;
}
void youLose() {
pulsate(255, 5, &tR, &rR, &mR);
state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION;
}
void tie() {
pulsate(100, 5, &tG, &rG, &mG);
pulsate(100, 5, &tR, &rR, &mR);
state = STATE_WAITING_FOR_GAME_OVER_CONFIRMATION;
}
void readyForNewGame() {
Serial.print(PROT_READY_FOR_NEW_GAME);
}
void newGame() {
theirChoice = NULL;
yourChoice = NULL;
state = STATE_WAITING_FOR_EITHER_CHOICE;
// TODO: do some blinky stuff here
//delay(2000); // wait 2 seconds before listening for other signals... otherwise we might catch a button held down too long
}
// called whenever a "frame" for red, green, and blue leds should be rendered
void rgbFrame() {
char state[32];
sprintf(state, "c:%02x%02x%02x t:%02x%02x%02x r:%02x%02x%02x m:%02x%02x%02x", // current target rate mode
cR, cG, cB, tR, tG, tB, rR, rG, rB, mR, mG, mB);
Serial.println(state);
frame(R, &cR, &tR, &rR, &mR);
frame(G, &cG, &tG, &rG, &mG);
frame(B, &cB, &tB, &rB, &mB);
}
// called to render a frame for any one of the leds
// led: the LED pin we're rendering a frame for
// *current: reference to a c_ variable
// *target: reference to a t_ variable
// *rate: reference to a r_ variable
// *mode: reference to a m_ variable
void frame(int led, byte *current, byte *target, int *rate, byte *mode) {
switch (*mode) {
case LED_MODE_STEADY:
if (*current != *target)
*current = *target;
break;
case LED_MODE_BLINK:
if ((frameCount % (*rate * 2)) > *rate)
*current = *target;
else
*current = 0;
analogWrite(led, *current);
break;
case LED_MODE_FADE:
if (*current == *target)
return;
else if (*current < *target)
*current = ((*current + *rate) > *target) ? *target : *current + *rate;
else if (*current > *target)
*current = ((*current - *rate) < *target) ? *target : *current - *rate;
analogWrite(led, convertRGBval(*current));
break;
case LED_MODE_PULSATE:
float val = (frameCount % *rate) / (float) *rate;
*current = (*target / 2) + ((*target / 2.0) * sin(val * 2.0 * PI));
analogWrite(led, convertRGBval(*current));
break;
}
}
// does any necessary transformation from a LED value to the value that should be written to the pin (using analogWrite)
byte convertRGBval(byte val) {
// due to the way my LEDs are wired, my pin values are inverted, so for me 0 == maximum, 255 == minimum
// get rid of the "255-" for yours to revert to normal usage
return 255-val;
}
// immediatley set the RED led to the given brightness; sets the mode to LED_MODE_STEADY
void setR(byte val) {
analogWrite(R, convertRGBval(val));
cR = val;
tR = val;
mR = LED_MODE_STEADY;
}
// immediatley set the GREEN led to the given brightness; sets the mode to LED_MODE_STEADY
void setG(byte val) {
analogWrite(G, convertRGBval(val));
cG = val;
tG = val;
mG = LED_MODE_STEADY;
}
// immediatley set the BLUE led to the given brightness; sets the mode to LED_MODE_STEADY
void setB(byte val) {
analogWrite(B, convertRGBval(val));
cB = val;
tB = val;
mB = LED_MODE_STEADY;
}
// immediatley set the RED, GREEN, and BLUE leds to the given brightness; sets their modes to LED_MODE_STEADY
void setRGB(byte r, byte g, byte b) {
setR(r); setG(g); setB(b);
}
// fade the given pin to the given value at the specified rate
// to: value that we should fade towards
// rate: rate that we should fade at (higher rate means faster fade)
// *t: reference to the t_ variable for the LED we want to fade
// *r: reference to the r_ variable for the LED we want to fade
// *m: reference to the m_ variable for the LED we want to fdae
void fade(byte to, int rate, byte *t, int *r, byte *m) {
*t = to;
*r = rate;
*m = LED_MODE_FADE;
}
// pulsate the given pin at the specified rate
// max: the maximum brightness for the pulse (minimum is always 0)
// period: the speed at which we should pulsate (higher period means slower pulse)
// *t: reference to the t_ variable for the LED we want to pulsate
// *r: reference to the r_ variable for the LED we want to pulsate
// *m: reference to the m_ variable for the LED we want to pulsate
void pulsate(byte max, int rate, byte *t, int *r, byte *m) {
*t = max;
*r = rate;
*m = LED_MODE_PULSATE;
}
// blink the given pin tat the specified rate
// max: the maximum brightness -- i.e. the "on" value ("off" value is always 0)
// rate: rate that we should blink at (higher rate means faster blinking)
// *t: reference to the t_ variable for the LED we want to blink
// *r: reference to the r_ variable for the LED we want to blink
// *m: reference to the m_ variable for the LED we want to blink
void blink(byte max, int rate, byte *t, int *r, byte *m) {
*t = max;
*r = rate;
*m = LED_MODE_BLINK;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment