#Import libraries
import board
import digitalio
#Import from an especific Library and change their name
from random import randint as R
from time import sleep as d

#Declare the buttons and location
buttonC1 = digitalio.DigitalInOut(board.D5)
buttonC1.direction = digitalio.Direction.INPUT

buttonC2 = digitalio.DigitalInOut(board.D10)
buttonC2.direction = digitalio.Direction.INPUT

buttonC3 = digitalio.DigitalInOut(board.D9)
buttonC3.direction = digitalio.Direction.INPUT

buttonC4 = digitalio.DigitalInOut(board.D8)
buttonC4.direction = digitalio.Direction.INPUT

#Declare the leds and location
ledC1 = digitalio.DigitalInOut(board.D0)
ledC1.direction = digitalio.Direction.OUTPUT

ledC2 = digitalio.DigitalInOut(board.D2)
ledC2.direction = digitalio.Direction.OUTPUT

ledC3 = digitalio.DigitalInOut(board.D3)
ledC3.direction = digitalio.Direction.OUTPUT

ledC4 = digitalio.DigitalInOut(board.D4)
ledC4.direction = digitalio.Direction.OUTPUT

#Array of buttons
arr_Buttons = [
    buttonC1,
    buttonC2,
    buttonC3,
    buttonC4
]
#Array of leds
arr_Leds = [
    ledC1,
    ledC2,
    ledC3,
    ledC4
]

#Flags if it lost or continue
b_Lose = False
b_Correct = False

#Stores the sequence of flashing leds
arr_Levels = []
maxLevels = 4 #Number of levels

#Delays of blinking
delay = 0.55
delayP = 0.25

#Random number for led
def newLevel():
    return R(0, 3)

#Turn on/off a led
def controlLed(index: int, value: bool):
    arr_Leds[index].value = value 

# Turn on the selected LED
def ledFill(value):
    arr_Leds[value].value = True  

# Turn off the selected LED
def ledUnfill(value):
    arr_Leds[value].value = False

#Turn on all the leds
def ledsON():
    for led in arr_Leds:
        led.value = True

#Turn on all the leds
def ledsOFF():
    for led in arr_Leds:
        led.value = False

#Blink all the leds
def blinkLeds(times):
    for i in range(times):
        ledsON()  # Turn on all LEDs
        d(delayP)
        ledsOFF()  # Turn off all LEDs
        d(delayP)

#If it pass a level it blinks certain times
def nextLevel():
    blinkLeds(1)

#IF win turn on the leds and blink
def Win():
    for led in arr_Leds:
        led.value = True
        d(1)
    blinkLeds(3)

#If lose turn all leds and start turning them off 1 by 1
def Lose():
    for led in arr_Leds:
        led.value = True
    d(2)
    for led in arr_Leds:
        led.value = False
        d(1)


#Loop of the game
while True:
    #If you haven't lose and exceeded the # of levels
    while not b_Lose and len(arr_Levels) < maxLevels:
        nextLevel() #Create a new level
        arr_Levels.append(newLevel()) #add on the array the sequence

        for level in arr_Levels: #Go over the arrey of levels
            controlLed(level, True) #Turn on
            d(delay)

            controlLed(level, False) #Turn off
            d(delay)

        for level in arr_Levels: #Check the button clicked with the leds sequence
            i = 0
            b_Correct = False

            while not b_Correct and not b_Lose: #Checking if you lose or continue
                while arr_Buttons[i].value: #Verify the buttons
                    ledFill(i) #Turn on the led/Button you clicked
                    if i != level:
                        b_Lose = True #Made a mistake
                    else:
                        b_Correct = True #Continue

                ledUnfill(i) #Turn off the led you pressed

                if i < len(arr_Buttons) - 1: #iterates all the buttons
                    i += 1
                else:
                    i = 0

            if b_Lose:
                break

        delay -= 0.05 #Decrease the time
    #Check the state of the game
    if b_Lose: #Lose
        Lose()
    else: #Win
        Win()

    delay = 0.5 #Reset the delay
    arr_Levels.clear() #Clear the levels
    b_Lose = False #Reset the flag
    d(1.5) #Time before restarting