import time
import random
import digitalio
import board
import pwmio
from note_freq import Notes
from note_freq import Dur

buzzer1 = pwmio.PWMOut(board.GP13, variable_frequency=True) # set the piezo up on GP13
OFF = 0  # pwm duty cycle when piezo is silent
ON = 2 ** 15  # pwm duty cycle when piezo is sounding - 50% 
ph = 0.003  # short sleep time used in phaser sound effect
raf = 20  # roll again factor - if 1 or 2 comes up, how ofter will the player be chosen to roll again. Factor of 20 is a 1 in 20 chance

# Set up the LEDs for the pips

p1 = digitalio.DigitalInOut(board.GP0)
p1.direction = digitalio.Direction.OUTPUT

p2 = digitalio.DigitalInOut(board.GP1)
p2.direction = digitalio.Direction.OUTPUT

p3 = digitalio.DigitalInOut(board.GP3)
p3.direction = digitalio.Direction.OUTPUT

p4 = digitalio.DigitalInOut(board.GP2)
p4.direction = digitalio.Direction.OUTPUT

p5 = digitalio.DigitalInOut(board.GP4)
p5.direction = digitalio.Direction.OUTPUT

p6 = digitalio.DigitalInOut(board.GP5)
p6.direction = digitalio.Direction.OUTPUT

p7 = digitalio.DigitalInOut(board.GP6)
p7.direction = digitalio.Direction.OUTPUT

p8 = digitalio.DigitalInOut(board.GP7)
p8.direction = digitalio.Direction.OUTPUT

p9 = digitalio.DigitalInOut(board.GP8)
p9.direction = digitalio.Direction.OUTPUT

# set up the tilt switch

roll = digitalio.DigitalInOut(board.GP26)
roll.direction = digitalio.Direction.INPUT
roll.pull = digitalio.Pull.UP

# set up the special switch - when low special fetures are enabled

special = digitalio.DigitalInOut(board.GP9)
special.direction = digitalio.Direction.INPUT
special.pull = digitalio.Pull.UP

# define functions 

def bn(): # stops the piezo sounding
    buzzer1.duty_cycle = OFF
    time.sleep(0.05)

def hbd(d):  # Happy Birthday melody when a player rolls a 1 or 2 and is selected to roll again
    x = 0
    while x < d:
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.A5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.B5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.w)
        bn()
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.A5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.D6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.w)
        bn()
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.G6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.E6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.B5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.A5
        buzzer1.duty_cycle = ON
        time.sleep(Dur.w)
        bn()
        bn()
        buzzer1.frequency = Notes.F6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.F6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.q)
        bn()
        buzzer1.frequency = Notes.E6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.D6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.h)
        bn()
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(Dur.w)
        bn()
        x = x + 1
        buzzer1.duty_cycle = OFF
        time.sleep(0.25)


def gliss(g, d):  # glissando sound effect
    x = 0
    while x < d:
        buzzer1.frequency = Notes.C4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.D4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.E4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.F4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.G4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.A4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.B4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.C5
        buzzer1.duty_cycle = ON
        time.sleep(g * 4)
        x = x + 1
        buzzer1.duty_cycle = OFF
        time.sleep(g * 2)

def mjr(g, d):  # major chord sound effect
    x = 0
    while x < d:
        buzzer1.frequency = Notes.C5
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.E5
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.G5
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.C5
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(g * 4)
        x = x + 1
        buzzer1.duty_cycle = OFF
        time.sleep(g * 2)

def mnr(g, d):  # minor chord sound effect
    x = 0
    while x < d:
        buzzer1.frequency = Notes.AS5
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.CS5
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.A4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.FS4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.GS4
        buzzer1.duty_cycle = ON
        time.sleep(g)
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(g * 1)
        x = x + 1
        buzzer1.duty_cycle = OFF
        time.sleep(g * 2)

def phaser(r):  # phaser sound effect
    x = 0
    while x < r:
        buzzer1.frequency = Notes.C5
        buzzer1.duty_cycle = ON
        time.sleep(ph)
        buzzer1.frequency = Notes.C6
        buzzer1.duty_cycle = ON
        time.sleep(ph)
        buzzer1.frequency - Notes.C7
        buzzer1.duty_cycle = ON
        time.sleep(ph)
        x = x + 1

def rollthedice():  # main function when the dice is rolled (tilt switch opens)
    if special.value == True:
        maxy = 6  # only allow roll of 1 - 6 when special switch is off
    else:
        maxy = 7
    x = random.randint(1, maxy)
    if x == 1:
        flashy(1, 0.05)  # flashy function flashes all of the LEDs before showing roll result
        r1()
        if maxy == 7:  # check to see if the player has won a roll again
            ra = random.randint(1, raf)
            if ra == raf:
                hbd(1)
        try:  # data logging of resulting roll
            with open("/logger.txt", "a") as datalog:
                datalog.write("1 \n")
                datalog.flush()

        except OSError as e:
            print("is error") 
            
    elif x == 2:
        flashy(1, 0.05)
        r2()
        if maxy == 7:
            ra = random.randint(1, raf)
            if ra == raf:
                hbd(1)
        try:
            with open("/logger.txt", "a") as datalog:
                datalog.write("2 \n")
                datalog.flush()

        except OSError as e:
            print("is error")
            
    elif x == 3:
        flashy(1, 0.05)
        r3()
        try:
            with open("/logger.txt", "a") as datalog:
                datalog.write("3 \n")
                datalog.flush()

        except OSError as e:
            print("is error")
            
    elif x == 4:
        flashy(1, 0.05)
        r4()
        try:
            with open("/logger.txt", "a") as datalog:
                datalog.write("4 \n")
                datalog.flush()

        except OSError as e:
            print("is error")
            
    elif x == 5:
        flashy(1, 0.05)
        r5()
        try:
            with open("/logger.txt", "a") as datalog:
                datalog.write("5 \n")
                datalog.flush()

        except OSError as e:
            print("is error")
            
    elif x == 6:
        flashy(1, 0.05)
        r6()
        try:
            with open("/logger.txt", "a") as datalog:
                datalog.write("6 \n")
                datalog.flush()

        except OSError as e:
            print("is error")
            
    else:  # roll is 7 therefore check to see if the player gets something greater than 6
        ctseven = random.randint(1, 20) 
        if ctseven > 15:  # if random number is between 16 to 20 - 1 in 4 chance - player rolls something greater than 6
            flashy(1, 0.03)
            adr = random.randint(0, 2)  # determine if player gets a 7 8 or 9
            if adr == 0:
                r7()
                gliss(.03, 3)
                bn()
                try:
                    with open("/logger.txt", "a") as datalog:
                        datalog.write("7 \n")
                        datalog.flush()

                except OSError as e:
                    print("is error")
                    
            elif adr == 1:
                r8()
                mjr(0.10, 3)
                bn()
                try:
                    with open("/logger.txt", "a") as datalog:
                        datalog.write("8 \n")
                        datalog.flush()

                except OSError as e:
                    print("is error")
                    
            else:
                r9()
                mnr(0.10, 3)
                bn()
                try:
                    with open("/logger.txt", "a") as datalog:
                        datalog.write("9 \n")
                        datalog.flush()

                except OSError as e:
                    print("is error")
                    
        else:  # if player not entitled to a 7 8 or 9 - 3 out of 4 chance - just roll again
            rollthedice()


def clearall():  # turns off all of the pips
    p1.value = False
    p2.value = False
    p3.value = False
    p4.value = False
    p5.value = False
    p6.value = False
    p7.value = False
    p8.value = False
    p9.value = False

# Functions defining each roll outcome - which pips to light up

def r1():
    p1.value = True

def r2():
    p2.value = True
    p3.value = True

def r3():
    p1.value = True
    p2.value = True
    p3.value = True

def r4():
    p2.value = True
    p4.value = True
    p5.value = True
    p3.value = True

def r5():
    p1.value = True
    p2.value = True
    p4.value = True
    p5.value = True
    p3.value = True

def r6():
    p2.value = True
    p4.value = True
    p5.value = True
    p3.value = True
    p7.value = True
    p6.value = True

def r7():
    p2.value = True
    p4.value = True
    p5.value = True
    p3.value = True
    p7.value = True
    p6.value = True
    p1.value = True

def r8():
    p2.value = True
    p3.value = True
    p4.value = True
    p5.value = True
    p6.value = True
    p7.value = True
    p8.value = True
    p9.value = True

def r9():
    p1.value = True
    p2.value = True
    p3.value = True
    p4.value = True
    p5.value = True
    p6.value = True
    p7.value = True
    p8.value = True
    p9.value = True

def flashy(c, t):  # pip flash sequence before roll is revealed
    z = 0
    while z < c:
        r1()
        time.sleep(t)
        clearall()
        r2()
        time.sleep(t)
        clearall()
        r3()
        time.sleep(t)
        clearall()
        r4()
        time.sleep(t)
        clearall()
        r5()
        time.sleep(t)
        clearall()
        r6()
        time.sleep(t)
        clearall()
        z = z + 1

while True:  # main loop waiting for a roll to begin
    if roll.value == True:
        clearall()
        flashy(2, 0.05)
        rollthedice()
        time.sleep(1)
    else:
        time.sleep(0.3)