#!/usr/bin/env python

import RPi.GPIO as gpio
from time import sleep, time
from random import randint
from pygame import mixer

#mixer.init(45000,-16,1,1024)
mixer.init()


def lightLED(led):
    #First clear the pins, by setting them all to input
    for pin in ControlPins:
        gpio.setup(pin,gpio.IN)
	
    #Now setup the first pin for HIGH OUTPUT
    gpio.setup(led[0],gpio.OUT)
    gpio.output(led[0],gpio.HIGH)
	
    #Now setup the second pin for LOW OUTPUT
    gpio.setup(led[1],gpio.OUT)
    gpio.output(led[1],gpio.LOW)

def winPattern(led):
    for led in ledsInOrder:
        lightLED(LEDs[led])
        sleep(0.1)
    for counter in range(0,26):
        lightLED(LEDs[randint(0,len(LEDs)-1)])
        sleep(.1)
        

def winPatternGreen(led):
    mixer.music.load('danda.mp3')
    mixer.music.play()
    for led in bottom:
        lightLED(LEDs[led])
        sleep(0.1)
    sleep(4)
    gpio.cleanup()

def winPatternRed(led):
    mixer.music.load('mario.mp3')
    mixer.music.play()
    for led in top:
        lightLED(LEDs[led])
        sleep(0.1)
    sleep(8)
    gpio.cleanup()

#Control 18 LEDs with only 5 pins using charlieplexing
#Courtesy of mmrath - https://www.instructables.com/id/Charlieplexing-with-the-Raspberry-Pi/
ControlPins=[7,11,12,13,15]
#Define LEDs by 2 rows for pattern forming
top=[0,2,4,6,8,10,12,14,16,18]   #Green LEDs -- Odd
bottom=[1,3,5,7,9,11,13,15,17,19]#Red LEDs -- Even

ledsInOrder=[0,1,2,3,8,9,4,5,10,11,14,15,6,7,12,13,16,17,18,19]

LEDs=[]
for i in range(0,len(ControlPins)-1):
    for j in range(i+1,len(ControlPins)):
            LEDs.append([ControlPins[i],ControlPins[j]])
            LEDs.append([ControlPins[j],ControlPins[i]])            

# setup the GPIO pins to BOARD mode
gpio.setmode(gpio.BOARD)

#Setup Buttons
b0=gpio.setup(29,gpio.IN,pull_up_down=gpio.PUD_UP)
b1=gpio.setup(31,gpio.IN,pull_up_down=gpio.PUD_UP)
b2=gpio.setup(32,gpio.IN,pull_up_down=gpio.PUD_UP)
b3=gpio.setup(33,gpio.IN,pull_up_down=gpio.PUD_UP)
b4=gpio.setup(35,gpio.IN,pull_up_down=gpio.PUD_UP)
b5=gpio.setup(36,gpio.IN,pull_up_down=gpio.PUD_UP)
b6=gpio.setup(37,gpio.IN,pull_up_down=gpio.PUD_UP)
b7=gpio.setup(38,gpio.IN,pull_up_down=gpio.PUD_UP)
b8=gpio.setup(40,gpio.IN,pull_up_down=gpio.PUD_UP)

#Adding logic to prevent alternate LED from lighting up if one of the LED is already on
#Essentially prevent the 2nd LED connected to the button from turning on if the other LED is already on
already_pressed_b0=0
already_pressed_b1=0
already_pressed_b2=0
already_pressed_b3=0
already_pressed_b4=0
already_pressed_b5=0
already_pressed_b6=0
already_pressed_b7=0
already_pressed_b8=0

ledArray = []
#print ('LEDs array is:' + str(LEDs))

count_green= []
count_red= []
turn=1
try:
    while 1:
        #If Button0 is pressed -- top left button -- Board Pin29 
        if gpio.input(29)==False and already_pressed_b0==0:
            print('Turn is:' + str(turn))
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[0])
                already_pressed_b0 = already_pressed_b0 +1
                count_red.append(0)
                print('Red count for b0 is: ' + str(count_red))
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[1])
                already_pressed_b0 = already_pressed_b0 +1
                count_green.append(0)
                print('Green count for b0 is: ' + str(count_green)) 
                sleep(.25)
            turn=turn+1
            print('Turn now is:' + str(turn))
        
        #If Button1 is pressed -- -- Board Pin31  -- Correct Placement           
        elif gpio.input(31)==False and already_pressed_b1==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[2])
                already_pressed_b1 = already_pressed_b1 +1
                count_red.append(1)
                print('Red count for b1 is: ' + str(count_red))               
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[3])
                already_pressed_b1 = already_pressed_b1 +1
                count_green.append(1)
                print('Green count for b1 is: ' + str(count_green)) 
                sleep(.25)
            turn = turn+1
        
        #If Button2 is pressed --- Board Pin 32      
        elif gpio.input(32)==False and already_pressed_b2==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[4])
                already_pressed_b2 = already_pressed_b2 +1
                count_red.append(2)
                print('Red count for b2 is: ' + str(count_red)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[5])
                already_pressed_b2 = already_pressed_b2 +1
                count_green.append(2)
                print('Green count for b2 is: ' + str(count_green)) 
                sleep(.25)
            turn = turn+1
        
        #If Button3 is pressed --- Board Pin33         
        elif gpio.input(33)==False and already_pressed_b3==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[6])
                already_pressed_b3 = already_pressed_b3 +1
                count_red.append(3)
                print('Red count for b3 is: ' + str(count_red)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[7])
                already_pressed_b3 = already_pressed_b3 +1
                count_green.append(3)
                print('Green count for b3 is: ' + str(count_green)) 
                sleep(.25)
            turn = turn+1
        
        #If Button4 is pressed -- top left button -- Board Pin35
        elif gpio.input(35)==False and already_pressed_b4==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[8])
                already_pressed_b4 = already_pressed_b4 +1
                count_red.append(4)
                print('Red count for b4 is: ' + str(count_red)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[9])
                already_pressed_b4 = already_pressed_b4 +1
                count_green.append(4)
                print('Green count for b4 is: ' + str(count_green)) 
                sleep(.25)
            turn = turn+1
            print('Center button was pressed the first time with value' + str(already_pressed_b4))

        #If Button5 is pressed --- Board Pin36
        elif gpio.input(36)==False and already_pressed_b5==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[10])
                already_pressed_b5 = already_pressed_b5 +1
                count_red.append(5)
                print('Red count for b5 is: ' + str(count_red)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[11])
                already_pressed_b5 = already_pressed_b5 +1
                count_green.append(5)
                print('Green count for b5 is: ' + str(count_green))
                sleep(.25)
            turn = turn+1
                
        #If Button6 is pressed -- top left button -- Board Pin37
        elif gpio.input(37)==False and already_pressed_b6==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[12])
                already_pressed_b6 = already_pressed_b6 +1
                count_red.append(6)
                print('Red count for b6 is: ' + str(count_green)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[13])
                already_pressed_b6 = already_pressed_b6 +1
                count_green.append(6)
                print('Green count for b6 is: ' + str(count_green))
                sleep(.25)
            turn = turn+1
                
        #If Button7 is pressed -- top left button -- Board Pin38
        elif gpio.input(38)==False and already_pressed_b7==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[14])
                already_pressed_b7 = already_pressed_b7 +1
                count_red.append(7)
                print('Red count for b7 is: ' + str(count_red)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[15])
                already_pressed_b7 = already_pressed_b7 +1
                count_green.append(7)
                print('Green count for b7 is: ' + str(count_green))
                sleep(.25)
            turn = turn+1
                
        #If Button8 is pressed -- top left button -- Board Pin40
        elif gpio.input(40)==False and already_pressed_b8==0:
            if (turn % 2) == 0:
                ledArray.append(ledsInOrder[16])
                already_pressed_b8 = already_pressed_b8 +1
                count_red.append(8)
                print('Red count for b8 is: ' + str(count_red)) 
                sleep(.25)
            else:
                ledArray.append(ledsInOrder[17])
                already_pressed_b8 = already_pressed_b8 +1
                count_green.append(8)
                print('Green count for b8 is: ' + str(count_green))
                sleep(.25)
            turn = turn+1
        
        #Check against winning combinations of the 3x3 grid
        elif (0 in count_green and 1 in count_green and 2 in count_green) or (0 in count_green and 3 in count_green and 6 in count_green) or (0 in count_green and 4 in count_green and 8 in count_green) or (1 in count_green and 4 in count_green and 7 in count_green) or (2 in count_green and 5 in count_green and 8 in count_green) or (3 in count_green and 4 in count_green and 5 in count_green) or (6 in count_green and 7 in count_green and 8 in count_green):
            sleep(2)
            for led in bottom:
                winPatternGreen(led)
                #gpio.cleanup()
                break
                
        #Check against winning combinations of the 3x3 grid
        elif (0 in count_red and 1 in count_red and 2 in count_red) or (0 in count_red and 3 in count_red and 6 in count_red) or (0 in count_red and 4 in count_red and 8 in count_red) or (1 in count_red and 4 in count_red and 7 in count_red) or (2 in count_red and 5 in count_red and 8 in count_red) or (3 in count_red and 4 in count_red and 5 in count_red) or (6 in count_red and 7 in count_red and 8 in count_red):
            sleep(2)
            for led in top:
                winPatternRed(led)
                #gpio.cleanup()
                break
        
        #If no one wins and turns>9 then reset game
        elif turn > 9:
            sleep(3)
            winPattern(led)
            gpio.cleanup()
            break
                       
        #Light LEDs at the end of all statements as opposed to lighting inside of each IF statement to improve overall speed        
        for led in ledArray:
            lightLED(LEDs[led])
            #sleep(0.25)

except KeyboardInterrupt:
    mixer.stop()
    gpio.cleanup()
    