#include "SPI.h"
#include <Tone.h>
#include <Wire.h>
#include "Adafruit_WS2801.h"
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
Adafruit_7segment matrix = Adafruit_7segment();
// Define pin numbers for each device
// a is left side, b right side
#define abutton 2
#define bbutton 8
#define switch1 3 // fast rainbow
#define switch2 12 // slow rainbow
#define switch3 5 // fast moving rainbow
#define switch4 6 // slow moving rainbow
#define switch5 9 // harder game switch
#define mute 4 // mute switch
#define pot 0 //analog pin
uint8_t SPEAKER = 7;
//for reference in hooking up, not used as they are hardware spi pins
//int dataPin = 11;
//int clockPin = 13;
// TWI (I2C) pins
// datapin = A4
// clockpin = A5
//color list for random color generation
#define numColors 128
int randColors[numColors][3] =
{
{127,0,0},//red
{127,127,0},//yellow
{0,127,0},//green
{0,127,127},//cyan
{0,0,127},//blue
{127,0,127},//violet
{100,100,10},//light blue
{165,42,42},
{178,34,34},
{220,20,60},
{255,99,71},
{255,127,80},
{205,92,92},
{240,128,128},
{233,150,122},
{250,128,114},
{255,160,122},
{255,69,0},
{255,140,0},
{255,165,0},
{255,215,0},
{184,134,11},
{218,165,32},
{238,232,170},
{189,183,107},
{240,230,140},
{128,128,0},
{255,255,0},
{154,205,50},
{85,107,47},
{107,142,35},
{124,252,0},
{127,255,0},
{173,255,47},
{34,139,34},
{50,205,50},
{144,238,144},
{152,251,152},
{143,188,143},
{0,250,154},
{0,255,127},
{46,139,87},
{102,205,170},
{60,179,113},
{32,178,170},
{47,79,79},
{0,128,128},
{0,139,139},
{0,255,255},
{0,255,255},
{224,255,255},
{0,206,209},
{64,224,208},
{72,209,204},
{175,238,238},
{127,255,212},
{176,224,230},
{95,158,160},
{70,130,180},
{100,149,237},
{0,191,255},
{30,144,255},
{173,216,230},
{135,206,235},
{135,206,250},
{25,25,112},
{65,105,225},
{138,43,226},
{75,0,130},
{72,61,139},
{106,90,205},
{123,104,238},
{147,112,219},
{139,0,139},
{148,0,211},
{153,50,204},
{186,85,211},
{128,0,128},
{216,191,216},
{221,160,221},
{238,130,238},
{255,0,255},
{218,112,214},
{199,21,133},
{219,112,147},
{255,20,147},
{255,105,180},
{255,182,193},
{255,192,203},
{250,235,215},
{245,245,220},
{255,228,196},
{255,235,205},
{245,222,179},
{255,248,220},
{255,250,205},
{250,250,210},
{255,255,224},
{139,69,19},
{160,82,45},
{210,105,30},
{205,133,63},
{244,164,96},
{222,184,135},
{210,180,140},
{188,143,143},
{255,228,181},
{255,222,173},
{255,218,185},
{255,228,225},
{255,240,245},
{250,240,230},
{253,245,230},
{255,239,213},
{255,245,238},
{245,255,250},
{112,128,144},
{119,136,153},
{176,196,222},
{230,230,250},
{255,250,240},
{240,248,255},
{248,248,255},
{240,255,240},
{255,255,240},
{240,255,255},
{255,250,250},
{128,128,128},
};
// Define notes for win music
// start at A below middle C
// Musical notes are defined differently in tone.h, that's why I had to included these here
#define NOTE_Ab 207.652
#define NOTE_A 220.000
#define NOTE_As 233.082
#define NOTE_Bb NOTE_As
#define NOTE_B 246.942
#define NOTE_C 261.626
#define NOTE_Cs 277.183
#define NOTE_Db NOTE_Cs
#define NOTE_D 293.665
#define NOTE_Ds 311.127
#define NOTE_Eb NOTE_Ds
#define NOTE_E 329.628
#define NOTE_F 349.228
#define NOTE_Fs 369.994
#define NOTE_Gb NOTE_Fs
#define NOTE_G 391.995
#define NOTE_Gs 415.305
#define NOTE_REST 0.0
#define NOTE_SUSTAIN -1.0
// Part of Bach 2-part invention #4 in D minor
// http://www.8notes.com/scores/2791.asp
int tempo = 150;
float composition[] = {
NOTE_D, NOTE_E, NOTE_F, NOTE_G, NOTE_A*2, NOTE_As*2,
NOTE_Db, NOTE_As*2, NOTE_A*2, NOTE_G, NOTE_F, NOTE_E,
NOTE_F, NOTE_REST, NOTE_A*2, NOTE_REST, NOTE_D*2, NOTE_REST,
NOTE_G, NOTE_REST, NOTE_Cs*2, NOTE_REST, NOTE_E*2, NOTE_REST,
NOTE_D*2, NOTE_E*2, NOTE_F*2, NOTE_G*2, NOTE_A*4, NOTE_As*4,
NOTE_Db*2, NOTE_As*4, NOTE_A*4, NOTE_G*2, NOTE_F*2, NOTE_E*2,
};
// uses a non standard tone library
// http://code.google.com/p/rogue-code/wiki/ToneLibraryDocumentation
Tone tone1;
// flags
// N: new game, i.e first time plugged in
// S: same game, each round is still same game
// R: right
// L: left
char flag = 'N';
char turn = 'A';
char cheat = 'N';
int winningscore = 12;
int nLEDs = 32;
int maxdelay = 60;//35
int mindelay = 18;
int i = 0;
int j = 0;
byte abuttonPoints = 0;
byte bbuttonPoints = 0;
// ball speed variables
byte ballSpeed = 0;
byte ballSpeedIncrease = 0;
int ballInitialSpeed = 0;
// how far away you can hit the button without missing is one less than this
// e.g. if bz=5 then you have to hit within five pixels of the edge
int normalbounce = 5;
int reducedbounce = 3;
int bouncezone = normalbounce;
// define strip, mine uses ws2801 chips, require ws2801 library
// https://github.com/adafruit/Adafruit-WS2801-Library
Adafruit_WS2801 strip = Adafruit_WS2801(nLEDs);
/* Helper functions for RGB strip colors */
// Create a 24 bit color ballInitialSpeedue from R,G,B
uint32_t Color(byte r, byte g, byte b)
{
uint32_t c;
c = r;
c <<= 8;
c |= g;
c <<= 8;
c |= b;
return c;
}
//Input a value 0 to 255 to get a color value.
//The colors are a transition r - g -b - back to r
uint32_t Wheel(byte WheelPos)
{
if (WheelPos < 85) {
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if (WheelPos < 170) {
WheelPos -= 85;
return Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
void setup()
{
//assign buttons
pinMode(abutton, INPUT);
pinMode(bbutton, INPUT);
pinMode(switch1, INPUT);
pinMode(mute, INPUT);
pinMode(SPEAKER, OUTPUT);
//initialize speaker
tone1.begin(SPEAKER);
//initialize LED strip
strip.begin();
// Update LED contents, to start they are all 'off'
strip.show();
//initalize 7 segment LED
matrix.begin(0x70);
randomSeed(analogRead(1));
}
void loop()
{
// points display code
if (abuttonPoints <= 9)
{
matrix.writeDigitNum(1, abuttonPoints);
matrix.writeDigitNum(0, 0);
}
else
{
int temp = abuttonPoints-10;
if (temp==0)
{
matrix.writeDigitNum(1, 0);
}
else
{
matrix.writeDigitNum(1, abuttonPoints-10);
}
matrix.writeDigitNum(0, 1);
}
matrix.drawColon(true);
if (bbuttonPoints <= 9)
{
matrix.writeDigitNum(4, bbuttonPoints);
matrix.writeDigitNum(3, 0);
}
else
{
int temp = bbuttonPoints-10;
if (temp==0)
{
matrix.writeDigitNum(4, 0);
}
else
{
matrix.writeDigitNum(4, bbuttonPoints-10);
}
matrix.writeDigitNum(3, 1);
}
matrix.writeDisplay();
// switch for light show - all color rainbow fast
if (digitalRead(switch1) == HIGH)
{
rainbow(5);
// set strip off for new game
for(i=0; i < nLEDs; i++) strip.setPixelColor(i, 0);
strip.show();
}
// switch for light show - all color rainbow slow
if (digitalRead(switch2) == HIGH)
{
rainbow(25);
// set strip off for new game
for(i=0; i < nLEDs; i++) strip.setPixelColor(i, 0);
strip.show();
}
// switch for light show - moving rainbow - fast
if (digitalRead(switch3) == HIGH)
{
rainbowCycleabutton(0);
}
// switch for light show - moving rainbow - slow
if (digitalRead(switch4) == HIGH)
{
rainbowCyclebbutton(5);
}
// switch for harder game - reduce bounce zone
if (digitalRead(switch5) == HIGH)
{
bouncezone = reducedbounce;
}
if (digitalRead(switch5) == LOW)
{
bouncezone = normalbounce;
}
// a wins
if(abuttonPoints > winningscore)
{
// reset speed increase conuter
ballSpeedIncrease = 0;
// light show
abuttonCelebrate();
}
// b wins
if(bbuttonPoints > winningscore)
{
// reset speed increase conuter
ballSpeedIncrease = 0;
// light show
bbuttonCelebrate();
}
// flag starts as N
// set pixel light for player who's turn it is
// this runs once, the first time the game is plugged in
if(flag == 'N' && turn == 'A')
{
strip.setPixelColor(0, Color(100, 100, 10));
strip.show();
}
if(flag == 'N' && turn == 'B')
{
strip.setPixelColor(nLEDs-1, Color(100, 100, 10));
strip.show();
}
// pot is being read anytime the ball is not moving
if(flag != 'R' && flag != 'L')
{
ballInitialSpeed = analogRead(pot);
ballInitialSpeed = map(ballInitialSpeed, 0, 1023, mindelay, maxdelay);
ballSpeed = ballInitialSpeed - ballSpeedIncrease;
}
// flag == right
if(flag == 'R')
{
// increase ball speed by reducing delay
ballSpeedIncrease += 1;
ballSpeed = ballInitialSpeed - ballSpeedIncrease;
if(ballSpeed < 0)
ballSpeed = 0;
if(ballSpeed > maxdelay)
ballSpeed = maxdelay;
// play tick sound
if(digitalRead(mute) == LOW)
{
tone1.play(NOTE_F5, 50);
}
delay(50);
int rand = random(0,numColors+1);
// random color ball goes to the right
chaseRight(Color(randColors[rand][1], randColors[rand][2], randColors[rand][3]), ballSpeed);
}
// flag = left
if(flag == 'L')
{
// increase ball speed by reducing delay
ballSpeedIncrease += 1;
ballSpeed = ballInitialSpeed - ballSpeedIncrease;
if(ballSpeed < 0)
ballSpeed = 0;
if(ballSpeed > maxdelay)
ballSpeed = maxdelay;
if(digitalRead(mute) == LOW)
{
tone1.play(NOTE_F5, 50);
}
delay(50);
int rand = random(0,numColors+1);
// random color ball goes to the left
chaseLeft(Color(randColors[rand][1], randColors[rand][2], randColors[rand][3]), ballSpeed);
}
int AbuttonState = digitalRead(abutton);
if(AbuttonState == HIGH && turn == 'A' && flag != 'R' && flag != 'L')
{
ballSpeed = ballInitialSpeed;
ballSpeedIncrease = 0;
i = 0;
int rand = random(0,numColors+1);
// random color ball goes to the right
chaseRight(Color(randColors[rand][1], randColors[rand][2], randColors[rand][3]), ballSpeed);
}
int BbuttonState = digitalRead(bbutton);
if(BbuttonState == HIGH && turn == 'B' && flag != 'R' && flag != 'L')
{
ballSpeed = ballInitialSpeed;
ballSpeedIncrease = 0;
i = nLEDs;
int rand = random(0,numColors+1);
// random color ball goes to the left
chaseLeft(Color(randColors[rand][1], randColors[rand][2], randColors[rand][3]), ballSpeed);
}
}
void win_music()
{
unsigned long note = composition[i];
for (i=1; i<37 ; i++)
{
unsigned long note = composition[i];
if (note == NOTE_REST)
tone1.stop();
else if (note == NOTE_SUSTAIN)
; // Don't do anything, just let the current tone continue
else
tone1.play(note);
delay(tempo);
}
}
void chaseRight(uint32_t c, uint8_t wait)
{
for(i; i < nLEDs; i++)
{
if(digitalRead(bbutton) == HIGH)
{
cheat = 'Y';
if(digitalRead(mute) == LOW)
{
tone1.play(NOTE_F3,150);
}
}
strip.setPixelColor(i, c); // Set new pixel 'on'
strip.show(); // Refresh LED states
strip.setPixelColor(i, 0); // Erase pixel, but don't refresh!
delay(wait);
if(i > nLEDs-bouncezone-1 && cheat != 'Y')
{
int BbuttonState = digitalRead(bbutton);
if(BbuttonState == HIGH)
{
turn = 'B';
flag = 'L';
return;
}
}
}
abuttonPoints++;
if(abuttonPoints <= winningscore)
strip.show();
if(digitalRead(mute) == LOW)
{
tone1.play(NOTE_B3, 500);
}
delay(500);
flag = 'S';
cheat = 'N';
// set light at player a side
strip.setPixelColor(0, Color(100, 100, 10));
strip.show();
}
void chaseLeft(uint32_t c, uint8_t wait)
{
for(i; i >= 0; i--)
{
if(digitalRead(abutton) == HIGH)
{
cheat = 'Y';
if(digitalRead(mute) == LOW)
{
tone1.play(NOTE_F3,150);
}
}
strip.setPixelColor(i, c); // Set new pixel 'on'
strip.show(); // Refresh LED states
strip.setPixelColor(i, 0); // Erase pixel, but don't refresh!
delay(wait);
if(i < bouncezone && cheat != 'Y')
{
int AbuttonState = digitalRead(abutton);
if(AbuttonState == HIGH)
{
//i = 0;
turn = 'A';
flag = 'R';
return;
}
}
}
bbuttonPoints++;
strip.show();
if(bbuttonPoints <= winningscore)
// play lose point sound
if(digitalRead(mute) == LOW)
{
tone1.play(NOTE_B3, 500);
}
delay(500);
flag = 'S';
cheat = 'N';
// set light at player b side
strip.setPixelColor(nLEDs-1, Color(100, 100, 10));
strip.show();
}
void abuttonCelebrate()
{
abuttonPoints = 0;
bbuttonPoints = 0;
if(digitalRead(mute) == LOW)
{
win_music();
}
colorWipeLeft(Color(255, 0, 0), 20);
colorWipeLeft(Color(0, 255, 0), 20);
colorWipeLeft(Color(0, 0, 255), 20);
rainbowCycleabutton(0);
flag = 'N';
turn = 'B';
}
void bbuttonCelebrate()
{
abuttonPoints = 0;
bbuttonPoints = 0;
if(digitalRead(mute) == LOW)
{
win_music();
}
colorWipeRight(Color(255, 0, 0), 20);
colorWipeRight(Color(0, 255, 0), 20);
colorWipeRight(Color(0, 0, 255), 20);
rainbowCyclebbutton(0);
flag = 'N';
turn = 'A';
}
void rainbowCycleabutton(uint8_t wait) {
int m = nLEDs;
uint16_t k, j;
for (j=0; j < 384 * 3; j++) { // 5 cycles of all 384 colors in the Wheel
for (k=0; k < strip.numPixels(); k++) {
// tricky math! we use each pixel as a fraction of the full 384-color Wheel
// (thats the i / strip.numPixels() part)
// Then add in j which makes the colors go around per pixel
// the % 384 is to make the Wheel cycle around
strip.setPixelColor(k, Wheel( ((k * 384 / strip.numPixels()) + j) % 384) );
}
strip.show(); // write all the pixels out
delay(wait);
}
for(m; m >= 0; m--)
{
strip.setPixelColor(m, 0);
strip.show();
}
}
void rainbowCyclebbutton(uint8_t wait) {
int m = 0;
uint16_t k, j;
for (j=384 * 3; j > 0; j--) { // 5 cycles of all 384 colors in the Wheel
for (k=0; k < strip.numPixels(); k++) {
// tricky math! we use each pixel as a fraction of the full 384-color Wheel
// (thats the i / strip.numPixels() part)
// Then add in j which makes the colors go around per pixel
// the % 384 is to make the Wheel cycle around
strip.setPixelColor(k, Wheel( ((k * 384 / strip.numPixels()) + j) % 384) );
}
strip.show(); // write all the pixels out
delay(wait);
}
for(m; m < nLEDs; m++)
{
strip.setPixelColor(m, 0);
strip.show();
}
}
void rainbow(uint8_t wait) {
int i, j;
for (j=0; j < 256; j++) { // 3 cycles of all 256 colors in the Wheel
for (i=0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel( (i + j) % 255));
}
strip.show(); // write all the pixels out
delay(wait);
}
}
// fill the dots one after the other with said color
// good for testing purposes
// goes to the right
void colorWipeRight(uint32_t c, uint8_t wait)
{
for (int i=0; i < strip.numPixels(); i++)
{
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
void colorWipeLeft(uint32_t c, uint8_t wait)
{
for (i=nLEDs; i > 0; i--)
{
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}