# Game On!

Figure 2 - Game Circuit

As well as being fun, this game also ties in a lot of useful programming techniques.  Essentially, there are three main “things” we want our program to do: display the color sequence, save the colors shown, and check user response.  Since we want the program to keep executing these main tasks indefinitely, the use of subroutines is perfect here.  Our main loop will check if the youLose flag has been set, and depending on if the flag has been set or not, will cycle through three subroutines:

• Begin_Game
• This subroutine will reset all values to zero and display and save the first pseudo-random color.  It will be used when the player first starts the game, or whenever he or she loses.
• Check_Response
• This subroutine checks the player’s response and sets the youLose flag equal to 1 when the response doesn’t match the color sequence.  If the player’s response is correct, this subroutine will add one to the round number count.
• Next_Round
• This subroutine will display the previously saved color sequence and add another color to the chain.

## EEPROM Color Memory

In order to save the color sequence, we’ll have to make extensive use of the READ and WRITE commands.  Since the EEPROM address always increments by 1 each time we call the WRITE command, we’ll also have to keep a running count of the current EEPROM address in order to read the color sequence later.

The first thing we’ll want to specify, however, is what gets written to EEPROM if the color is red or green.  In order to keep things simple, we’ll write the number 1 to EEPROM if the color red is displayed and 0 to EEPROM if the color green is displayed:

```IF (displayColor = 1) THEN
...
ELSEIF (displayColor = 0) THEN
...
```

After each color is written to EEPROM, we’ll add 1 to the EEPROM address counter.  This makes displaying the color sequence a simple FOR…NEXT loop:

```FOR eepromAddress = 0 TO currentAddress
IF (savedColor = 1) THEN
...
ELSEIF (savedColor = 0) THEN
...
ENDIF
...
NEXT
```

Confused?
For more information on reading and writing data to and from EEPROM, check out the READ and WRITE commands in the PBASIC Language Webhelp.

## Player Response

Once the color pattern is displayed, we want to check and be sure that the sequence of pushbutton states matches the sequence of colors shown.  The first thing we want to do is read the color sequence from EEPROM.  This can be achieved in the same way we display the color sequence, with a FOR…NEXT loop:

```FOR eepromAddress = 0 TO currentAddress
```

Next, we’ll want to keep track of the player pushbutton input, and this can get a bit tricky.  The code executes very quickly, and we have to be sure that it will wait for the player to enter the entire color sequence.  If we’re not careful, the code will read the first pushbutton state as the entire color sequence, which would be very frustrating for the player!

The simplest way to tackle this problem is to make sure the code waits for the player to press and release a pushbutton.  This will make the code wait for a press and release each time through the loop.  Since the pushbutton states will be 0 before we check the player response against the saved color, we’ll simply use two sets of variables to keep track of everything.  The first set (PbRed and PbGreen) will hold the states of the red and green pushbuttons.  Since we then want to save the states of these pushbuttons, the second set of variables (Red and Green) will be set to the states of PbRed and PbGreen before the pushbutton is released and their values are reset to 0.

```DO
PbGreen = IN1
PbRed = IN0
LOOP UNTIL (PbGreen = 1) OR (PbRed = 1)

Green = PbGreen
Red = PbRed

DO
PbGreen = IN1
PbRed = IN0
LOOP UNTIL (PbGreen = 0) AND (PbRed = 0)
```

Next we’ll want to compare the player input against the color displayed.  When the user is repeating the color pattern displayed by the bi-color LED, there are four conditions that can occur, with only two results:

 Color Displayed Player Response Result Red (savedColor = 1) Red (Red = 1) Next Round Red (savedColor = 1) Green (Green = 1) Lose Green (savedColor = 0) Red (Red = 1) Lose Green (savedColor = 0) Green (Green = 1) Next Round

Since all of our values are either 0 or 1, we can use conditional IF…THEN statements to compare the value in savedColor to the state of the pushbutton pressed.  If the button pressed does not match the color shown, the youLose flag is set and the program returns to the main loop.  Otherwise, the program continues through the subroutine and adds 1 to the variable roundNumber if the player inputs the correct sequence:

```IF savedColor <> Green THEN
PbGreen = 0
PAUSE 100
ELSEIF savedColor <> Red THEN
youLose = 1
RETURN
ELSEIF savedColor = Red THEN
PbRed = 0
PAUSE 100
ELSEIF savedColor = Green THEN
youLose = 1
RETURN
ENDIF
```

The <> Operator:
When writing code, we always want things to be as clear as possible.  In the example above, the <> operator was used.  This is a comparative operator which means “not equal.”  So instead of writing:
IF (savedColor = 0) AND (Green = 1) THEN …
We can replace this with much simpler code using the not-equal operator:
IF savedColor <> Green THEN …

## BiColorLedGame.bs2

Enter and run BiColorLedGame.bs2 to start improving your fluid memory!  Since the highest round number is displayed whenever the player loses, challenge your family and friends and see who can reach the highest level!

```' BiColorLedGame.bs2
' This program is for a memory game using a bi-color LED and two pushbuttons.
' The bi-color LED will emit random red-green patterns, which the player will
' have to imitate using the two pushbuttons wired to the board.

' {\$STAMP BS2}
' {\$PBASIC 2.5}

' -----[ EEPROM Definitions ]------------------------------------------------

' -----[ I/O Definitions ]---------------------------------------------------

displayRed      PIN   15                      ' Red Pin
displayGreen    PIN   14                      ' Green Pin

' -----[ Variables ]---------------------------------------------------------

PbGreen         VAR   Byte                    ' Pushbutton pressed = green
PbRed           VAR   Byte                    ' Pushbutton pressed = red
Green           VAR   Byte                    ' Green pushbutton select
Red             VAR   Byte                    ' Red pushbutton select
btnWrk          VAR   Byte                    ' BUTTON command workspace
youLose         VAR   Byte                    ' Lose flag

roundNumber     VAR   Word                    ' Current level
delayTime       VAR   Word                    ' Current light delay time
generateColor   VAR   Word                    ' Random color generated
displayColor    VAR   generateColor.BIT0      ' Bit 0 of random color gen.
savedColor      VAR   Word                    ' Save colors displayed
GOSUB Begin_Game                              ' At startup, go to the
' Begin_Game subroutine

' -----[ Main Routine ]------------------------------------------------------
Main:
DO
GOSUB Check_Response                      ' Check player response

IF (youLose = 1) THEN                     ' If the youLose flag has been
DEBUG "You Lose!  Game Over.", CR,      ' set, inform the player & show
"Level Reached: ",                ' the highest level reached
DEC roundNumber
PAUSE 2000
DEBUG CLS
GOSUB Begin_Game                        ' Reset - go to Begin_Game
ELSEIF (youLose = 0) THEN                 ' If the youLose flag was not
GOSUB Next_Round                        ' set, go to the Next_Round
ENDIF                                     ' subroutine
LOOP

' -----[ Subroutine - Begin_Game ]-------------------------------------------
' Only used at beginning or after the player loses.  Resets all variables to
' their initial values, and displays the first color.

Begin_Game:
' Reset all variables to their initial values.
roundNumber = 0
delayTime = 750

' Tell user to press the bottom button to begin and randomize the variable
' generateColor until the button is pressed.
DEBUG HOME, "Press the bottom button to begin.", CR
RANDOM generateColor
BUTTON 0, 1, 100, 250, btnWrk, 0, Begin_Game

DEBUG CLS                                  ' Clear the Screen

IF (displayColor = 1) THEN                 ' If bit0 of the random number
HIGH displayRed                          ' generated is 1, then display
LOW displayGreen                         ' the color red.
PAUSE delayTime                          ' Wait for the value in delayTime
WRITE eepromAddress, 1                   ' Write a 1 to EEPROM to save
' the color displayed.
ELSEIF (displayColor = 0) THEN             ' If bit0 of the random number
HIGH displayGreen                        ' generated is 0, then display
LOW displayRed                           ' the color green.
PAUSE delayTime                          ' Wait for the value in delayTime
WRITE eepromAddress, 0                   ' Write a 0 to EEPROM to save
ENDIF                                      ' the color displayed

LOW displayRed                             ' Turn the LED off
LOW displayGreen

' -----[ Subroutine - Check_Response ]---------------------------------------
' Checks the player's response to see if the pattern they've entered matches
' the pattern displayed by the LEDs.

Check_Response:
youLose = 0                                 ' You lose flag is cleared

' Reads values from EEPROM until it reaches the number of colors that have
' been displayed.
' Monitor pushbutton states until one is pressed
DO
PbGreen = IN1                           ' State of pin 1 (green button)
PbRed = IN0                             ' State of pin 0 (red button)
LOOP UNTIL (PbGreen = 1) OR (PbRed = 1)

Green = PbGreen                           ' Save the state of each PB
Red = PbRed                               ' Save the state of each PB

' Wait until the player releases the pushbutton
DO
PbGreen = IN1                           ' State of pin 1 (green button)
PbRed = IN0                             ' State of pin 0 (red button)
LOOP UNTIL (PbGreen = 0) AND (PbRed = 0)

IF savedColor <> Green THEN               ' If the values of savedColor
PbGreen = 0                             ' and Green are different,
PAUSE 100                               ' keep looping
ELSEIF savedColor <> Red THEN             ' If the values of savedColor
youLose = 1                             ' and Red are different, the
ELSEIF savedColor = Red THEN              ' If the values of savedColor
PbRed = 0                               ' and Red are equal, keep
PAUSE 100                               ' looping
ELSEIF savedColor = Green THEN            ' If the values of savedColor
youLose = 1                             ' and Red are equal, the
ENDIF
NEXT

' If the code got here, the player did not lose, add 1 to the round number
roundNumber = roundNumber + 1

' -----[ Subroutine - Next_Round ]--------------------------------------------
' Displays the last colors shown and adds a new random color to the sequence

Next_Round:

PAUSE 750                                   ' Wait so player can get ready

' Subtract 50 from the delayTime so the sequence displays faster, but set a
' limit so the colors are still viewable
delayTime = (delayTime - 50) MIN 200

' Read the last colors from EEPROM and display them
IF (savedColor = 1) THEN
HIGH displayRed
LOW displayGreen
PAUSE delayTime
ELSEIF (savedColor = 0) THEN
HIGH displayGreen
LOW displayRed
PAUSE delayTime
ENDIF
LOW displayRed
LOW displayGreen
PAUSE delayTime
NEXT

RANDOM generateColor                        ' Generate a new random number

IF (displayColor = 1) THEN                  ' If bit0 of the random number
HIGH displayRed                           ' generated is 1, then display
LOW displayGreen                          ' the color red.
PAUSE delayTime                           ' Wait for value in delayTime
WRITE eepromAddress, 1                    ' Write a 1 to EEPROM to save
' the color displayed
ELSEIF (displayColor = 0) THEN              ' If bit0 of the random number
HIGH displayGreen                         ' generated is 0, then display
LOW displayRed                            ' the color green.
PAUSE delayTime                           ' Wait for value in delayTime
WRITE eepromAddress, 0                    ' Write a 0 to EEPROM to save
ENDIF                                       ' the color displayed.

LOW displayRed                              ' Turn LED off
LOW displayGreen