#!/usr/bin/python3
import RPi.GPIO as GPIO
import time
import pygame
import random
import Adafruit_CharLCD as LCD

leds = [ 16, 26, 13 ]
buttons = [ 12, 19, 6 ] 

wait_time = 0.3
wait_time2 = 0.5
tries = 30 

def setup():
    GPIO.setmode(GPIO.BCM)
    for led in leds:
        GPIO.setup(led, GPIO.OUT)
    for button in buttons:
        GPIO.setup(button, GPIO.IN)
        
    all_leds_off()

    lcd_columns   = 20
    lcd_rows      = 4
    
    lcd_rs        = 25 
    lcd_en        = 24
    lcd_d4        = 23
    lcd_d5        = 17
    lcd_d6        = 18
    lcd_d7        = 22
    lcd_backlight = 4

    global lcd    
    lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, lcd_columns, lcd_rows, lcd_backlight)

    lcd.clear()
    
    pygame.mixer.pre_init(44100, -16, 1, 512)
    pygame.mixer.init()
    pygame.init()

    
def led_on(led):
    GPIO.output(led, GPIO.HIGH)

def led_off(led):
    GPIO.output(led, GPIO.LOW)

def all_leds_off():
    for led in leds:
        led_off(led)

def button_pressed(button):
    return GPIO.input(button) == GPIO.LOW  

def all_effects_off(effects):
    for effect in effects:
        effect.stop()

def report_score(points):
    lcd.clear()
    lcd.message("********************")
    lcd.set_cursor(0,1)
    lcd.message("Game Over: %s" % points)
    lcd.set_cursor(0,2)
    if points > 25:
        lcd.message("Excellent!")
    elif points > 20:
        lcd.message("Very Good!")
    elif points > 15:
        lcd.message("Good")
    elif points > 10:
        lcd.message("Not so great")
    elif points > 5:
        lcd.message("No comment")
    else:
        lcd.message("Terrible")
    lcd.set_cursor(0,3)
    lcd.message("********************")

def main():

    setup()

    effect1 = pygame.mixer.Sound('/home/pi/Desktop/WAV/beep (2).wav')
    effect2 = pygame.mixer.Sound('/home/pi/Desktop/WAV/beep (3).wav')
    effect3 = pygame.mixer.Sound('/home/pi/Desktop/WAV/beep (5).wav')

    effects = [effect1, effect2, effect3]

    try:
        points = 0

        for step in range(0, tries):
            
            lcd.clear()
            lcd.set_cursor(0,0)
            lcd.message("Catch The LED!")
            lcd.set_cursor(0,1)
            lcd.message("Tries Left: %s " % ( tries - step))
            lcd.set_cursor(0,2)
            lcd.message("Points: %s \n" % points) 
            lcd.set_cursor(0,3)
            
            wait = random.randint(30, max(40, 5000 - step*200 ))
            time.sleep(wait/1000)

            choice = random.randint(0, 2)
            led = leds[choice]

            button = buttons[choice]
            other_button1 = buttons[(choice + 1) % len(buttons)]
            other_button2 = buttons[(choice - 1) % len(buttons)] 

            led_on(led)
            
            # cheat detection - button already pressed?
            if button_pressed(button):
                lcd.message("YOU CHEATER!!")
                points = max(0, points-5)
                all_effects_off(effects)
                effect3.play()
                led_off(led)
                time.sleep(1)
                continue
            
            ts = time.clock()
            reacted = False

            while time.clock() - ts < wait_time : 
                if button_pressed(button):
                    lcd.message(random.choice(["Great!", "Nice", "Very Good!", "You Rock!"]))
                    all_effects_off(effects)
                    effect2.play()
                    time.sleep(wait_time2)
                    points += 1
                    reacted = True
                    break
                elif button_pressed(other_button1) or button_pressed(other_button2):
                    lcd.message(random.choice(["Bad!", "Wrong Button", "Not Good!"]))
                    all_effects_off(effects)
                    effect1.play() 
                    time.sleep(wait_time2)
                    if points > 0:
                        points -= 1
                    reacted = True 
                    break

            led_off(led)
            if not reacted:
                lcd.message(random.choice(["To Late!", "Lame!", "Speed Up", "Try Harder!"]))
                time.sleep(wait_time2)
        
        report_score(points)
        
    finally:

        all_leds_off()
        GPIO.cleanup()

main()



