#include "LPD8806.h"

#include "SPI.h"

/*

* battle thing

*

* Hook up two pushbuttons with pullup resistors to the pins listed below

* you can also hook up a piezo buzzer to pin 9 if you want sound effects

* the principal of the game is a little green ball that goes back and forth

* down the strip. you need to hit your button to switch directions when the ball

* gets to your end. if you don't there's an explosion.

* djweis@sjdjweis.com

*/

#define NUM_LEDS 240

#define PIN_DATA 2

#define PIN_CLOCK 3

#define PLAYER1_IN 4 // digital

#define PLAYER2_IN 5 // digital

#define PIEZO_OUT 9 // digital

int delay_time = 10 ;

LPD8806 strip = LPD8806 ( NUM_LEDS, PIN_DATA, PIN_CLOCK ) ;

uint32_t COLOR_BLACK = strip. Color ( 0 , 0 , 0 ) ;

uint32_t COLOR_YELLOW = strip. Color ( 80 , 0 , 80 ) ;

// which direction is the ball moving

#define DIRECTION_ASCENDING 1

#define DIRECTION_DESCENDING 2

#define WARNING_ZONE_LENGTH 8

// where is the ball

byte position ;

// which direction is it heading?

byte direction ;

/*

* called on start and after an explosion

*/

void start_game ( )

{

// default ball to middle of board

position = ( NUM_LEDS / 2 ) ;

// set default direction

// direction = DIRECTION_DESCENDING;

direction = DIRECTION_ASCENDING ;

strip. begin ( ) ;

// black out the board again

for ( int i = 0 ; i < NUM_LEDS ; i ++ ) {

strip. setPixelColor ( i, strip. Color ( 0 , 0 , 0 ) ) ;

}

draw_warning_zones ( ) ;

strip. show ( ) ;

}

void draw_warning_zones ( )

{

// warning zones

for ( int i = 0 ; i < WARNING_ZONE_LENGTH ; i ++ ) {

strip. setPixelColor ( i, COLOR_YELLOW ) ;

}

for ( int i = NUM_LEDS ; i >= NUM_LEDS - WARNING_ZONE_LENGTH ; i -- ) {

strip. setPixelColor ( i, COLOR_YELLOW ) ;

}

}

/*

* the explosion takes 1/4 of the led's on the losing

* player's side. we increase them as red from the end of

* the strip showing as we grow, then make every other one

* black and show.

*/

void explode ( )

{

byte start_pos, end_pos ;

byte led ;

if ( DIRECTION_DESCENDING == direction ) {

start_pos = 0 ;

end_pos = NUM_LEDS / 4 ;

// red fill

for ( led = start_pos ; led < end_pos ; led ++ ) {

strip. setPixelColor ( led, strip. Color ( 127 , 0 , 0 ) ) ;

strip. show ( ) ;

}

// alternate black

for ( led = start_pos ; led < end_pos ; led + = 2 ) {

strip. setPixelColor ( led, strip. Color ( 0 , 0 , 0 ) ) ;

strip. show ( ) ;

}

// black fill

for ( led = end_pos ; led > start_pos ; led -- ) {

strip. setPixelColor ( led, strip. Color ( 0 , 0 , 0 ) ) ;

strip. show ( ) ;

}

} else {

start_pos = NUM_LEDS ;

end_pos = NUM_LEDS - ( NUM_LEDS / 4 ) ;

for ( led = start_pos ; led > end_pos ; led -- ) {

strip. setPixelColor ( led, strip. Color ( 127 , 0 , 0 ) ) ;

strip. show ( ) ;

}

for ( led = start_pos ; led > end_pos ; led - = 2 ) {

strip. setPixelColor ( led, strip. Color ( 0 , 0 , 0 ) ) ;

strip. show ( ) ;

}

// black fill

for ( led = end_pos ; led <= start_pos ; led ++ ) {

strip. setPixelColor ( led, strip. Color ( 0 , 0 , 0 ) ) ;

strip. show ( ) ;

}

}

#if 0

tone ( PIEZO_OUT, 440 , 200 ) ;

delay ( 300 ) ;

tone ( PIEZO_OUT, 300 , 200 ) ;

delay ( 300 ) ;

tone ( PIEZO_OUT, 200 , 400 ) ;

delay ( 500 ) ;

#endif

}

/*

* warning zone is considered the last 6 LED's before the end

*/

byte in_warning_zone ( )

{

byte retval = 0 ;

if ( ( DIRECTION_ASCENDING == direction ) &&

( position >= ( NUM_LEDS - WARNING_ZONE_LENGTH ) ) ) {

retval = 1 ;

}

if ( ( DIRECTION_DESCENDING == direction ) &&

( position <= WARNING_ZONE_LENGTH ) ) {

retval = 1 ;

}

return retval ;

}

void setup ( )

{

pinMode ( PLAYER1_IN, INPUT ) ;

pinMode ( PLAYER2_IN, INPUT ) ;

pinMode ( PIEZO_OUT, OUTPUT ) ;

calibrate_delay_time ( ) ;

start_game ( ) ;

tone ( PIEZO_OUT, 440 , 1000 ) ;

delay ( 1000 ) ;

}

void loop ( )

{

// grab the button status at the beginning

byte button1 = digitalRead ( PLAYER1_IN ) ;

byte button2 = digitalRead ( PLAYER2_IN ) ;

// normal movement somewhere else on the play field

byte old_position = position ;

if ( DIRECTION_ASCENDING == direction ) {

position ++ ;

} else {

position -- ;

}

draw_warning_zones ( ) ;

strip. setPixelColor ( old_position, strip. Color ( 0 , 0 , 0 ) ) ;

strip. setPixelColor ( position, strip. Color ( 0 , 0 , 127 ) ) ;

strip. show ( ) ;

if ( ( position == 0 ) ||

( position == NUM_LEDS ) ) {

// hit end of track with no button

// boom

explode ( ) ;

// start over

start_game ( ) ;

} else if ( in_warning_zone ( ) ) {

// need to check for button press and reverse direction

// check for proper button being pressed

if ( ( DIRECTION_ASCENDING == direction ) &&

( LOW == button1 ) ) {

direction = DIRECTION_DESCENDING ;

} else if ( ( DIRECTION_DESCENDING == direction ) &&

( LOW == button2 ) ) {

direction = DIRECTION_ASCENDING ;

} // direction/button check

} // big loop if check

// wait for next cycle

// delay(5);