Thursday, February 26, 2015

Simon Project Completed!

After a little bit of a setback, I managed to put all the pieces together and complete my Simon game. The setback was that I was having trouble getting Python to access the GPIO pins from the desktop. The problem was that I wasn't running it from the root. But I don't want to log in as the root. When I tried to run sudo idle from the terminal, I got the following error:
Invalid MIT-MAGIC-COOKIE-1 keyTraceback (most recent call last):
  File "/usr/bin/idle", line 5, in 
    main()
  File "/usr/lib/python2.7/idlelib/PyShell.py", line 1427, in main
    root = Tk(className="Idle")
  File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1712, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: couldn't connect to display ":0.0"
I had no clue what that meant. So I asked on the Raspberry Pi forum, and it turns out that I need to use gksudo idle to run it instead. I tried to read up on it, but I still don't really understand what it means. But it worked, so I don't really care that much at the moment.

But after getting that all worked out, I was able to insert the pygame graphics code relatively easily. Here's the final code:
import RPi.GPIO as GPIO
import time
import random
import pygame
GPIO.setmode(GPIO.BCM)

##### Debug Scripts
def log(msg):
    if DebugDisplay == True:
        print msg

##### LED Scripts
def AllLEDsOn():
    for i in range(0,5):
        GPIO.output(LED[i], GPIO.HIGH)
    AllColorsOn()

def AllLEDsOff():
    for i in range(0,5):
        GPIO.output(LED[i], GPIO.LOW)
    ColorOff()

def Flashes(times, pause):
    AllLEDsOff()
    for j in range(0,times):
        AllLEDsOn()
        time.sleep(0.1)
        AllLEDsOff()
        time.sleep(0.1)
    time.sleep(pause)

def LEDFlash(LEDNum, OnTime, Sound):
    GPIO.output(LED[LEDNum], GPIO.HIGH)
    OneColorOn(LEDNum)
    if Sound == 1:
        toneChannel[LEDNum-1].play(tone[LEDNum-1])
        time.sleep(0.1)
    time.sleep(OnTime)
    GPIO.output(LED[LEDNum], GPIO.LOW)
    ColorOff()

def PlayList(Listing):
    for i in Listing:
        LEDFlash(i, 0.5, 1)
        time.sleep(0.1)
    time.sleep(1)

##### Button Scripts

def LookupButton(channel):
    for i in range(0,5):
        if channel == button[i]:
            return i

def ButtonPressed(channel):
    global Pressed, Listening, Busy
    TheButton = LookupButton(channel)
    if (TheButton == 0):
        log("Button 0 Pressed")
        Pressed = 0
        Listening = 0
    elif (TheButton > 0 and Listening == 1):
        log("Button {} Pressed -- Listening".format(TheButton))
        Pressed = TheButton
        Listening = 0
    elif (TheButton > 0 and Listening == 0):
        log("Button {} Pressed -- NOT Listening".format(TheButton))
        Pressed = -1

##### Color Scripts
def OneColorOn(ThisOne):
    if ThisOne == 1:
        pygame.draw.rect(screen, REDON, [0, 0, 100, 100])
        pygame.draw.rect(screen, YELLOW, [100, 0, 100, 100])
        pygame.draw.rect(screen, GREEN, [200, 0, 100, 100])
        pygame.draw.rect(screen, BLUE, [300, 0, 100, 100])
    elif ThisOne == 2:
        pygame.draw.rect(screen, RED, [0, 0, 100, 100])
        pygame.draw.rect(screen, YELLOWON, [100, 0, 100, 100])
        pygame.draw.rect(screen, GREEN, [200, 0, 100, 100])
        pygame.draw.rect(screen, BLUE, [300, 0, 100, 100])
    elif ThisOne == 3:
        pygame.draw.rect(screen, RED, [0, 0, 100, 100])
        pygame.draw.rect(screen, YELLOW, [100, 0, 100, 100])
        pygame.draw.rect(screen, GREENON, [200, 0, 100, 100])
        pygame.draw.rect(screen, BLUE, [300, 0, 100, 100])
    elif ThisOne == 4:
        pygame.draw.rect(screen, RED, [0, 0, 100, 100])
        pygame.draw.rect(screen, YELLOW, [100, 0, 100, 100])
        pygame.draw.rect(screen, GREEN, [200, 0, 100, 100])
        pygame.draw.rect(screen, BLUEON, [300, 0, 100, 100])

    pygame.display.flip()

def ColorOff():
    pygame.draw.rect(screen, RED, [0, 0, 100, 100])
    pygame.draw.rect(screen, YELLOW, [100, 0, 100, 100])
    pygame.draw.rect(screen, GREEN, [200, 0, 100, 100])
    pygame.draw.rect(screen, BLUE, [300, 0, 100, 100])

    pygame.display.flip()

def AllColorsOn():
    pygame.draw.rect(screen, REDON, [0, 0, 100, 100])
    pygame.draw.rect(screen, YELLOWON, [100, 0, 100, 100])
    pygame.draw.rect(screen, GREENON, [200, 0, 100, 100])
    pygame.draw.rect(screen, BLUEON, [300, 0, 100, 100])

    pygame.display.flip()

##### Text Display
def ShowText(Text):
    pygame.draw.rect(screen, BLACK, [0, 100, 400, 100])
    text = font.render(Text, True, WHITE)
    textpos = text.get_rect()
    textpos.centerx = screen.get_rect().centerx
    textpos.y = 110
    screen.blit(text, textpos)

    pygame.display.flip()


##### Color codes
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
YELLOW = (255,255,0)

REDON = (255,127,127)
GREENON = (127,255,127)
BLUEON = (127,127,255)
YELLOWON = (255,255,127)

WHITE = (255,255,255)
BLACK = (0,0,0)

##### Pygame setup
pygame.init()

font = pygame.font.SysFont('Calibri', 36, False, False)

screen = pygame.display.set_mode((400,150))
pygame.display.set_caption("Simon")

done = False
clock = pygame.time.Clock()

pygame.draw.rect(screen, RED, [0, 0, 100, 100])
pygame.draw.rect(screen, YELLOW, [100, 0, 100, 100])
pygame.draw.rect(screen, GREEN, [200, 0, 100, 100])
pygame.draw.rect(screen, BLUE, [300, 0, 100, 100])

ShowText("Welcome")

pygame.display.flip()

##### MAIN GAME LOOP
# Game Constants
DebugDisplay = False
button = [4, 12, 16, 20, 21]
LED = [22, 5, 6, 13, 19]

pygame.mixer.init(48000, -16, 1, 1024)
tone = [pygame.mixer.Sound("RedTone.ogg"), \
        pygame.mixer.Sound("YellowTone.ogg"), \
        pygame.mixer.Sound("GreenTone.ogg"), \
        pygame.mixer.Sound("BlueTone.ogg")]

toneChannel = [pygame.mixer.Channel(1), \
               pygame.mixer.Channel(2), \
               pygame.mixer.Channel(3), \
               pygame.mixer.Channel(4) ]

# Variables
Pressed = -1
Listening = 1
GameState = 1
HighScore = 0

# Set GPIO pins
for i in range (0,5):
    GPIO.setup(button[i], GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.setup(LED[i], GPIO.OUT)
    GPIO.add_event_detect(button[i], GPIO.FALLING, callback=ButtonPressed, bouncetime=200)

# LED loop in waiting mode
while True:
    Listening = 1
    if GameState == 0:
        log("GameState = 0, Exiting Game")
        break
    elif GameState == 1:
        log("GameState = 1, Pressed = {}".format(Pressed))
        if Pressed == 0:
            GameState = 0
            break
        else:
            for i in range(1,5):
                LEDFlash(i,0.2,0)
                if Pressed == 0:
                    GameState = 0
                    break
                elif Pressed > 0:
                    GameState = 2
                    break
            Pressed = -1
    elif GameState == 2:
        log("GameState = 2, Pressed = {}".format(Pressed))
        ShowText("Get Ready...")
        Pressed = -1
        Listening = 0
        Simon = [random.randint(1,4)]
        Flashes(5, 2)
        while GameState == 2:
            log("Starting a round, length = {}".format(len(Simon)))
            ShowText("Round {}".format(len(Simon)))
            Listening = 0
            PlayList(Simon)
            Flashes(1,0)
            for Levels in range(0, len(Simon)):
                log("Waiting for user input, correct answer = {}".format(Simon[Levels]))
                ShowText("Go!")
                GPIO.output(LED[0], GPIO.HIGH)
                Listening = 1
                Pressed = -1
                for timerloop in range(0,500):
                    if Pressed > -1:
                        break
                    time.sleep(0.01)
                if Pressed == Simon[Levels]:
                    LEDFlash(Pressed, 0.5, 1)
                else:
                    toneChannel[0].play(tone[0])
                    toneChannel[1].play(tone[1])
                    toneChannel[2].play(tone[2])
                    toneChannel[3].play(tone[3])
                    Flashes(5,2)
                    GameState = 1
                    if HighScore < len(Simon):
                        HighScore = len(Simon)
                    ShowText("High Score: {}".format(HighScore))
                    break
            GPIO.output(LED[0], GPIO.LOW)
            if (GameState == 1 and Pressed != 0):
                PlayList(Simon[0:Levels])
                for i in range(0,10):
                    LEDFlash(Simon[Levels], 0.1, 1)
                    time.sleep(0.1)
                time.sleep(1)
            elif GameState == 2:
                Simon.append(random.randint(1,4))
                time.sleep(0.2)
                Flashes(2,0)
                time.sleep(1)
        GameState = 1
        Pressed = -1

AllLEDsOff()
GPIO.cleanup()
pygame.quit()
The only thing that I might have left to do with this is to generate a little bit of documentation so that in a year or two when I look back at this, I'll know what I did and be able to go back through the whole thing. I'm not sure if I'm disciplined enough to do that, but that's really what I should do at this point.

No comments:

Post a Comment