from tkinter import *
import pickle as pk
import fileManaging as fm
import UtilityView as uv
import KeyboardView as kv
import StaticParameter as SP
import os
import shutil
from time import sleep

class ListAssociationView:

    #  schermata che appare dopo aver cliccato il pulsante ASSOCIAZIONI nel MENU PRINCIPALE
    def schermata_associazioni():

        # variablile globale
        # in questo modo è più semplice gestire la chiusura di questa schermata
        global root
        root = Tk()
        root.attributes('-fullscreen', SP.full_screen_option)

        root.config(bg=SP.standard_color_setting("root_list_association_view"))

        current_list = fm.name_file
        frame = Frame(root)
        frame.config(bg=SP.standard_color_setting("frame_list_association_view"))

        label_memo = Label(frame, text=current_list,
                           font=SP.font_piccolo,
                           bg=SP.standard_color_setting("label_list_association_view"),
                           fg=SP.root_font_color,
                           bd=20,
                           width=200,
                           height=2)
        label_memo.pack(side=TOP,)
        sorted_list = fm.give_sorted_list()

        my_list = Listbox(root,  # yscrollcommand = scrollbar.set ,
                          name='my_list',
                          font=SP.font_piccolo,
                          fg=SP.root_font_color,
                          width=90, height=8,
                          bg=SP.standard_color_setting("listbox_list_association_view"),
                          activestyle="none")

        for audio in sorted_list:
            my_list.insert(END, audio)

       # my_list.bind('<<ListboxSelect>>', ListAssociationView.drop_menu_list_association)

        frame.pack()
        my_list.pack()
        ListAssociationView.menu_cascata_schermata_associazioni(root)
        uv.exit_button_with_text(root, SP.exit_text)
        root.mainloop()
        # _______________________ end of schermata_associazioni ___________________________

    # funzione che importa automaticamente l'unica lista presente sottoforma di cartella
    #nella cartella "Liste" di blindo
    def auto_import_list():
        #uv.show_dialog_with_time("Attendere\ncaricamento automatico in corso...", 2)
        chiavetta = os.listdir(SP.path_punto_accesso_chiavette)

        # finchè il path adibito all'accoglienza delle chiavette non viene riempito
        #con la usb key collegata, il ciclo previene un errore causato #
        # dalla differenza di velocità tra il comportamento sopracitato #
        # e la velocità dell' event detect che triggera questa funzione
        # l'event detect può essere trovato nel file GPIO mamaging
        while len(chiavetta) == 0:
            chiavetta = os.listdir(SP.path_punto_accesso_chiavette)
            sleep(1)

        path_folder_liste=os.path.join(SP.path_punto_accesso_chiavette,
                                        os.path.join(chiavetta[0],SP.expor_folder_name))

        # se non trovo la cartella "Liste" la creo ed esco
        # dalla funzione auto_import perchè non c'è nulla da importare
        if not os.path.exists(path_folder_liste):
            oldmask = os.umask(0o77)
            os.makedirs(path_folder_liste, 0o1411)
            os.umask(oldmask)
            return

        # ulteriore controllo ridondante
        if len(chiavetta) > 0:

            folder_lista = os.listdir(path_folder_liste)

            path_folder_lista = os.path.join(path_folder_liste,folder_lista[0])

            # ciclo che scorre il contenuto della cartella che rappresenta la lista
            # al suo interno esistono sia i file audio
            #che l'oggetto lista
            # ognuno di questi file finisce in un posto diverso all' interno della memoria del raspberry
            for file in os.listdir(path_folder_lista):

                path_file = os.path.join(path_folder_lista,file)

                if file == folder_lista[0]:
                    fm.copy_file_from_path_to_another(path_file, SP.path_liste)

                else:
                    fm.copy_file_from_path_to_another(path_file,SP.path_che_simula_la_memoria_interna_del_raspberry)

            fm.change_list(folder_lista[0])
            #uv.show_dialog_with_time("Lista "+folder_lista[0]+" importata con successo",2)

        else:
            print("nessuna chiavetta inserita")

    '''
    funzione disabilitata

    def drop_menu_list_association(evt):

        def unbind_and_closing(unbind_root):
            global root
            root.destroy()
            unbind_root.destroy()
            fm.delete_bind(id_button, name_audio)
            ListAssociationView.schermata_associazioni()

        def delete_and_closing(unbind_root):
            global root
            root.destroy()
            unbind_root.destroy()
            uv.elimina_file_con_conferma(SP.path_che_simula_la_memoria_interna_del_raspberry, name_audio)
            ListAssociationView.schermata_associazioni()

        # Note here that Tkinter passes an event object to onselect()
        w = evt.widget

        index = int(w.curselection()[0])
        value = w.get(index)

        root = Tk()
        root.overrideredirect(True)

        root_width = 140
        root_height = 200

        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()

        # calculate position x and y coordinates
        x = (screen_width / 2) - (root_width / 2)
        y = (screen_height / 2) - (root_height / 2)
        root.geometry('%dx%d+%d+%d' % (root_width, root_height, x, y))

        frame = Frame(root,
                      bg=SP.standard_color_setting("frame_list_association_view"))

        # str(value)[a:b] ritorna la substring con i caratteri
        # str(value)[a:b] ritorna la substring con i caratteri
        # che vanno dalla posizione a(compresa) alla posizione b(esclusa)
        # in questo caso b è la lunghezza stessa di value
        # value si presenta nel formato [Pulsante x --------> nomefile]
        # l'ultimo carattere è \n quindi lo rimuovo, ecco perchè sottraggo 1 a len(str(value))
        name_audio = str(value)[25:len(str(value))-1]
        id_button = int(str(value)[9:11])

        unbind_button = Button(frame,
                               text="Disassocia",
                               height=1, width=8,
                               bg=SP.standard_color_setting("button_list_association_view"),
                               fg=SP.button_font_color_gray_scale,
                               command=lambda: unbind_and_closing(root),
                               font = SP.font_piccolo,
                               relief = SP.bord_style,
                               bd = SP.bord_size,
                               activebackground = SP.active_background_color_gray_scale)

        pulsante_annulla = Button(frame,
                                  text="  Annulla  ",
                                  height=1, width=8,
                                  bg=SP.standard_color_setting("button_list_association_view"),
                                  fg=SP.button_font_color_gray_scale,
                                  command=lambda: root.destroy(),
                                  font=SP.font_piccolo,
                                  relief=SP.bord_style,
                                  bd=SP.bord_size,
                                  activebackground=SP.active_background_color_gray_scale)
        pulsante_elimina = Button(frame,
                                  text="   Elimina   ",
                                  height=1, width=8,
                                  bg=SP.standard_color_setting("button_list_association_view"),
                                  fg=SP.button_font_color_gray_scale,
                                  command=lambda: delete_and_closing(root),
                                  font=SP.font_piccolo,
                                  relief=SP.bord_style,
                                  bd=SP.bord_size,
                                  activebackground=SP.active_background_color_gray_scale)

        orientation=TOP
        unbind_button.pack(side=orientation)
        pulsante_elimina.pack(side=orientation)
        pulsante_annulla.pack(side=orientation)

        frame.pack(fill=BOTH, expand=YES)
        # _________________________________end of drop_menu_list_association()____________________
    '''
    # schermata che stampa tanti punsanti (sw) quanti pulsanti (hw) sono collegati a Blindo
    def schermata_pulsanti(closingroot, number_of_button):

        def close(root):
            root.destroy()
            ListAssociationView.schermata_associazioni()
            # _____________end of close()____________________

        # ____________________ start of schermata_pulsanti______________________
        closingroot.destroy()
        root = Tk()
        root.attributes('-fullscreen', SP.full_screen_option)
        root.config(bg=SP.standard_color_setting("root_list_association_view"))

        frame = Frame(root)
        frame.config(bg=SP.standard_color_setting("frame_list_association_view"))

        # caratteristiche della scrollbar
        text = Text(frame, wrap="none", bg=SP.standard_color_setting("frame_list_association_view"))
        vsb = Scrollbar(frame, orient="vertical", command=text.yview,width=40)
        vsb.config(width=90)
        text.configure(yscrollcommand=vsb.set,width=3,bg=SP.standard_color_setting("frame_list_association_view"))
        vsb.pack(side="left", fill="y")
        text.pack(side ="left",fill="both",expand=True)

        exit_button = Button(frame,
                                  text="Torna \nindietro",
                                  command=lambda: close(root),
                                  bd=SP.bord_size,
                                  relief=SP.bord_style,
                                  bg=SP.standard_color_setting("exit_button_with_text"),
                                  font=SP.font_piccolo,
                                  fg=SP.button_font_color_gray_scale,
                                  activebackground=SP.standard_color_setting("exit_button_with_text")
                                  )
        exit_button.config(height=50, width=18)

        #  ciclo che crea "number_of_button" pulsanti
        for i in range(number_of_button):
            pulsante = uv.bottom_with_text(frame, "Pulsante " + str(i + 1))
            pulsante.pack(side=TOP, fill=BOTH)
            text.window_create("end", window=pulsante)
            text.insert("end", "\n")

        text.configure(state="disabled")
        frame.pack(fill=BOTH, expand=True)
        exit_button.pack(side=RIGHT, fill=BOTH)
        root.mainloop()
        # ________________________end of schermata_pulsanti__________________

    def new_list_view(root):
        root.destroy()
        find_list_existing_name = False
        existing_list=os.listdir(SP.path_liste)

        new_list_name = kv.keyboard("Inserisci il nome della lista")

        for list in existing_list:
            if list == new_list_name:
                find_list_existing_name=True

        if find_list_existing_name:
            choice = uv.multi_choice_view("Lista già presente!\nSostituisci oppure \nannulla l'operazione",
                                          "Sostituisci",
                                          "Annulla")

            if choice:
                fm.create_list(new_list_name)
            else:
                return

        else:
            fm.create_list(new_list_name)
        fm.change_list(new_list_name)
        ListAssociationView.schermata_associazioni()
        # ______________________________end of new_list_view__________________

    def show_list(closing_root):
        closing_root.destroy()

        def delete_item(root):

            list_name = mylist.get('active')
            uv.elimina_file_con_conferma(SP.path_liste, list_name)

            if list_name == fm.name_file:
                fm.change_list('Lista di default')

            # senza questo destroy() l'eliminazione della lista non avviene finchè il programma non viene chiuso
            # questa tecnica è usata anche nella funzione select_items_and_copy
            #root.destroy()
            #ListAssociationView.show_list(closing_root)
            root.destroy()
            ListAssociationView.schermata_associazioni()
            # _______________  END OF delete_item _______________________

        def upload_list(root):
            list_name = mylist.get('active')
            fm.change_list(list_name)
            root.destroy()
            ListAssociationView.schermata_associazioni()
            # ____________________ end of upload_list  ___________________

        def show_chiavette():
            root = Tk()
            root.attributes('-fullscreen', SP.full_screen_option)
            root.config(bg=SP.standard_color_setting("root_list_association_view"))

            frame = Frame(root, bg=SP.standard_color_setting("frame_list_association_view"))
            frame.pack()

            # passo alla funzione pi\media e quindi verranno visualizzate a schermo le chiavette disponibili
            dirs = os.listdir(SP.path_punto_accesso_chiavette)

            label = Label(frame,
                          text="Selezionare la chiavetta su cui esportare la lista",
                          bd=20,
                          bg=SP.standard_color_setting("frame_list_association_view"),
                          font=SP.font_piccolo,
                          fg=SP.root_font_color)
            label.grid(row=1, column=0)
            label.config(width=50, height=4)

            # ciclo che stampa tante "chiavette" quante inserite nel device
            for USB_key in dirs:

                path_chiavetta = os.path.join(SP.path_punto_accesso_chiavette, USB_key)
                pulsante = Button(frame, text=USB_key,
                                  bg=SP.standard_color_setting("button_list_association_view"),
                                  font=SP.font_piccolo,
                                  fg=SP.button_font_color_gray_scale,
                                  bd=SP.bord_size,
                                  relief=SP.bord_style,
                                  activebackground=SP.active_background_color_gray_scale,
                                  # Using the "path_chiavetta=path_chiavetta" trick
                                  # causes your function to store the current value
                                  # of "path_chiavetta" at the time your lambda is defined,
                                  # instead of waiting to look up the value of "path_chiavetta" later.
                                  command=lambda path_chiavetta=path_chiavetta: esporta_lista(root, path_chiavetta)
                                  )
                pulsante.config(width=40, height=3)
                pulsante.grid()

            uv.exit_button_with_text(root, SP.exit_text)

            root.mainloop()
            # _______________________ end of show_chiavette

        def esporta_lista(root,path_chiavetta_destinazione):
            root.destroy()
            list_name = mylist.get('active')

            final_path_list = os.path.join(SP.path_liste, list_name)

            final_path_cartella_liste= os.path.join(path_chiavetta_destinazione, SP.expor_folder_name)
            #print(final_path_cartella_liste)

            cartella_lista_esportata = os.path.join(final_path_cartella_liste, list_name)
            #print(cartella_lista_esportata)

            rewite = True

            if os.path.exists(cartella_lista_esportata):

                # variabile booleana assegnata dalla risposta dell' utente
                user_choice = uv.multi_choice_view("Attenzione!\nEsiste già una versione di\n'"+list_name[0:20]+"'",
                                                   "Sovrascrivi",
                                                   "Annulla")

                if user_choice:
                    shutil.rmtree(cartella_lista_esportata)
                    rewite = True

                    # umask serve a garantire tutti i diritti di scrittura/lettura
                    # alla cartella creata con makedirs
                    oldmask = os.umask(0o77)
                    os.makedirs(cartella_lista_esportata, 0o1411)
                    os.umask(oldmask)
                    uv.show_dialog_with_time("Esportazione in corso...", 2)
                    uv.show_dialog_with_time("Operazione conclusa con successo", 2)
                else:
                    rewite = False

            else:

                oldmask = os.umask(0o77)
#                os.makedirs(final_path_cartella_liste, 0o1411)
                os.makedirs(cartella_lista_esportata, 0o1411)
                os.umask(oldmask)
                uv.show_dialog_with_time("Esportazione in corso...", 2)
                uv.show_dialog_with_time("Operazione conclusa con successo", 2)

            # carico la lista selezionata dall'utente e la metto nell'oggetto "list_obj"
            if rewite:

                try:
                    with open(final_path_list, 'rb') as io:
                        list_objects = pk.load(io)
                        fm.copy_file_from_path_to_another(final_path_list, cartella_lista_esportata)

                        for audio in list_objects:
                            if audio.name != "DEFAULT":
                                name_file = str(audio.name)
                                path_scr = os.path.join(SP.path_che_simula_la_memoria_interna_del_raspberry,name_file)

                                fm.copy_file_from_path_to_another(path_scr,
                                                                  cartella_lista_esportata)

                except (FileNotFoundError, IOError) as e:
                    print(e)
            # pop up informativo

            # ____________________________  end of esport_list ____________________________

        def rename_selected_element(root):
            # array con tutti gli elementi selezionati
            selected_items = [mylist.get(idx) for idx in mylist.curselection()]

            #file_in_memory= os.listdir(SP.path_che_simula_la_memoria_interna_del_raspberry)
            # selezione del primo elemento dell'array
            selected = selected_items[0]
            if selected!="Lista di default":
                new_name = kv.keyboard("Rinomina '" + selected + "'")

                # path file da rinominare
                scr = os.path.join(SP.path_liste, selected)
                # path file rinominato
                dst = os.path.join(SP.path_liste, new_name)
                os.rename(scr, dst)
                root.destroy()
                ListAssociationView.schermata_associazioni()
            else:
                uv.show_dialog_with_time("Attenzione\nImpossibile rinominare 'Lista di default'",2)

            # _______________ end of rename_selected_element

        # ________________________  START OF show_list
        root = Tk()
        root.attributes('-fullscreen', SP.full_screen_option)
        root.config(bg=SP.standard_color_setting("root_list_association_view"))

        scrollbar = Scrollbar(root)
        scrollbar.config(width=70)
        scrollbar.pack(side=LEFT, fill=Y)

        mylist = Listbox(root,
                         yscrollcommand=scrollbar.set,
                         font=SP.font_piccolo,
                         bg=SP.standard_color_setting("listbox_list_association_view"),
                         fg=SP.root_font_color, )

        # questo ciclo controlla tutte le sottocartelle del path passato in os.walk
        # e inserisce in mylist tutti i file con un'estensione contenuta in "formats"
        for lista in os.listdir(SP.path_liste):
            mylist.insert(END, lista)
        mylist.pack(side=LEFT, fill=BOTH, expand=True)

        mylist.pack(side=LEFT, fill=BOTH, expand=1, )
        scrollbar.config(command=mylist.yview)

        upload_list_button = Button(root,
                                    text="Carica lista",
                                    command=lambda: upload_list(root),
                                    bg=SP.standard_color_setting("button_list_association_view"),
                                    font=SP.font_piccolo,
                                    fg=SP.button_font_color_gray_scale,
                                    bd=SP.bord_size,
                                    relief=SP.bord_style,
                                    activebackground=SP.standard_color_setting("button_list_association_view"))
        upload_list_button.config(height=2, width=25)
        upload_list_button.pack(side=TOP, fill=BOTH)

        export_list_button = Button(root,
                                    text="Esporta lista",
                                    command=lambda:show_chiavette(),
                                    bg=SP.standard_color_setting("button_list_association_view"),
                                    font=SP.font_piccolo,
                                    fg=SP.button_font_color_gray_scale,
                                    bd=SP.bord_size,
                                    relief=SP.bord_style,
                                    activebackground=SP.standard_color_setting("button_list_association_view"))
        export_list_button.config(height=2, width=25)
        export_list_button.pack(side=TOP, fill=BOTH)

        rename_list_button = Button(root,
                                         text="Rinomina lista",
                                         command=lambda: rename_selected_element(root),
                                         bg=SP.standard_color_setting("button_list_association_view"),
                                         font=SP.font_piccolo,
                                         fg=SP.button_font_color_gray_scale,
                                         bd=SP.bord_size,
                                         relief=SP.bord_style,
                                         activebackground=SP.standard_color_setting("button_list_association_view"))
        rename_list_button.config(height=2, width=25)
        rename_list_button.pack(side=TOP, fill=BOTH)

        #  pulsante per eliminare le liste selezionate
        delete_list_button = Button(root,
                                    text="Elimina lista",
                                    command=lambda: delete_item(root),
                                    bg=SP.standard_color_setting("delete_button_background"),
                                    bd=SP.bord_size,
                                    relief=SP.bord_style,
                                    activebackground=SP.standard_color_setting("delete_button_background"),
                                    font=SP.font_piccolo,
                                    fg=SP.button_font_color_gray_scale)

        delete_list_button.config(height=2, width=25)
        delete_list_button.pack(fill=BOTH)

        uv.exit_button_with_text(root, "Torna al menu principale ")

    def import_list(list_association_root):
        list_association_root.destroy()
        usb_key = os.listdir(SP.path_punto_accesso_chiavette)

        root = Tk()
        root.attributes('-fullscreen', SP.full_screen_option)
        root.config(bg=SP.standard_color_setting("root_list_association_view"))

        frame = Frame(root, bg=SP.standard_color_setting("frame_list_association_view"))
        frame.pack()

        label = Label(frame,
                      text="Selezionare la chiavetta da cui importare le liste",
                      bd=SP.bord_size,
                      bg=SP.standard_color_setting("label_list_association_view"),
                      font=SP.font_piccolo,
                      fg=SP.root_font_color)
        label.grid(row=1, column=0)
        label.config(width=50, height=4)

        # stampa delle chiavette sottoforma di pulsanti
        for usb in usb_key:
            pulsante = ListAssociationView.button_USB_key(frame, usb,root)
            pulsante.grid()

        uv.exit_button_with_text(root, "torna indietro")

        root.mainloop()

    def button_USB_key(frame, nome_chiavetta,closing_root):
        #
        path_key = os.path.join(SP.path_punto_accesso_chiavette, nome_chiavetta)

        button = Button(frame, text=nome_chiavetta,
                          bg=SP.standard_color_setting("button_list_association_view"),
                          font=SP.font_piccolo,
                          fg=SP.button_font_color_gray_scale,
                          bd=SP.bord_size,
                          relief=SP.bord_style,
                          activebackground=SP.standard_color_setting("button_list_association_view"),
                          command=lambda: ListAssociationView.show_and_import_list(path_key,closing_root)
                          )
        button.config(width=40, height=3)
        return button

    def show_and_import_list(path_usb_key,closing_root):

        closing_root.destroy()
        '''
        funzione disabilitata per problematiche di esecuzione su raspberry
        il drop menu si apre tante volte quante sono le selezioni dell'utente

        def drop_menu_list_manager(evt):

            def import_list_and_closing():

                # root del drop_menu
                #unbind_root.destroy()
                fm.change_list(name_list)
                # path della cartella contenente la lista e i file sulla chiavetta

                list_folder = os.path.join(path_list_folders, name_list)

                for file in os.listdir(list_folder):

                    # path del singolo file analizzato
                    path_file = os.path.join(list_folder, file)
                    if file == name_list:
                        fm.copy_file_from_path_to_another(path_file, SP.path_liste)
                    else:
                        fm.copy_file_from_path_to_another(path_file,
                                                          SP.path_che_simula_la_memoria_interna_del_raspberry)
                # ___________________ end of import_list_and_closing________________________

            def delete_list(drop_menu_root):

                drop_menu_root.destroy()
                main_root.destroy()
                uv.elimina_file_con_conferma(path_list_folders, name_list)
                ListAssociationView.show_and_import_list(path_usb_key)
                # __________________________end of delete_list ____________________________
            # Note here that Tkinter passes an event object to onselect()
            w = evt.widget

            index = int(w.curselection()[0])
            name_list = w.get(index)

            root = Tk()
            root.overrideredirect(True)

            root_width = 140
            root_height = 150

            screen_width = root.winfo_screenwidth()
            screen_height = root.winfo_screenheight()

            # calculate position x and y coordinates
            x = (screen_width / 2) - (root_width / 2)
            y = (screen_height / 2) - (root_height / 2)
            root.geometry('%dx%d+%d+%d' % (root_width, root_height, x, y))

            frame = Frame(root,
                          bg=SP.standard_color_setting("frame_list_association_view"))

            import_list_button_drop_menu = Button(frame,
                                                  text="Importa",
                                                  height=1, width=8,
                                                  bg=SP.standard_color_setting("button_list_association_view"),
                                                  fg=SP.button_font_color_gray_scale,
                                                  command=lambda: import_list_and_closing(root),
                                                  font=SP.font_piccolo,
                                                  relief=SP.bord_style,
                                                  bd=SP.bord_size,
                                                  activebackground=SP.standard_color_setting("button_list_association_view")
                                                  )

            abort_button = Button(frame,
                                  text="  Annulla  ",
                                  height=1, width=8,
                                  bg=SP.standard_color_setting("button_list_association_view"),
                                  fg=SP.button_font_color_gray_scale,
                                  command=lambda: root.destroy(),
                                  font=SP.font_piccolo,
                                  relief=SP.bord_style,
                                  bd=SP.bord_size,
                                  activebackground=SP.standard_color_setting("button_list_association_view")
                                  )
            delete_button = Button(frame,
                                      text="   Elimina   ",
                                      height=1, width=8,
                                      bg=SP.standard_color_setting("delete_button_background"),
                                      fg=SP.button_font_color_gray_scale,
                                      command=lambda: delete_list(root),
                                      font=SP.font_piccolo,
                                      relief=SP.bord_style,
                                      bd=SP.bord_size,
                                      activebackground=SP.standard_color_setting("button_list_association_view")
                                      )

            import_list_button_drop_menu.pack(side=TOP)
            delete_button.pack(side=TOP)
            abort_button.pack(side=TOP)

            frame.pack(fill=BOTH, expand=YES)
            # ________________________ End of drop_menu_list:list_managetr ____________________________
        '''
        def import_list_with_button(name_list, cl_root):

            # root del drop_menu
            # unbind_root.destroy()
            fm.change_list(name_list)
            # path della cartella contenente la lista e i file sulla chiavetta

            list_folder = os.path.join(path_list_folders, name_list)
            saved_list = os.listdir(SP.path_liste)

            found_existing_list = False
            # controllo se la lista che si prova ad importare è già esistente in memoria
            for list in saved_list:
                if list == name_list:
                    found_existing_list = True
                    break
                else:
                    found_existing_list = False

            user_choice = True
            if found_existing_list:
                user_choice = uv.multi_choice_view("Attenzione\n'"+name_list[0:20]+"'\nè già presente", "Sovrascrivi", "Annulla")

            if user_choice:

                for file in os.listdir(list_folder):

                    # path del singolo file analizzato
                    path_file = os.path.join(list_folder, file)
                    # copio l'ggetto lista nella cartella "liste"
                    if file == name_list:
                        fm.copy_file_from_path_to_another(path_file, SP.path_liste)
                    # copio i file audio nella meoria interna
                    else:
                        fm.copy_file_from_path_to_another(path_file,
                                                          SP.path_che_simula_la_memoria_interna_del_raspberry)

                    uv.show_dialog_with_time("Caricamento in corso....\n"
                                             "Attendere qualche secondo.",2)
                    uv.show_dialog_with_time("Operazione conclusa con successo",2)
                    cl_root.destroy()

                    ListAssociationView.schermata_associazioni()
            # ____________________________end of import_list_with_button_________________________

        # ______________________________start of show_import_list____________________________

        path_list_folders = os.path.join(path_usb_key, SP.expor_folder_name)
        #se la cartella "Liste" non esiste la creo immediatamente

        if not os.path.exists(path_list_folders):
            oldmask = os.umask(0o77)
            os.makedirs(os.path.join(path_usb_key, SP.expor_folder_name), 0o1411)
            os.umask(oldmask)

        main_root = Tk()
        main_root.attributes('-fullscreen', SP.full_screen_option)
        main_root.config(bg=SP.standard_color_setting("root_list_association_view"))

        frame = Frame(main_root, bg=SP.standard_color_setting("frame_list_association_view"))
        frame.pack()

        label_info = Label(main_root,
                           text="Scegli lista e importa",
                           bg=SP.standard_color_setting("label_list_association_view"),
                           fg=SP.root_font_color,
                           font=SP.font_piccolo,
                           width=90, height=3,
                           )
        label_info.pack()
        # visualizzazione liste con scrollbar
        scrollbar = Scrollbar(main_root)
        scrollbar.pack(side=LEFT, fill=Y)

        my_list = Listbox(main_root,
                          yscrollcommand=scrollbar.set,
                          font=SP.font_piccolo,
                          fg=SP.root_font_color,
                          bg=SP.standard_color_setting("listbox_list_association_view")
                           )

        for list in os.listdir(path_list_folders):
            my_list.insert(END, list)
        # questo evento trigghera una funzione (drop_menu_list_manager  in questo caso)
        # dopo la pressione di un elemento nella listbox
        # my_list.bind('<<ListboxSelect>>', drop_menu_list_manager)
        my_list.pack(side=LEFT, fill=BOTH, expand=True)
        scrollbar.config(width=70, command=my_list.yview)

        list_name = my_list.get('active')

        import_list_button = Button(main_root,
                                    text="Importa lista",
                                    command=lambda:import_list_with_button(list_name, main_root),
                                    bg=SP.standard_color_setting("button_list_association_view"),
                                    font=SP.font_piccolo,
                                    fg=SP.button_font_color_gray_scale,
                                    bd=SP.bord_size,
                                    relief=SP.bord_style,
                                    activebackground=SP.standard_color_setting("button_list_association_view")
                                    )
        import_list_button.config(height=4, width=25)
        import_list_button.pack(side=TOP, fill=BOTH)

        uv.exit_button_with_text(main_root, "Torna indietro")

        main_root.mainloop()
        # _________________end of show_and_import_list__________________

    def menu_cascata_schermata_associazioni(master):
        # serve a rimuovere la riga tratteggiata che permette di spostare le ozioni col mouse
        master.option_add('*tearOff', FALSE)
        menu = Menu(master,
                    font=SP.font_medio,
                    bg=SP.standard_color_setting("menu_list_association_view"),
                    fg=SP.root_font_color, )
        master.config(menu=menu)
        # crea il menu a cascata
        subMenu = Menu(menu,
                       font=SP.font_medio,
                       bg=SP.standard_color_setting("menu_list_association_view"),
                       fg=SP.root_font_color, )
        menu.add_cascade(label="Opzioni                                                            ",
                         font=SP.font_medio,
                         menu=subMenu, )  # menu a cascata
        # riga di separazione
        menu.config(bd=SP.bord_size,activebackground=SP.standard_color_setting("menu_list_association_view"))
        subMenu.add_command(label="Nuova Lista     ", font=SP.font_medio,
                            command=lambda: ListAssociationView.new_list_view(master),
                            activebackground=SP.standard_color_setting("menu_list_association_view"),
                            activeforeground=SP.root_font_color)
        subMenu.add_separator()
        subMenu.add_command(label="Mostra Liste    ", font=SP.font_medio,
                            command=lambda: ListAssociationView.show_list(master),
                            activebackground=SP.standard_color_setting("menu_list_association_view"),
                            activeforeground=SP.root_font_color)
        subMenu.add_separator()
        subMenu.add_command(label="Modifica Lista", font=SP.font_medio,
                            command=lambda: ListAssociationView.schermata_pulsanti(master, 5),
                            activebackground=SP.standard_color_setting("menu_list_association_view"),
                            activeforeground=SP.root_font_color)
        subMenu.add_separator()
        subMenu.add_command(label="Importa Liste  ", font=SP.font_medio,
                            command=lambda: ListAssociationView.import_list(master),
                            activebackground=SP.standard_color_setting("menu_list_association_view"),
                            activeforeground=SP.root_font_color)
        #subMenu.add_separator()


from configs.hparams import create_hparams
from concurrent.futures import ProcessPoolExecutor
from functools import partial
import librosa
from utils import read_wav_np
import os
hparams = create_hparams()
from scipy.io.wavfile import write
from utils import read_wav_np
import torch
def check_paths(lists, num_workers=16, tqdm=lambda x: x):
    files2d = [[] for i in range(len(lists))]
    futures = [[] for i in range(len(lists))]
    names = ['train', 'valid', 'test']
    for i in range(len(lists)):
        with open(lists[i],  'r', encoding='utf-8-sig') as f:
            files2d[i] = f.readlines()
    executor = ProcessPoolExecutor(max_workers=num_workers)

    for i in range(len(files2d)):
        for line in files2d[i]:
            path = line.split('|')[0]
            futures[i].append(executor.submit(partial(_process_utterance, path)))
        write_metadata([future.result() for future in tqdm(futures[i])], 'filelists', 'problematic_merge_korean_pron_{}.txt'.format(names[i]))

'''
1. Read each file
2. Down sample to 22050Hz
3. Create meta file with the format 'path|phonemes|speaker'
["g",  "n",  "d",  "l",  "m",  "b",  "s",  "-", "j",   "q",
                "k", "t", "p", "h", "x", "w", "f", "c", "z", "A",
                "o", "O", "U", "u", "E", "a", "e", "1", "2", "3",
                "4", "5", "6", "7", "8", "9", "[", "]", "<", ">",
                "G", "N", "D", "L", "M", "B", "0", "K", ";;",";", "sp", "*",
                "$", "?", "!","#"]
'''
# I have not decided whether to separate dierectories for train/eval/test
def _process_utterance(in_path):
    try:
        sr, wav = read_wav_np(in_path)
    except:
        return in_path+'\n'
    return ''

def write_metadata(metadata, out_dir, out_file):
    with open(os.path.join(out_dir, out_file), 'w', encoding='utf-8') as f:
        for m in metadata:
            f.write((m))


# Example: This processes the value's given in the GUI in to a text file and checks entered value's from GUI
import csv
import os
from API import *

bestand_gebruiker = 'user_information.txt'
bestand_aanbieder = 'aanbieder_information.txt'
u_bestand_reserved_movies = 'gereserveerdefilms_gebruiker.txt'
p_bestand_reserved_opnaam = 'filmsopnaam_provider.txt'

def get_title_from_csv():
    with open(bestand, "r") as f:
        infile = csv.reader(f)
        movies = []
        for row in infile:
            text = row[0]
            title = text.split(";")[0]
            movies.append(title)
    return movies

def get_title_from_file():
    with open(p_bestand_reserved_opnaam, 'r')as f:
        text = f.readlines()

        titles = []
        for row in text:
            title = row.split(';')[1]
            titles.append(title)

    return titles

def movies_in_file():
    movie_from_csv = get_title_from_csv()
    movie_from_file = get_title_from_file()
    movie_to_print = []

    for i in movie_from_csv:
        movie_to_print.append(i)
        if i in movie_from_file:
            movie_to_print.remove(i)
    return movie_to_print

def file_is_empty(bestand):
    with open(bestand, 'r') as file:
        file.seek(0, os.SEEK_END)  # gaat naar einde van file
        if file.tell():
            file.seek(0)  # zet de cursor weer op de 0 positie
            return False
        else:
            return True

def handle_user_signup(user_input):
    file = open(bestand_gebruiker, 'r+')
    if file_is_empty(bestand_gebruiker):
        file.write(user_input)
        file.close()
    else:
        append_file = open(bestand_gebruiker, 'a')
        append_file.write(user_input)
        append_file.close()

def handle_provider_signup(user_input):
    file = open(bestand_aanbieder, 'r+')
    if file_is_empty(bestand_aanbieder):
        file.write(user_input)
        file.close()
    else:
        appen_file = open(bestand_aanbieder, 'a')
        appen_file.write(user_input)
        appen_file.close()

def username_infile(user_input):
    with open(bestand_gebruiker, 'r')as file:
        readlines = file.readlines()

    for elem in readlines:
        elem_mod = elem.strip()

        if elem_mod == user_input:
            print(f'overeenkomende username gevonden {elem_mod} -- {user_input}')
            return True

        else:
            print('geen overeenkomende username gevonden in gebruiker')

def username_provider_infile(user_input):
    with open(bestand_aanbieder, 'r')as file:
        p_readlines = file.readlines()

    for p_elem in p_readlines:
        p_elem_mod = p_elem.strip()

        if p_elem_mod == user_input:
            print('overeenkomende username gevonden')
            return True

        else:
            print('geen overeenkomende username gevonden in aanbieder')


import pygame
from player import Player

class Overlay:
    def __init__(self, player: Player, display_surface: pygame.Surface):
        self.gameCanvas = display_surface
        self.player = player
        self.font = pygame.font.Font("../Assets/Fonts/monogram.ttf", 40)
        # Overlay
        self.overlayUI = pygame.image.load("../Assets/Overlay/overlay.png").convert_alpha()
        self.overlayUIRect = self.overlayUI.get_rect(topleft=(10, 10))

        self.playerIcon = pygame.image.load("../Assets/Overlay/player_icon.png").convert_alpha()
        self.playerIconRect = self.overlayUI.get_rect(topleft=(14, 9))

    def display(self):
        money = self.player.itemInventory["money"]
        money_surf = self.font.render(str(money), False, "#E2E2E2")
        self.gameCanvas.blit(self.overlayUI, self.overlayUIRect)
        self.gameCanvas.blit(self.playerIcon, self.playerIconRect)
        self.gameCanvas.blit(money_surf, (180, 63))


from die import Die
import pygal

die_1 = Die()  # create a die using the Die Class
die_2 = Die() # create a second die using the Die Class

# try to make it take an imputted number of rolls
#number_rolls = int(input("How many rolls would you like (must be a number)? "))

# ------------------ Roll die and update the result list for each roll ------------------
results = []
for roll_num in range(1000000):
    result = die_1.roll() + die_2.roll()
    results.append(result)

# ------------------ Result Analysis ------------------
frequencies = []
max_result = die_1.num_sides + die_2.num_sides # adding the 2 dice maximum result
# recall that the list will start at 0 so we have to push it up one
for value in range(2, max_result+1):
    frequency = results.count(value)
    frequencies.append(frequency)

print(frequencies)

# ------------------ Visualize the results ------------------
hist = pygal.Bar() # Bar graph created with pygal

hist.title = "Results of rolling 6 sided die one million times"
hist.x_labels = list(range(2, max_result+1))
hist.x_title = "Results"
hist.y_title = "Frequency of Result"

hist.add('D6', frequencies)
hist.render_to_file('two_D6_visual.svg')


import argparse

import sgutils

def main():
    parser = argparse.ArgumentParser()

    parser.add_argument("device", action="store", help="Path to device to inquiry.")

    args = parser.parse_args()

    with open(args.device, mode="w+b") as device:
        print(sgutils.simple_inquiry(device))

if __name__ == "__main__":
    main()


import engine
import json
import pandas as pd
import numpy as np
from sim_setting import sim_setting_control
import argparse
from utility import parse_arguments

baseline_tt = {
    "hangzhou_1x1_bc-tyc_18041610_1h": 479.19,
    "hangzhou_1x1_bc-tyc_18041607_1h": 340.15,
    "hangzhou_1x1_bc-tyc_18041608_1h": 573.18,
    "hangzhou_1x1_kn-hz_18041607_1h": 161.48,
    "hangzhou_1x1_sb-sx_18041607_1h": 258.61,
}

def main():
    args = parse_arguments()
    sim_setting = sim_setting_control
    sim_setting["num_step"] = args.num_step
    evaluate_one_traffic(sim_setting, args.scenario)

def evaluate_one_traffic(dic_sim_setting, scenario):
    roadnetFile = "data/{}/roadnet.json".format(scenario)
    flowFile = "data/{}/flow.json".format(scenario)
    planFile = "data/{}/signal_plan_template.txt".format(scenario)
    outFile = "data/{}/evaluation.txt".format(scenario)

    if check(planFile, dic_sim_setting["num_step"]):
        tt = cal_travel_time(dic_sim_setting, roadnetFile, flowFile, planFile)
        print("====================== travel time ======================")
        print("scenario_{0}: {1:.2f} s".format(scenario, tt))
        print("====================== travel time ======================\n")
        b = baseline_tt[scenario]
        score = (b - tt)/b
        print("====================== score ======================")
        print("scenario_{0}: {1}".format(scenario, score))
        print("====================== score ======================")
        with open(outFile, "w") as f:
            f.write(str(score))
    else:
        print("planFile is invalid, Rejected!")

def cal_travel_time(dic_sim_setting, roadnetFile, flowFile, planFile):
    eng = engine.Engine(dic_sim_setting["interval"], dic_sim_setting["threadNum"],
                        dic_sim_setting["saveReplay"], dic_sim_setting["rlTrafficLight"],
                        dic_sim_setting["changeLane"])
    eng.load_roadnet(roadnetFile)
    eng.load_flow(flowFile)

    plan = pd.read_csv(planFile, sep="\t", header=0, dtype=int)
    intersection_id = plan.columns[0]

    for step in range(dic_sim_setting["num_step"]):
        phase = int(plan.loc[step])
        eng.set_tl_phase(intersection_id, phase)
        eng.next_step()
        current_time = eng.get_current_time()

        if current_time % 100 == 0:
            print("Time: {} / {}".format(current_time, dic_sim_setting["num_step"]))

    return eng.get_score()

def check(planFile, num_step):
    flag = True
    error_info = ''
    try:
        plan = pd.read_csv(planFile, sep='\t', header=0, dtype=int)
    except:
        flag = False
        error_info = 'The format of signal plan is not valid and cannot be read by pd.read_csv!'
        print(error_info)
        return flag

    intersection_id = plan.columns[0]
    if intersection_id != 'intersection_1_1':
        flag = False
        error_info = 'The header intersection_id is wrong (for example: intersection_1_1)!'
        print(error_info)
        return flag

    phases = plan.values
    current_phase = phases[0][0]

    if len(phases) < num_step:
        flag = False
        error_info = 'The time of signal plan is less than the default time!'
        print(error_info)
        return flag

    if current_phase == 0:
        yellow_time = 1
    else:
        yellow_time = 0

    # get first green phase and check
    last_green_phase = '*'
    for next_phase in phases[1:]:
        next_phase = next_phase[0]

        # check phase itself
        if next_phase == '':
            continue
        if next_phase not in [0, 1, 2, 3, 4, 5, 6, 7, 8]:
            flag = False
            error_info = 'Phase must be in [0, 1, 2, 3, 4, 5, 6, 7, 8]!'
            break

        # check changing phase
        if next_phase != current_phase and next_phase != 0 and current_phase != 0:
            flag = False
            error_info = '5 seconds of yellow time must be inserted between two different phase!'
            break

        # check unchangeable phase
        if next_phase != 0 and next_phase == last_green_phase:
            flag = False
            error_info = 'No yellow light is allowed between the same phase!'
            break

        # check yellow time
        if next_phase != 0 and yellow_time != 0 and yellow_time != 5:
            flag = False
            error_info = 'Yellow time must be 5 seconds!'
            break

        # normal
        if next_phase == 0:
            yellow_time += 1
            if current_phase != 0:
                last_green_phase = current_phase
        else:
            yellow_time = 0
        current_phase = next_phase

    if not flag:
        print(error_info)
    return flag

if __name__ == "__main__":
    main()


from app import ma
from models.round import RoundModel

class RoundSchema(ma.SQLAlchemyAutoSchema):
    class Meta:
        model = RoundModel
        dump_only = (
            "id",
            "created_at",
            "updated_at",
        )
        load_only = ("months_id",)
        load_instance = True
        include_fk = True
        ordered = True

    month = ma.Nested(
        "MonthSchema",
        only=(
            "id",
            "name",
            "year",
        ),
    )
    prize = ma.Nested("PrizeSchema", only=("id", "name"))


import numpy as np

def pad_sents(sents, pad_idx=0):
    if isinstance(sents[0], np.ndarray):
        return sents
    padded_sents = []
    maxlen = max([len(sent) for sent in sents])
    for sent in sents:
        padded_sent = sent.copy()
        padded_sent.extend([pad_idx] * (maxlen - len(sent)))
        padded_sents.append(padded_sent)
    return padded_sents

def data_iterator(*args, batch_size=100, random=True):
    npargs = []
    for arg in args:
        assert (len(arg) == len(args[0]))
        npargs.append(np.array(arg))

    ixs = np.arange(len(args[0]))
    if random:
        np.random.shuffle(ixs)
    for i in range(len(args[0]) // batch_size):
        batch_ixs = ixs[i * batch_size:(i + 1) * batch_size]
        batches = []
        for arg in npargs:
            batches.append(arg[batch_ixs])
        yield batches


# Course: CS261 - Data Structures
# Assignment: 5
# Student: Timothy Pham
# Description: MinHeap Implementation using Dynamic Array

# Import pre-written DynamicArray and LinkedList classes
from a5_include import *

class MinHeapException(Exception):
    """
    Custom exception to be used by MinHeap class
    DO NOT CHANGE THIS CLASS IN ANY WAY
    """
    pass

class MinHeap:
    def __init__(self, start_heap=None):
        """
        Initializes a new MinHeap
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        self.heap = DynamicArray()

        # populate MH with initial values (if provided)
        # before using this feature, implement add() method
        if start_heap:
            for node in start_heap:
                self.add(node)

    def __str__(self) -> str:
        """
        Return MH content in human-readable form
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        return 'HEAP ' + str(self.heap)

    def is_empty(self) -> bool:
        """
        Return True if no elements in the heap, False otherwise
        DO NOT CHANGE THIS METHOD IN ANY WAY
        """
        return self.heap.length() == 0

    def add(self, node: object) -> None:
        """
        adds a new object to the MinHeap maintaining heap property
        Runtime complexity of this implementation must be O(logN).
        """
        self.heap.append(node)
        # getting the length should be O(1) since we are using the __len__ built in
        current_index = self.heap.length() - 1
        current = self.heap.get_at_index(current_index)
        if (current_index - 1) // 2 < 0:
            parent_index = 0
        else:
            parent_index = (current_index - 1) // 2
        parent = self.heap.get_at_index(parent_index)
        while current < parent:
            self.heap.swap(current_index, parent_index)
            current_index = parent_index
            current = self.heap.get_at_index(current_index)
            if (current_index - 1) // 2 < 0:
                parent_index = 0
            else:
                parent_index = (current_index - 1) // 2
            parent = self.heap.get_at_index(parent_index)

    def get_min(self) -> object:
        """
        returns an object with a minimum key without removing it from
        the heap. If the heap is empty, the method raises a MinHeapException.
        Runtime complexity of this implementation is O(1).
        """
        if self.is_empty():
            raise MinHeapException
        return self.heap.get_at_index(0)

    def _heapify(self, array, index, loop=1):
        """helper function to recursively find the smallest value"""

        smallest = index

        # setting the children
        left = 2 * index + 1
        right = 2 * index + 2

        # when the left child is smaller than parent
        if left < array.length() and array[left] < array[smallest]:
            smallest = left

        # when the right child is smaller than parent
        if right < array.length() and array[right] < array[smallest]:
            smallest = right

        if smallest != index:
            array.swap(index, smallest)
            self._heapify(array, smallest, loop + 1)

    def remove_min(self) -> object:
        """
        This method returns an object with a minimum key and removes it from
        the heap. If the heap is empty, the method raises a MinHeapException.
        Runtime complexity of this implementation must be O(logN).
        """

        if self.is_empty():
            raise MinHeapException

        last_item_index = self.heap.length() - 1

        # swapping minimum with last item in DA
        self.heap.swap(0, last_item_index)

        # deleting last item and popping it
        min_item = self.heap.pop()

        # if empty after pop()
        if self.is_empty():
            return min_item
        current_index = 0

        # finding minimum value child
        self._heapify(self.heap, current_index)

        return min_item

    def build_heap(self, da: DynamicArray) -> None:
        """
        receives a dynamic array with objects in any order and builds a
        proper MinHeap from them. Current content of the MinHeap is lost.
        Runtime complexity of this implementation must be O(N).
        """
        new_heap = DynamicArray()
        for index in range(da.length()):
            new_heap.append(da[index])

        for index in range(new_heap.length() // 2 - 1, -1, -1):
            self._heapify(new_heap, index)

        self.heap = new_heap
        return

# BASIC TESTING
if __name__ == '__main__':

    print("\nPDF - add example 1")
    print("-------------------")
    h = MinHeap()
    print(h, h.is_empty())
    for value in range(300, 200, -15):
        h.add(value)
        print(h)

    print("\nPDF - add example 2")
    print("-------------------")
    h = MinHeap(['fish', 'bird'])
    print(h)
    for value in ['monkey', 'zebra', 'elephant', 'horse', 'bear']:
        h.add(value)
        print(h)

    print("\nPDF - get_min example 1")
    print("-----------------------")
    h = MinHeap(['fish', 'bird'])
    print(h)
    print(h.get_min(), h.get_min())

    print("\nPDF - remove_min example 1")
    print("--------------------------")
    h = MinHeap([1, 10, 2, 9, 3, 8, 4, 7, 5, 6])
    while not h.is_empty():
        print(h, end=' ')
        print(h.remove_min())

    print("\nPDF - build_heap example 1")
    print("--------------------------")
    da = DynamicArray([100, 20, 6, 200, 90, 150, 300])
    h = MinHeap(['zebra', 'apple'])
    print(h)
    h.build_heap(da)
    print(h)
    da.set_at_index(0, 500)
    print(da)
    print(h)


'''

Winning will be decided by the person who picks second

Idea :  When will A can win ?
        ->  when he can grab the all remaining coins at this step.

       ->  dp[i]  =  whether A can win or not with value i

       if he didn't won dp[i-1] , then he can pick 1 now and can win
       same applies for x and y .
'''

class Solution :

    def predictWinner (self, n,x,y):

        dp = [0  for i in range(n+1)]
        dp[0] = False
        dp[1] = True
        for i in range (2, n+1):

            if i >=1  and not dp[i-1]:
                dp[i]  = True
            elif i>=x and not dp[i-x] :
                dp[i]  =  True
            elif i>= y and not dp[i-y] :
                dp[i]  = True
            else :
                dp[i]  = False

        return dp[n]


import numpy as np

from collections import deque
from keras.models import Model
from keras.layers import Input, Dense
from keras.optimizers import adam_v2

import random
import utility_functions as util

REPLAY_MEMORY_SIZE = 42000  # How many of last   to keep for model training, 42000 means remember last ~200 games
MIN_REPLAY_MEMORY_SIZE = 4200  # Minimum number of tricks in memory to start training, 10500 means at least ~20 games
MINIBATCH_SIZE = 32  # How many steps (samples) to use for training

# Agent class
class PlayingNetwork:
    def __init__(self, input_size, name):

        self.input_size = input_size
        self.name = name

        # Main model
        self.model = self.create_model()

        # An array with last n steps for training
        self.replay_memory = deque(maxlen=REPLAY_MEMORY_SIZE)

    @staticmethod
    def dense_layer(num_units):
        return Dense(num_units, activation="relu")

    def create_model(self):

        input1 = Input(self.input_size)  # input size for observation state is 3732
        # input2 = Input(1)  # scalar input for action taken
        #
        # combined = concatenate([input1, input2])
        if self.input_size > 3000:
            if self.name == "small":
                x = self.dense_layer(1024)(input1)
            else:
                x = self.dense_layer(2048)(input1)
            if self.name == "large":
                x = self.dense_layer(1024)(x)
            x = self.dense_layer(512)(x)
            x = self.dense_layer(256)(x)
            x = self.dense_layer(128)(x)
        else:
            x = self.dense_layer(128)(input1)
        x = self.dense_layer(64)(x)
        x = self.dense_layer(32)(x)
        x = Dense(1, activation="linear")(x)  # evaluation

        model = Model(inputs=input1, outputs=x)

        model.compile(
            loss="mse",
            optimizer=adam_v2.Adam(learning_rate=0.0001),
            metrics=["accuracy"],
        )
        # print(model.summary())
        return model

    # Adds data to a memory replay array
    # (state, reward)
    def update_replay_memory(self, transition):
        # util.write_state(util.key_to_state(192, transition[0]), "backprop", 192)
        self.replay_memory.append(transition)

    # Trains main network once every backpropagation/round
    def train(self):
        # print("Calling train, Replay size: ", len(self.replay_memory))
        # Start training only if certain number of samples is already saved
        if len(self.replay_memory) < MIN_REPLAY_MEMORY_SIZE:
            return 0

        # Get a minibatch of random samples from memory replay table
        minibatch = random.sample(self.replay_memory, MINIBATCH_SIZE)

        # Get states (x) and rewards (y) from minibatch
        states = np.array(
            [
                util.key_to_state(self.input_size, transition[0])
                for transition in minibatch
            ]
        )
        rewards = np.array([transition[1] for transition in minibatch])

        # Fit on all samples as one batch, log only on terminal state
        history = self.model.fit(
            states,
            rewards,
            batch_size=MINIBATCH_SIZE,
            verbose=0,
            shuffle=False,
        )
        loss = history.history["loss"][0]
        return loss

    def predict(self, state):
        return self.model.predict(state.reshape(-1, *state.shape))[0]


lista = ["Segunda","Terça","Quarta","Quinta","Sexta","Sábado","Domingo"]

#modo leitura/escrita
f = open("data.txt","r+")

#escrever conteúdo da listas
f.writelines(lista)

linhas = f.readlines()
print(linhas)
f.close()


import torch.nn as nn
import torch
import data
from torch.autograd import Variable
class RNN(nn.Module):
   def __init__(self, input_size, h_size, output_size):
      super(RNN, self).__init__()

      self.h_size = h_size
      self.i2h = nn.Linear(input_size + h_size, h_size)
      self.i2o = nn.Linear(input_size + h_size, output_size)
      self.softmax = nn.LogSoftmax(dim = 1)

   def forward(self, input, hidden):
      combined = torch.cat((input, hidden), 1)
      hidden = self.i2h(combined)
      output = self.i2o(combined)
      output = self.softmax(output)
      return output, hidden

   def initHidden(self):
      return Variable(torch.zeros(1, self.h_size))

def get_output(output):
   _,top_i = output.topk(3)
   cat_index =[ top_i[0][i] for i in range(top_i[0].size()[0])]
   top_cats = []
   for index in cat_index:
     top_cats.append(data.all_categories[index])
   return top_cats
n_hidden = 128
rnn = RNN(data.n_letters, n_hidden, data.n_categories)


"""
Plugins to track bases and mining locations, based on https://github.com/dsjoerg/ggpyjobs/blob/master/sc2parse/plugins.py
Aaron Bauer
Carleton College
August 2020
"""

import os

from sc2.position import Point2

os.environ["OMP_NUM_THREADS"] = "1"  # keep sklearn from spawning a bunch of threads

import traceback
from sklearn.cluster import AffinityPropagation
import numpy as np
from math import dist
import time
import warnings

warnings.simplefilter('ignore', UserWarning)
import sc2reader
from sc2reader.log_utils import loggable
import logging
from sc2reader.engine.plugins import SelectionTracker, APMTracker
from selection_plugin import ActiveSelection
from typing import NamedTuple, Tuple
from enum import Enum

base_names_tier_one = set(["Hatchery", "Nexus", "CommandCenter"])
base_names = set(["Hatchery", "Lair", "Hive", "Nexus", "CommandCenter", "CommandCenterFlying", "OrbitalCommand",
                  "OrbitalCommandFlying", "PlanetaryFortress"])
flying_buildings = ["Barracks", "Factory", "Starport", "CommandCenter"]
land_cc_abils = ['LandOrbitalCommand', 'LandCommandCenter']
cc_names = ['OrbitalCommand', 'CommandCenter']
BaseType = Enum("BaseType", "MAIN EXPANSION PROXY NONE")

class BaseCluster(NamedTuple):
    label: int
    center: Tuple[int, int]
    base_type: BaseType
    player_id: int

def is_mining_loc(resource_clusters, location):
    """
    Uses affinity propagation (https://scikit-learn.org/stable/modules/clustering.html#affinity-propagation)
    to cluster resource locations into possible base locations, returns True if location within 8.5 of a center
    """
    # 8.5 threshold set empirically based on 5-replay sample
    # TODO verify with bigger sample
    if len(resource_clusters) == 0:
        return False
    return min([dist(location, center) for center in resource_clusters]) < 8.5

def select_center(cs):
    if len(cs) == 1:
        return cs[0]
    for c in cs:
        assert len([dist(c, x) for x in cs if x != c]) > 0, cs
    return min(cs, key=lambda c: np.mean([dist(c, x) for x in cs if x != c]))

def get_current_name(unit, frame):
    name = unit.name
    for f, t in unit.type_history.items():
        if frame >= f:
            name = t.name
    return name

def get_last_known_loc(unitid, frame, lookup):
    for f in range(frame - 1, 0, -1):
        if f in lookup and unitid in lookup[f]:
            return f, lookup[f][unitid]
    raise ValueError(f"no last known location for {unitid}")

# TODO differentiate between mining bases and other bases (usually turrets/bunkers/nydus worm/proxy barrack or pylon)
@loggable
class BaseTracker(object):
    """
    Tracks a player's current bases
    """

    name = "BaseTracker"

    def handleInitGame(self, event, replay):
        self.resource_locs = None
        try:
            replay.load_map()
            self.map_dim = (replay.map.map_info.width + replay.map.map_info.height) / 2
        except:
            self.map_dim = 150  # go with a reasonable if map can't be loaded
        self.under_construction = {}
        self.building_locs = {}
        self.lookup = {}
        self.keyframes = []
        self.mains = []

    def handleUnitBornEvent(self, event, replay):
        if event.unit.is_building:
            # this must be a starting base
            assert event.unit.name in base_names, "born event for non-main building"
            self.building_locs[event.unit.id] = (event.location, event.unit.owner.team_id, 0, True)
            self.lookup[event.frame] = self.building_locs.copy()
            self.keyframes.append(event.frame)
            self.mains.append(event.location)

    def handleUnitInitEvent(self, event, replay):
        # resources should have been created by now, can initialize resoursce locations
        if self.resource_locs is None:
            self.resource_locs = [o.location for o in replay.objects.values() if
                                  o.name and ("Mineral" in o.name or "Vespene" in o.name) and hasattr(o, "location")]
            try:
                self.resource_clusters = AffinityPropagation(preference=-1000, random_state=None).fit(
                    self.resource_locs).cluster_centers_
            except:
                print(self.resource_locs)
                traceback.print_exc()
        if event.unit.is_building:
            assert event.unit.id not in self.under_construction, "init event for already under construction unit"
            self.under_construction[event.unit.id] = (event.location, event.unit.owner.team_id, event.unit.finished_at,
                                                      is_mining_loc(self.resource_clusters,
                                                                    event.location) and event.unit.name in base_names)

    def handleUnitDoneEvent(self, event, replay):
        if event.unit.is_building:
            assert event.unit.id in self.under_construction and event.unit.id not in self.building_locs, "done event dictionary problem"
            self.building_locs[event.unit.id] = self.under_construction[event.unit.id]
            del self.under_construction[event.unit.id]
            self.lookup[event.frame] = self.building_locs.copy()
            self.keyframes.append(event.frame)

    def handleUnitDiedEvent(self, event, replay):
        if event.unit.is_building and "Flying" not in get_current_name(event.unit, event.frame):
            if event.unit.id not in self.building_locs and event.unit.id not in self.under_construction:
                self.logger.info(
                    f"dying {event.unit}, built {event.unit.finished_at} missing from dicts as of {event.frame}, probably due to missed landing: {replay.filename}")
            if event.unit.id in self.under_construction:
                del self.under_construction[event.unit.id]
            elif event.unit.id in self.building_locs:
                del self.building_locs[event.unit.id]
            self.lookup[event.frame] = self.building_locs.copy()
            self.keyframes.append(event.frame)

    def handleTargetPointCommandEvent(self, event, replay):
        if event.ability_name.startswith("Land"):
            selects = event.active_selection
            flying_selects = [obj for obj in selects if sorted(obj.type_history.items())[0][1].name in flying_buildings]
            target_type = event.ability_name[4:]
            targets = [obj for obj in flying_selects if get_current_name(obj, event.frame) == f"{target_type}Flying"]
            if len(targets) == 0:
                self.logger.error(
                    f"Landing {target_type} but none selected. event={event}, selects={selects}, names={[get_current_name(s, event.frame) for s in selects]}")
            else:
                # assume the order is given to the first selected building
                # TODO is this true? probably not, selection is sorted by id
                unit = targets[0]
                if unit.id in self.building_locs:
                    self.logger.info(f"\nflying building {unit} should not be in dict: {replay.filename}, {event}")
                    # go back through events and find the type change where the building lifted off
                    for e in [e for e in replay.events[::-1] if e.frame < event.frame]:
                        if isinstance(e,
                                      sc2reader.events.UnitTypeChangeEvent) and e.unit == unit and e.unit_type_name == f"{target_type}Flying":
                            # remove flying building from intervening frames
                            for frame in range(event.frame - 1, e.frame - 1, -1):
                                if frame in self.lookup and unit.id in self.lookup[frame]:
                                    del self.lookup[frame][unit.id]
                            self.logger.info(f"CORRECTED via type change event {e}\n")
                            break
                # drop the z-coordinate from the event location
                self.building_locs[unit.id] = (event.location[:2], unit.owner.team_id, unit.finished_at,
                                               is_mining_loc(self.resource_locs,
                                                             event.location[:2]) and unit.name in base_names)
                self.lookup[event.frame] = self.building_locs.copy()
                self.keyframes.append(event.frame)

    def handleBasicCommandEvent(self, event, replay):
        if event.ability_name.startswith("Lift"):
            selects = event.active_selection
            flying_selects = [obj for obj in selects if sorted(obj.type_history.items())[0][1].name in flying_buildings]
            target_type = event.ability_name[4:]
            targets = [obj for obj in flying_selects if get_current_name(obj, event.frame - 1) == target_type]
            if len(targets) == 0:
                self.logger.error(
                    f"Lifting {target_type}, but none selected. event={event}, selects={selects}, names={[get_current_name(s, event.frame - 1) for s in selects]}")
            else:
                # assume all selected building of the target type lift off
                # TODO is this true?
                for unit in targets:
                    if unit.id not in self.building_locs:
                        self.logger.info(
                            f"\nlanded building {unit} should be in dict at {event.frame}: {replay.filename}, {event}")
                        for e in replay.events[::-1]:
                            if unit.finished_at is not None and unit.finished_at < e.frame < event.frame and isinstance(
                                    e,
                                    sc2reader.events.UnitTypeChangeEvent) and e.unit == unit and e.unit_type_name == target_type:
                                # most recent landing
                                self.logger.info(
                                    f"found recent landing {e}, last known loc = {get_last_known_loc(unit.id, e.frame, self.lookup)}, built at {self.lookup[unit.finished_at][unit.id]}")
                                frame, loc = get_last_known_loc(unit.id, e.frame, self.lookup)
                                for f in range(frame + 1, event.frame):
                                    if f in self.lookup:
                                        self.lookup[f][unit.id] = loc
                                self.logger.info(f"CORRECTED using position as of {frame}\n")
                                break
                    else:
                        del self.building_locs[unit.id]

                    self.lookup[event.frame] = self.building_locs.copy()
                    self.keyframes.append(event.frame)

    #     def handleUnitTypeChangeEvent(self, event, replay):
    #         # current state is flying or new state is flying
    #         if ("Flying" in get_current_name(event.unit, event.frame - 1)) != ("Flying" in event.unit_type_name):
    #             unit = event.unit
    #             # lifting
    #             if "Flying" in event.unit_type_name:
    #                 print("lifting", unit)
    #                 assert unit.id in self.building_locs, f"landed building {unit} should be in dict: {replay.filename}, {event}"
    #                 del self.building_locs[unit.id]
    #                 self.lookup[event.frame] = self.building_locs.copy()
    #             else:
    #                 print("landing", unit)
    #                 assert unit.id not in self.building_locs, f"flying building {unit} should not be in dict: {replay.filename}, {event}"
    #                 # drop the z-coordinate from the event location
    #                 self.building_locs[unit.id] = (event.location[:2], unit.owner.team_id, unit.finished_at,
    #                                                is_mining_loc(self.resource_locs, event.location[:2]) and unit.name in base_names)
    #                 self.lookup[event.frame] = self.building_locs.copy()

    def handleEndGame(self, event, replay):
        try:
            pdict = {}
            for player in replay.players:
                player.bases = {}
                player.base_cluster = {}
                pdict[player.team_id] = player

            old_frames = {p.pid: 0 for p in replay.players}
            for frame in self.keyframes:
                for player in replay.players:
                    player.bases[frame] = {}
                    player.base_cluster[frame] = {}
                    if frame > 0:
                        for f in range(old_frames[player.pid] + 1, frame):
                            player.bases[f] = player.bases[old_frames[player.pid]]
                            player.base_cluster[f] = player.base_cluster[old_frames[player.pid]]
                        old_frames[player.pid] = frame

                for f, ls in self.lookup.items():
                    if f <= frame:
                        locs, teamids, finishes, prefs = zip(*list(ls.values()))
                        unit_ids = list(ls.keys())
                    else:
                        break
                locs = np.array(locs)
                prefs = np.array(prefs)
                finishes = np.array(finishes)
                self.logger.debug(f"(frame {frame}): locs = {locs.tolist()} prefs = {prefs.tolist()}")

                af = AffinityPropagation(preference=[0 if p else -5000 for p in prefs], random_state=None).fit(locs)
                count = 1
                while -1 in af.labels_ and count < 100:  # indicates clustering did not converge, so we retry until it does (giving up after 100 tries)
                    af = AffinityPropagation(preference=[0 if p else -5000 for p in prefs], random_state=None,
                                             max_iter=5000).fit(locs)
                    count += 1
                if count > 1:
                    self.logger.warning(
                        f"(frame {frame}): Tried {count} times to achieve convergence --- {'FAILED' if count == 100 else 'SUCCEEDED'}")
                cluster_centers_indices = af.cluster_centers_indices_
                centers = af.cluster_centers_.tolist()
                labels = af.labels_
                self.logger.debug(f"(frame {frame}): labels = {labels}")
                n_clusters = len(cluster_centers_indices)

                # mining location? must be separate cluster
                new_centers = []
                for k in range(n_clusters):
                    # mining bases in this cluster
                    mining_locs = [(loc, finish) for loc, finish, pref in
                                   zip(locs[labels == k], finishes[labels == k], prefs[labels == k]) if pref]
                    if len(mining_locs) > 1:
                        # split up clusters with more than one mining base
                        self.logger.debug(f"(frame {frame}): mining_locs = {mining_locs}")
                        original = min(filter(lambda x: x is not None, mining_locs), key=lambda x: x[1])
                        to_split = [x for x in mining_locs if x[0].tolist() != original[0].tolist()]
                        self.logger.debug(f"(frame {frame}): original = {original}, to_split = {to_split}")
                        for i, (loc, finish) in enumerate(to_split):
                            new_label = n_clusters + i
                            self.logger.debug(
                                f"(frame {frame}): changing {labels[(locs == loc).all(axis=1).nonzero()]} to {new_label}")
                            labels[(locs == loc).all(axis=1).nonzero()] = new_label
                            members = [(loc, finish) for loc, finish, pref in
                                       zip(locs[labels == k], finishes[labels == k], prefs[labels == k]) if not pref]
                            for ml, mf in members:
                                if dist(ml, loc) == min(dist(ml, x[0]) for x in
                                                        [original] + to_split[:i] + to_split[i + 1:]) and mf >= finish:
                                    self.logger.debug(
                                        f"(frame {frame}): changing {labels[(locs == ml).all(axis=1).nonzero()]} to {new_label}")
                                    labels[(locs == ml).all(axis=1).nonzero()] = new_label
                        new_centers.append(loc)

                for c in new_centers:
                    cluster_centers_indices = np.append(cluster_centers_indices, (locs == c).all(axis=1).nonzero())
                    n_clusters += 1

                # maximum distance
                new_centers = []
                for loc in locs:
                    if all(dist(loc, c) / self.map_dim > 0.1 for c in
                           centers):  # too far away from any cluster center, should be split
                        if any(dist(loc, select_center(cs)) / self.map_dim <= 0.1 for cs in
                               new_centers):  # close to an already split building, merge
                            _, i = min((dist(loc, select_center(cs)), i) for i, cs in enumerate(new_centers))
                            labels[(locs == loc).all(axis=1).nonzero()] = n_clusters + i
                            new_centers[i].append(tuple(loc))
                        else:  # start a new cluster
                            labels[(locs == loc).all(axis=1).nonzero()] = n_clusters + len(new_centers)
                            new_centers.append([tuple(loc)])

                for cs in new_centers:
                    central = select_center(cs)
                    cluster_centers_indices = np.append(cluster_centers_indices,
                                                        (locs == central).all(axis=1).nonzero())
                    n_clusters += 1
                self.logger.debug(
                    f"(frame {frame}): set(labels) = {set(labels)} center indices = {cluster_centers_indices}")
                base_types = {}
                for loc, label in zip(locs, labels):
                    if any(np.array_equal(loc, m) for m in self.mains):
                        base_types[label] = BaseType.MAIN
                    elif label not in base_types and (is_mining_loc(self.resource_clusters, loc)):
                        base_types[label] = BaseType.EXPANSION
                for unit_id, loc, team_id, label in zip(unit_ids, locs, teamids, labels):
                    pdict[team_id].bases[frame][unit_id] = loc
                    pdict[team_id].base_cluster[frame][unit_id] = BaseCluster(label, Point2(
                        locs[cluster_centers_indices[label]]), base_types.get(label, BaseType.PROXY), team_id)

        except:
            print(locs)
            print(replay.filename)
            traceback.print_exc()

        for player in replay.players:
            if frame < replay.frames:
                for f in range(frame + 1, replay.frames + 1):
                    player.bases[f] = player.bases[frame]
                    player.base_cluster[f] = player.base_cluster[frame]
            assert len(
                player.bases) == replay.frames + 1, f"{len(player.bases)} base entries, {replay.frames} frames {sorted(player.bases.keys())}"

            # TODO save cluster information for detecting scouting of new bases, etc.
            # for k in range(n_clusters):
            #     class_members = labels == k
            #     cluster_center = locs[cluster_centers_indices[k]]
            #     player = replay.player[teamids[cluster_centers_indices[k]]]

if __name__ == "__main__":
    # pro replays over 1000 seconds long
    files = ['replays/spawningtool_52661.SC2Replay',
             'replays/spawningtool_55197.SC2Replay',
             'replays/spawningtool_54185.SC2Replay',
             'replays/spawningtool_56994.SC2Replay',
             'replays/spawningtool_55200.SC2Replay',
             'replays/spawningtool_55942.SC2Replay',
             'replays/spawningtool_52636.SC2Replay',
             'replays/spawningtool_47751.SC2Replay',
             'replays/spawningtool_47709.SC2Replay',
             'replays/spawningtool_52635.SC2Replay',
             'replays/spawningtool_59082.SC2Replay',
             'replays/spawningtool_58796.SC2Replay',
             'replays/spawningtool_52662.SC2Replay',
             'replays/spawningtool_40787.SC2Replay']
    sc2reader.engine.register_plugin(APMTracker())
    sc2reader.engine.register_plugin(SelectionTracker())
    sc2reader.engine.register_plugin(ActiveSelection())
    bt = BaseTracker()
    bt.logger.setLevel(logging.WARN)
    bt.logger.addHandler(logging.StreamHandler())
    sc2reader.engine.register_plugin(bt)

    start = time.perf_counter()
    replays = [sc2reader.load_replay(f) for f in files]
    print(f"loading {len(files)} replays each over 1000 seconds took {time.perf_counter() - start} seconds")

    # fig, ax = plt.subplots()
    # fig.set_tight_layout(True)
    # def update(r, frame):
    #     ax.clear()
    #     colors = " br"
    #     for k in range(len({c.label for c in n_clusters):
    #         class_members = labels == k
    #         cluster_center = locs[cluster_centers_indices[k]]
    #         col = colors[teamids[cluster_centers_indices[k]]]
    #         ax.plot(locs[class_members, 0], locs[class_members, 1], col + '.')
    #         ax.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor=col,
    #                  markeredgecolor='k', markersize=14)
    #         for loc in locs[class_members]:
    #             ax.plot([cluster_center[0], loc[0]], [cluster_center[1], loc[1]], col)
    #     ax.text(1, 1, f"{frame // 22.4}s          {r.filename}")
    #     return ax


# Import the classes from the respective files
from customer import Customer
from restaurant import Restaurant
from review import Review

# Create customers and restaurants
customer1 = Customer("John", "Doe")
customer2 = Customer("Jane", "Smith")

restaurant1 = Restaurant("Delicious Eats")
restaurant2 = Restaurant("Tasty Treats")

# Add reviews
review1 = Review(customer1, restaurant1, 4)
review2 = Review(customer2, restaurant1, 5)

# Example usage
print(customer1.full_name())            # Output: John Doe
print(Restaurant.all_restaurants())       # Output: [restaurant1, restaurant2]
print(review1.rating())                 # Output: 4
print(restaurant1.customers())          # Output: [customer1, customer2]
print(restaurant1.average_star_rating())  # Output: 4.5

# Exit the Python interpreter
exit()


# https://leetcode.com/problems/combination-sum/
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        res = []

        def _combinationSum(start, target, chosen):
            for i in range(start, len(candidates)):
                if target - candidates[i] < 0:
                    continue

                elif target - candidates[i] > 0:
                    chosen.append(candidates[i])
                    _combinationSum(i, target-candidates[i], chosen)

                else:
                    chosen.append(candidates[i])
                    res.append(tuple(chosen))

                chosen.pop()

        _combinationSum(0, target, [])
        return res


import pandas as pd
from sklearn.model_selection import train_test_split

# Read in the Iris data
iris_df = pd.read_csv("./../data/iris.txt", sep = ",")

# Create additional features that report whether a sample belongs to each species
iris_df['is_setosa'] = (iris_df['class'] == "Iris-setosa").astype(float)
iris_df['is_versicolor'] = (iris_df['class'] == "Iris-versicolor").astype(float)
iris_df['is_virginica'] = (iris_df['class'] == "Iris-virginica").astype(float)

# Create a feature for our future predictions
iris_df["predicted_class"] = "No prediction"

# Split data into training and test sets
train_df, test_df = train_test_split(iris_df, test_size = 0.2)

# Write the training and test sets to csv files
train_df.to_csv("./../data/iris_train.txt", index = False)
test_df.to_csv("./../data/iris_test.txt", index = False)


#https://www.acmicpc.net/problem/1197
V, E = map(int, input().split())
graph = [list(map(int, input().split())) for i in range(E)]
def find(parent, x):
    if parent[x] != x:
        parent[x] = find(parent, parent[x])
    return parent[x]

def union(parent, a, b):
    a = find(parent, a)
    b = find(parent, b)
    if a < b:
        parent[b] = a
    else:
        parent[a] = b

parent = [0] * (V+1)
for i in range(V+1):
    parent[i] = i

#세번째 값 기준으로 sort
graph.sort(key=lambda x : x[2])
print(graph)
result = 0
for g in graph:
    a, b, cost = g
    #두 노드 이어져 있지 않으면
    if find(parent, a) != find(parent, b):
        #합치기
        union(parent, a, b)
        result += cost
print(result)


##wap to input a integer list to be appended to an existing list.
##whether the user enters a single number of list,the program should append the list accordingly

elist=[1,2,4,52,41,6]                        ##existing list variable
print("Existing list elements are : ",elist)

ilist=eval(input("Enter list elements to be appendend to the existing list : "))

if type(ilist)==type([]):                   ##if a list is input
    elist.extend(ilist)

elif type(ilist)==type(1):                  ##if an integer is input
   elist.append(ilist)

else:
     print("Please enter either an integer or a list ")

print("Appended list is :  ",elist)

input a list to be appended to an existing list.py


N = int(input())

paper = [list(map(int, input().split())) for _ in range(N)]

def check(n, x, y):
    global b_count
    global w_count

    count = 0
    for i in range(x, x+n):
        for j in range(y, y+n):
            if paper[i][j] == 1:
                count += 1

    if count == n * n:
        b_count += 1
    elif count == 0:
        w_count += 1
    else:
        check(n // 2, x, y)
        check(n // 2, x, y + n // 2)
        check(n // 2, x + n // 2, y)
        check(n // 2, x + n // 2, y + n // 2)

b_count = 0
w_count = 0

check(N, 0, 0)

print(w_count)
print(b_count)

baekjoon/lev 26. divied & conquer/2630.py