import uuid
import pytest
from datetime import datetime, timedelta

from app import create_app
from app.config import TestConfig
from app.extensions import db, jwt as _jwt
from app.api.utils.include.user_info import User
from app.api.utils.setup_marshmallow import run_after_configure

from .constants import *
from tests.factories import FACTORY_LIST

from app import auth
auth.apply_security = False

def pytest_itemcollected(item):
    par = item.parent.obj
    node = item.obj
    pref = par.__doc__.strip() if par.__doc__ else par.__class__.__name__
    suf = node.__doc__.strip() if node.__doc__ else node.__name__
    if pref or suf:
        item._nodeid = ' '.join((pref, suf))

@pytest.fixture(scope="session")
def app(request):
    app = create_app(TestConfig)
    return app

@pytest.fixture(scope="session")
def auth_headers(app):
    base_auth_token = _jwt.create_jwt(BASE_AUTH_CLAIMS, TOKEN_HEADER)
    full_auth_token = _jwt.create_jwt(FULL_AUTH_CLAIMS, TOKEN_HEADER)
    view_only_auth_token = _jwt.create_jwt(VIEW_ONLY_AUTH_CLAIMS, TOKEN_HEADER)
    create_only_auth_token = _jwt.create_jwt(CREATE_ONLY_AUTH_CLAIMS, TOKEN_HEADER)
    admin_only_auth_token = _jwt.create_jwt(ADMIN_ONLY_AUTH_CLAIMS, TOKEN_HEADER)
    proponent_only_auth_token = _jwt.create_jwt(PROPONENT_ONLY_AUTH_CLAIMS, TOKEN_HEADER)
    nros_vfcbc_only_auth_token = _jwt.create_jwt(NROS_VFCBC_AUTH_CLAIMS, TOKEN_HEADER)
    return {
        'base_auth_header': {
            'Authorization': 'Bearer ' + base_auth_token
        },
        'full_auth_header': {
            'Authorization': 'Bearer ' + full_auth_token
        },
        'view_only_auth_header': {
            'Authorization': 'Bearer ' + view_only_auth_token
        },
        'create_only_auth_header': {
            'Authorization': 'Bearer ' + create_only_auth_token
        },
        'admin_only_auth_header': {
            'Authorization': 'Bearer ' + admin_only_auth_token
        },
        'proponent_only_auth_header': {
            'Authorization': 'Bearer ' + proponent_only_auth_token
        },
        'nros_vfcbc_auth_header': {
            'Authorization': 'Bearer ' + nros_vfcbc_only_auth_token
        }
    }

@pytest.fixture(scope="session")
def cli_runner(app):
    runner = app.test_cli_runner()
    return runner

@pytest.fixture(scope='session')
def test_client():
    app = create_app(TestConfig)
    client = app.test_client()
    ctx = app.app_context()
    ctx.push()

    User._test_mode = True

    # The event that this function runs off of is never fired
    # when the tests are run so it has to be called manually.
    run_after_configure()

    yield client

    ctx.pop()

@pytest.fixture(scope="function")
def db_session(test_client):
    conn = db.engine.connect()
    txn = conn.begin()

    options = dict(bind=conn, binds={})
    sess = db.create_scoped_session(options=options)
    db.session = sess

    for factory in FACTORY_LIST:
        factory._meta.sqlalchemy_session = sess

    yield db.session

    sess.remove()
    txn.rollback()
    conn.close()


import threading
from tkinter import *
import socket
from PIL import Image, ImageTk
from time import sleep
from modules.server import Server
from threading import Thread
from modules.client import User
from multiprocessing import Process, Queue
import time
from modules.socket_functions import *
import os

try:
    from playsound import playsound
##except:
##    try:
##        os.system("pip install playsound==1.2.2")
##        print("Playsound was successfully installed please restart")
except:
    pass

class Poker_Gui(Socket_function):

    def __init__(self):
        cards = [("Kreuz", 2), ("Kreuz", 3), ("Kreuz", 4), ("Kreuz", 5), ("Kreuz", 6), ("Kreuz", 7),
                 ("Kreuz", 8)]
        self.status_list = ["Call", "Raise", "Check", "Call", "Raise", "Check"]
        self.card_list_table = cards[:5]
        self.card_list_player = cards[5:7]
        self.money_labels = []
        self.name_labels = []
        self.status_labels = []
        self.player_cards = []
        self.table_cards = []
        self.own_money = 0
        self.player_name = ""
        self.numb_players = 0
        self.ip_adress_server = ""
        self.queueCG = Queue()
        self.queueGC = Queue()
        self.server = None
        self.client = None
        self.sounds = True
        self.main_menu()

    def play_music(self):
        try:
            self.music = Process(target=playsound, args=("sounds/background_music.mp3",))
            self.music.daemon = True
            self.music.start()
        except:
            pass

        self.is_music = True

    def start_stop_music(self):
        if self.is_music:
            try:
                self.music.terminate()
            except:
                pass
            self.is_music = False
            try:
                img = ImageTk.PhotoImage(Image.open("images/music_crossed.png").resize((50, 50), Image.ANTIALIAS))
                self.music_label.configure(image=img)
                self.music_label.image = img
            except:
                pass
        else:
            self.is_music = True
            try:
                img = ImageTk.PhotoImage(Image.open("images/music.png").resize((50, 50), Image.ANTIALIAS))
                self.music_label.configure(image=img)
                self.music_label.image = img
                self.play_music()
            except:
                pass

    def start_stop_sounds(self):
        if self.sounds:
            try:
                img = ImageTk.PhotoImage(Image.open("images/Speaker_crossed.png").resize((50, 50), Image.ANTIALIAS))
                self.sound_label.configure(image=img)
                self.sound_label.image = img
                self.sounds = False
            except:
                pass
        else:
            try:
                img = ImageTk.PhotoImage(Image.open("images/Speaker.png").resize((50, 50), Image.ANTIALIAS))
                self.sound_label.configure(image=img)
                self.sound_label.image = img
                self.sounds = True
            except:
                pass

    def set_buttons(self, gamewindow, flag, pos_list):  # [dealer,small blind, big blind]
        #print('setting...',flag,pos_list)
        if flag == 'set':

            for i, each in enumerate(pos_list):
                if not each:
                    continue
                if each == 'b':
                    #print('big blind')
                    image = ImageTk.PhotoImage(file='images/big_blind.png')
                elif each == 's':
                    #print('small blind')
                    image = ImageTk.PhotoImage(file='images/small_blind.png')
                else:
                    #print('dealer')
                    image = ImageTk.PhotoImage(file='images/dealer_button.png')
                self.player_buttons_list[i].create_image(1.5, 1.5, image=image, anchor='nw')
                self.player_buttons_list[i].image = image
        elif flag == 'clear':
            #print('cleaning...')
            for i, each in enumerate(pos_list):
                self.player_buttons_list[i].delete('all')

    def set_money(self, money_list):
        for i, label in enumerate(self.money_labels):
            label['text'] = str(money_list[i]) + "$"

    def set_names(self, name_list):
        for i, label in enumerate(self.name_labels):
            label['text'] = name_list[i]

    def set_status(self, status_list):
        for i, label in enumerate(self.status_labels):
            label['text'] = status_list[i]

    def set_pot_money(self, pot_money):
        self.pot_money['text'] = "Pot Money: " + str(pot_money) + "$"

    def set_own_money(self, own_money):
        self.own_money = own_money
        self.Money_label['text'] = "Your current money:\n" + str(own_money) + "$"

    def set_player_cards(self, card_list, game_window):
        if card_list:
            card_images_player = []
            for card in card_list:
                card = tuple(card)
                card_images_player.append(
                    ImageTk.PhotoImage(Image.open("cards/" + str(card) + ".png").resize((80, 100), Image.ANTIALIAS)))

            for i, element in enumerate(self.player_cards):
                element.configure(image=card_images_player[i])
                element.image = card_images_player[i]

    def set_current(self, current_list):
        #print(index_player,current_list)
        for i, each in enumerate(current_list):
            if each:
                player_image = PhotoImage(file="images/player1_your_turn.png")
                try:
                    if self.sounds == True and i == 0:
                        s = Process(target=playsound, args=("sounds/beans.mp3",))
                        s.start()
                except:
                    pass
            else:
                player_image = PhotoImage(file="images/player1.png")
            self.label_list[i].configure(image=player_image)
            self.label_list[i].image = player_image

    def set_table_cards(self, card_list, game_window):
        if card_list:
            card_images_table = []
            for card in card_list:
                card = tuple(card)
                card_images_table.append(
                    ImageTk.PhotoImage(Image.open("cards/" + str(card) + ".png").resize((120, 180), Image.ANTIALIAS)))

            for i, element in enumerate(card_images_table):
                self.table_cards[i].configure(image=element)
                self.table_cards[i].image = element
        else:
            card_images_table = []
            for card in range(5):
                card_images_table.append(
                    ImageTk.PhotoImage(Image.open("cards/back.png").resize((120, 180), Image.ANTIALIAS)))

            for i, element in enumerate(card_images_table):
                self.table_cards[i].configure(image=element)
                self.table_cards[i].image = element

    def set_player_input(self):
        self.player_name = self.user_input.get()
        self.numb_players = self.var.get()
        self.ip_adress_server = socket.gethostbyname(socket.gethostname())

    def set_input_join(self):
        self.player_name = self.user_name.get()
        self.ip_adress_server = self.input_ip.get()

    def set_client(self, ip):
        komm_s = socket.socket()
        komm_s.connect((ip, 55556))
        self.player_number = int(self.empfangeStr(komm_s))  # should ask server how many players
        self.side = 'client'

    def set_server(self):
        self.side = 'server'

    def winner_window(self,winning_cards=[("Kreuz", 2), ("Kreuz", 3), ("Kreuz", 4)],player="PlayerXY",combination="Straight"):
        winner_window = Toplevel()
        winner_window['bg'] = "white"
        winner_window.geometry("680x400")
        winner_window.title("Winner announcement")

        # Used for placing images with a certain margin between
        t=70
        # init list of images
        self.images_winner = []

        # Winner text: "PlayerXY won with Combination"
        player_Label = Label(winner_window,text=str(player+" won with "+combination),font="Arial 25 bold",bg="white")
        player_Label.place(relx=0.5,rely=0.1,anchor=CENTER)

        # Frame to Center all cards in window no matter how many
        card_frame = Frame(winner_window,bg="dimgrey",width=str(130*len(winning_cards)+10),height="200")
        card_frame.place(relx=0.5,rely=0.5,anchor=CENTER)

        # filling list of card images
        for element in winning_cards:
            self.images_winner.append(ImageTk.PhotoImage(Image.open("cards/" + str(tuple(element)) + ".png").resize((120, 180), Image.ANTIALIAS)))

        # Placing images in Lables
        for i in range(0,len(self.images_winner)):
            winning_cards_Label = Label(card_frame,image=self.images_winner[i],bg="white")
            winning_cards_Label.place(x=t,rely=0.5,anchor=CENTER)
            t+=130

        # Okay button to destroy Winner Window
        buttn = Button(winner_window,text="Okay",font="Arial 20 bold",command=winner_window.destroy)
        buttn.place(relx=0.5,rely=0.9,anchor=CENTER)

        # Mainloop
        #winner_window.mainloop()

    def open_host_window(self):

        host_window = Tk()

        host_window.geometry('600x597')

        host_window.title("Coffee-Poker - Host a Game")

        background_image = PhotoImage(file="images/welcome_background1.png")
        background_label = Label(host_window, image=background_image)
        background_label.place(x=0, y=0, relwidth=1, relheight=1)

        heading = Label(host_window, text="Welcome to Coffee-Poker", font="Arial 30 bold underline", foreground="white",
                        bg="#303030")

        heading.place(relx=0.5, rely=0.07, anchor=CENTER)

        Label_server_ip = Label(host_window, text="Your IP is:\n" + socket.gethostbyname(socket.gethostname()),
                                font="Arial 25 bold", foreground="white", bg="#303030")
        Label_server_ip.place(relx=0.5, rely=0.2, anchor=CENTER)

        Label_name = Label(host_window, text="Enter Name:", font="Arial 20 bold", foreground="white", bg="#303030")
        Label_name.place(relx=0.5, rely=0.35, anchor=CENTER)

        # Input Name
        self.user_input = StringVar()
        self.input_name = Entry(host_window, font="Arial 20", justify=CENTER, textvariable=self.user_input)
        self.input_name.place(relx=0.5, rely=0.45, anchor=CENTER)

        Label_player = Label(host_window, text="Enter number of players:", font="Arial 20 bold", foreground="white",
                             bg="#303030")
        Label_player.place(relx=0.5, rely=0.55, anchor=CENTER)

        # Select player number
        option_list = [2, 3, 4, 5, 6]

        self.var = StringVar(host_window)
        self.var.set(option_list[0])

        input_player = OptionMenu(host_window, self.var, *option_list)
        input_player.config(width=10, font=("Arial", 20), relief="solid")
        input_player.place(relx=0.5, rely=0.65, anchor=CENTER)

        connect_button = Button(host_window, text="Run", font="Arial 20",
                                command=lambda: [self.set_player_input(), self.set_server(), host_window.destroy(),
                                                 self.open_game_window(int(self.var.get()))])
        connect_button.place(relx=0.5, rely=0.8, anchor=CENTER)

        Back_button = Button(host_window, text="Back", font="Arial 20",
                             command=lambda: [host_window.destroy(), self.main_menu()])
        Back_button.place(relx=0.5, rely=0.9, anchor=CENTER)

        host_window.mainloop()

    def open_join_window(self):

        join_window = Tk()

        join_window.geometry('600x597')

        join_window.title("Coffee-Poker - Join a Game")

        background_image = PhotoImage(file="images/welcome_background1.png")
        background_label = Label(join_window, image=background_image)
        background_label.place(x=0, y=0, relwidth=1, relheight=1)

        heading = Label(join_window, text="Welcome to Coffee-Poker", font="Arial 30 bold underline", foreground="white",
                        bg="#303030")

        heading.place(relx=0.5, rely=0.07, anchor=CENTER)

        Label_server_ip = Label(join_window, text="Enter Host IP:", font="Arial 20 bold", foreground="white",
                                bg="#303030")
        Label_server_ip.place(relx=0.5, rely=0.25, anchor=CENTER)

        self.input_ip = StringVar()
        input_server_ip = Entry(join_window, font="Arial 20", justify=CENTER, textvariable=self.input_ip)
        input_server_ip.place(relx=0.5, rely=0.35, anchor=CENTER)

        Label_name = Label(join_window, text="Enter Name:", font="Arial 20 bold", foreground="white", bg="#303030")
        Label_name.place(relx=0.5, rely=0.45, anchor=CENTER)

        self.user_name = StringVar()
        self.input_name = Entry(join_window, font="Arial 20", justify=CENTER, textvariable=self.user_name)
        self.input_name.place(relx=0.5, rely=0.55, anchor=CENTER)

        connect_button = Button(join_window, text="Connect", font="Arial 20",
                                command=lambda: [self.set_input_join(), self.set_client(self.ip_adress_server),
                                                 join_window.destroy(),
                                                 self.open_game_window(self.player_number)])
        connect_button.place(relx=0.5, rely=0.65, anchor=CENTER)

        Back_button = Button(join_window, text="Back", font="Arial 20",
                             command=lambda: [join_window.destroy(), self.main_menu()])
        Back_button.place(relx=0.5, rely=0.85, anchor=CENTER)

        join_window.mainloop()

    def update(self, game_window):  # [name_list, money_list, status_list, pot, table_cards, player_cards]
        self.index = None
        self.flag = True
        while self.flag:
            last = None
            while not self.queueCG.empty():
                last = self.queueCG.get()
                #print('got', last)
            if last:
                name_list, money_list, status_list, current_list, pot, op, button_list, winner, table_cards, player_cards = \
                    last[0], last[1], last[2], last[3], \
                    last[4], last[5], last[6], last[7], last[8], last[9]
                if not self.index:
                    self.index = name_list.index(self.player_name)
                    time.sleep(0.1)
                if status_list.count("win!!") != 0:
                    if status_list.count("win!!") == 1:
                        t = threading.Thread(target=self.winner_window,args=(winner[0][1][1],winner[0][0],winner[0][1][0]))
                        t.start()
                    else:
                        t = threading.Thread(target=self.winner_window,args=(winner[0][1][1],"Everybody",winner[0][1][0]))
                        t.start()

                self.set_current(current_list[self.index:] + current_list[:self.index])
                self.set_names(name_list[self.index:] + name_list[:self.index])
                self.set_money(money_list[self.index:] + money_list[:self.index])
                self.set_status(status_list[self.index:] + status_list[:self.index])
                self.set_pot_money(pot)
                self.set_own_money(money_list[self.index])
                self.set_table_cards(table_cards, game_window)
                self.set_player_cards(player_cards, game_window)
                self.set_buttons(game_window, op, button_list[self.index:] + button_list[:self.index])

            time.sleep(0.1)

    def wrap_update(self, game_window):
        t = threading.Thread(target=self.update, args=(game_window,))
        t.start()

    # Main Window for Poker Game
    def open_game_window(self, number_of_players):

        self.play_music()

        self.client = User(self.ip_adress_server, self.player_name, self.queueCG, self.queueGC)
        self.process_client = Process(target=self.client.run)
        if self.side == 'server':
            self.server = Server(int(self.numb_players))
            self.process_server = Process(target=self.server.run)
            self.process_server.start()
        self.process_client.start()

        game_window = Tk()
        self.wrap_update(game_window)

        game_window.geometry('1200x720')

        game_window.title("Coffee-Poker - Game")

        # Background
        background_image = ImageTk.PhotoImage(Image.open("images/pokertisch1.png"))
        background_label = Label(game_window, image=background_image)
        background_label.place(x=0, y=0, relwidth=1, relheight=1)

        # Placing Player icons
        # player_coords = [(43,500),(43,5),(1040,500),(1040,20),(540,0),(540,520)]
        player_coords = [(500, 520), (500, 0), (23, 20), (970, 20), (23, 500), (970, 500)]
        player_image = PhotoImage(file="images/player1.png")
        self.label_list = []
        for i in range(0, number_of_players):
            player_label = Label(game_window, image=player_image, bg="white")
            player_label.place(x=player_coords[i][0], y=player_coords[i][1])
            self.label_list.append(player_label)

        # Placing Money Labels
        money_coords = [(650, 555), (650, 35), (175, 55), (1120, 55), (175, 535), (1120, 535)]
        for i in range(0, number_of_players):
            money_label = Label(game_window, text="0$", bg="white", font="Arial 11 bold")
            money_label.place(x=money_coords[i][0], y=money_coords[i][1], anchor=CENTER)
            self.money_labels.append(money_label)

        # Placing Name Labels
        name_coords = [(655, 580), (655, 60), (180, 80), (1125, 80), (175, 560), (1125, 560)]
        for i in range(0, number_of_players):
            player_label = Label(game_window, text="", bg="white", font="Arial 11 bold")
            player_label.place(x=name_coords[i][0], y=name_coords[i][1], anchor=CENTER)
            self.name_labels.append(player_label)

        # Placing Status Labels

        status_coords = [(630, 590), (625, 70), (150, 90), (1100, 90), (145, 570), (1090, 570)]
        for i in range(0, number_of_players):
            status_label = Label(game_window, text="", bg="white", font="Arial 11 bold")
            status_label.place(x=status_coords[i][0], y=status_coords[i][1])
            self.status_labels.append(status_label)
        # Placing table cards

        card_images = []
        for card in self.card_list_table:
            card_images.append(ImageTk.PhotoImage(Image.open("cards/back.png").resize((120, 180), Image.ANTIALIAS)))
        card_coords = [(340, 320), (470, 320), (600, 320), (730, 320), (860, 320)]
        for i, card in enumerate(self.card_list_table):
            # card_image = ImageTk.PhotoImage(Image.open("cards/"+str(card)+".png").resize((120,180), Image.ANTIALIAS))
            card_label = Label(game_window, image=card_images[i], bg="white")
            card_label.place(x=card_coords[i][0], y=card_coords[i][1], anchor=CENTER)
            self.table_cards.append(card_label)

        # Placing player cards
        card_images_player = []
        for card in range(0, 2):
            card_images_player.append(
                ImageTk.PhotoImage(Image.open("cards/back.png").resize((80, 100), Image.ANTIALIAS)))
        card_coords_player = [(50, 60), (140, 60)]

        frame_cards = Frame(game_window, bg="#303030")
        frame_cards.place(x=300, y=520, width=190, height=120)

        for i in range(0, 2):
            card_label = Label(frame_cards, image=card_images_player[i], bg="white")
            card_label.place(x=card_coords_player[i][0], y=card_coords_player[i][1], anchor=CENTER)
            self.player_cards.append(card_label)

        # Button for Call, Raise, Check, Fold, Quit
        # Quit
        Quit_Button = Button(game_window, text="Quit", font="Arial 20",
                             command=lambda: [self.start_stop_music(),self.on_closing(game_window), self.main_menu()])
        Quit_Button.place(relx=0.05, rely=0.95, anchor=CENTER, height=55)

        def check_call():
            self.queueGC.put(['call', 0])

        # Check/Call
        Check_Button = Button(game_window, text="Check\nCall", font="Arial 15", command=check_call)
        Check_Button.place(relx=0.95, rely=0.95, anchor=CENTER, width=100, height=55)

        #Music Button
        music_icon = ImageTk.PhotoImage(Image.open("images/music.png").resize((50, 50), Image.ANTIALIAS))
        self.music_label = Button(game_window, image=music_icon,bg="#393939",command=self.start_stop_music,border=0)
        self.music_label.place(relx=0.12, rely=0.95, anchor=CENTER)

        #Sound Button
        sound_icon = ImageTk.PhotoImage(Image.open("images/Speaker.png").resize((50, 50), Image.ANTIALIAS))
        self.sound_label = Button(game_window, image=sound_icon,bg="#393939",command=self.start_stop_sounds,border=0)
        self.sound_label.place(relx=0.19, rely=0.95, anchor=CENTER)

        # Money
        self.Money_label = Label(game_window, text="Your current money:\n0$", font="Arial 20", foreground="white",
                                 bg="#393939")
        self.Money_label.place(relx=0.5, rely=0.94, anchor=CENTER)

        # Raise
        def save(value, button):
            self.queueGC.put(['raise', value])
            button['command'] = raise_fct
            raise_fct()

        def raise_fct():
            if Raise_Button['text'] == 'Raise':
                global Raise_slider
                Raise_slider = Scale(game_window, from_=self.own_money, to=1, relief="solid", font="Arial 20")
                Raise_slider.place(relx=0.85, rely=0.84, anchor=CENTER, width=100)
                Raise_Button['text'] = "Okay"
                Raise_Button['command'] = lambda: save(Raise_slider.get(), Raise_Button)

            else:
                Raise_slider.destroy()
                Raise_Button["text"] = 'Raise'

        Raise_Button = Button(game_window, text="Raise", font="Arial 20", command=raise_fct)
        Raise_Button.place(relx=0.85, rely=0.95, anchor=CENTER, width=100, height=55)

        def fold():
            self.queueGC.put(['fold', 0])

        # Checkd
        Fold_Button = Button(game_window, text="Fold", font="Arial 20", command=fold)
        Fold_Button.place(relx=0.75, rely=0.95, anchor=CENTER, width=100, height=55)

        # Pot Money
        self.pot_money = Label(game_window, text="Pot Money: 0$", font="Arial 20", foreground="white", bg="#393939")
        self.pot_money.place(relx=0.5, rely=0.65, anchor=CENTER)

        # Dealer Buttons
        ##        button_coords = [(500+220, 520+30), (500+220, 0+30), (23+220, 20+30), (970-45, 20+30), (23+220, 500+30), (970-45, 500+30)]
        ##        for i in range(len(button_coords)):
        ##            dealer_image = ImageTk.PhotoImage(file='dealer_button.png')
        ##            dealer_label = Canvas(width=50, height=50,bg = 'yellow')
        ##            dealer_label.place(x=button_coords[i][0],y = button_coords[i][1])
        ##            dealer_label.create_image(1.5, 1.5, image=dealer_image, anchor='nw')

        # Mainloop2
        # print(self.user_name.get())
        # place buttons
        button_coords = [(500 + 220, 520 + 30), (500 + 220, 0 + 30), (23 + 220, 20 + 30), (970 - 45, 20 + 30),
                         (23 + 220, 500 + 30), (970 - 45, 500 + 30)]
        self.player_buttons_list = []
        for i in range(0, number_of_players):
            label = Canvas(game_window, width=52, height=52,bg="white",highlightthickness=0)
            label.place(x=button_coords[i][0], y=button_coords[i][1])
            self.player_buttons_list.append(label)

        game_window.protocol("WM_DELETE_WINDOW", func=lambda: self.on_closing(game_window))
        game_window.mainloop()

    def on_closing(self, game_window):
        if self.server:
            self.process_server.terminate()
            del self.server
        self.process_client.terminate()
        del self.client
        self.flag = False
        try:
            self.music.terminate()
        except:
            pass
        game_window.destroy()

    # To DO
    # menu select start money automatic adapt small/big blind
    # winner of the round screen
    # fix problems with status image

    def main_menu(self):
        welcome_window = Tk()

        welcome_window.geometry('600x397')

        welcome_window.title("Coffee-Poker")

        background_image = PhotoImage(file="images/welcome_background1.png")
        background_label = Label(welcome_window, image=background_image)
        background_label.place(x=0, y=0, relwidth=1, relheight=1)

        heading = Label(welcome_window, text="Welcome to Coffee-Poker", font="Arial 30 bold underline",
                        foreground="white", bg="#303030")

        heading.place(relx=0.5, rely=0.1, anchor=CENTER)

        join_button = Button(welcome_window, text="Join a Game", font="Arial 20",
                             command=lambda: [welcome_window.destroy(), self.open_join_window()])

        join_button.place(relx=0.5, rely=0.4, anchor=CENTER, width=250)

        Host_button = Button(welcome_window, text="Host a Game", font="Arial 20",
                             command=lambda: [welcome_window.destroy(), self.open_host_window()])

        Host_button.place(relx=0.5, rely=0.7, anchor=CENTER, width=250)

        welcome_window.mainloop()

if __name__ == '__main__':
    gui = Poker_Gui()


from builtins import NotImplementedError
from functools import reduce
import torch
import torch_geometric
import torch.nn.functional as F
import torch.nn as nn
import numpy as np
import torch
from torch_geometric.nn import MessagePassing
from torch_geometric.utils import add_self_loops, degree
from typing import Union, Tuple
from torch_geometric.typing import OptPairTensor, Adj, Size
from torch import Tensor
from torch_sparse import SparseTensor, matmul, fill_diag, sum as sparsesum, mul, set_diag
from torch_geometric.nn.conv import MessagePassing, gat_conv, gcn_conv, sage_conv
from torch_geometric.nn.conv.gcn_conv import gcn_norm
from torch_geometric.nn.dense.linear import Linear
from torch_geometric.nn import SplineConv, GATConv, GATv2Conv, SAGEConv, GCNConv, GCN2Conv, GENConv, DeepGCNLayer, APPNP, JumpingKnowledge, GINConv
from torch_geometric.typing import (OptPairTensor, Adj, Size, NoneType,
                                    OptTensor)
from typing import Union, Tuple, Optional
from torch_geometric.utils import remove_self_loops, add_self_loops, softmax
import torch_sparse

class GINNet(torch.nn.Module):
    def __init__(self, dataset, layer_num=2, hidden=16):
        super(GINNet, self).__init__()
        self.convs = nn.ModuleList()
        if layer_num == 1:
            self.convs.append(
                GINConv(Linear(dataset.num_features, dataset.num_classes))
            )
        else:
            for num in range(layer_num):
                if num == 0:
                    self.convs.append(GINConv(Linear(dataset.num_features, hidden), train_eps=True))
                elif num == layer_num - 1:
                    self.convs.append(GINConv(Linear(hidden, dataset.num_classes), train_eps=True))
                else:
                    self.convs.append(GINConv(Linear(hidden, hidden), train_eps=True))

    def reset_parameters(self):
        for conv in self.convs:
            conv.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                x = conv(x, edge_index)
            else:
                x = F.relu(conv(x, edge_index))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return F.log_softmax(x, dim=1)

class JKNet(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, num_layers, dropout, mode='cat'):
        super().__init__()

        self.convs = torch.nn.ModuleList()
        self.convs.append(GCNConv(in_channels, hidden_channels, cached=False))
        # self.bns = torch.nn.ModuleList()
        # self.bns.append(torch.nn.BatchNorm1d(hidden_channels))
        for _ in range(num_layers - 1):
            self.convs.append(GCNConv(hidden_channels, hidden_channels, cached=False))
            # self.bns.append(torch.nn.BatchNorm1d(hidden_channels))
        self.jump = JumpingKnowledge(mode=mode, channels=hidden_channels, num_layers=num_layers)
        if mode == 'cat':
            self.lin = Linear(num_layers * hidden_channels, out_channels)
        else:
            self.lin = Linear(hidden_channels, out_channels)

        self.dropout = dropout
        self.adj_t_cache = None

    def reset_parameters(self):
        for conv in self.convs:
            conv.reset_parameters()
        # for bn in self.bns:
        #     bn.reset_parameters()

        self.jump.reset_parameters()
        self.lin.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        if self.adj_t_cache is None:
            self.adj_t_cache = torch_sparse.SparseTensor(row=edge_index[1], col=edge_index[0], value=torch.ones(data.edge_index.shape[1]).to(edge_index.device), sparse_sizes=(x.shape[0], x.shape[0]))
            self.adj_t_cache = gcn_norm(self.adj_t_cache)
            # self.adj_t_cache = adj_norm(self.adj_t_cache, norm='symmetric')
        xs = []
        for i, conv in enumerate(self.convs):
            x = conv(x, self.adj_t_cache)
            # x = self.bns[i](x)
            x = F.relu(x)
            x = F.dropout(x, p=self.dropout, training=self.training)
            xs += [x]

        x = self.jump(xs)
        x = self.lin(x)

        return F.log_softmax(x, dim=-1)

class APPNP_Net(torch.nn.Module):
    def __init__(self, dataset, hidden=16):
        super().__init__()
        self.lin1 = Linear(dataset.num_features, hidden)
        self.lin2 = Linear(hidden, dataset.num_classes)
        self.prop1 = APPNP(10, 0.1)

    def reset_parameters(self):
        self.lin1.reset_parameters()
        self.lin2.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        x = F.dropout(x, p=0.5, training=self.training)
        x = F.relu(self.lin1(x))
        x = F.dropout(x, p=0.5, training=self.training)
        x = self.lin2(x)
        x = self.prop1(x, edge_index)
        return F.log_softmax(x, dim=1)

class DeeperGCN(torch.nn.Module):
    def __init__(self, dataset, hidden_channels, num_layers):
        super().__init__()

        self.node_encoder = Linear(dataset.num_features, hidden_channels)

        self.layers = torch.nn.ModuleList()
        for i in range(1, num_layers + 1):
            conv = GENConv(hidden_channels, hidden_channels, aggr='softmax',
                           t=1.0, learn_t=True, num_layers=2, norm='layer')
            norm = nn.LayerNorm(hidden_channels, elementwise_affine=True)
            act = nn.ReLU(inplace=True)

            layer = DeepGCNLayer(conv, norm, act, block='res+', dropout=0.1,
                                 ckpt_grad=i % 3)
            self.layers.append(layer)

        self.lin = Linear(hidden_channels, dataset.num_classes)

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        x = self.node_encoder(x)

        x = self.layers[0].conv(x, edge_index)

        for layer in self.layers[1:]:
            x = layer(x, edge_index)

        x = self.layers[0].act(self.layers[0].norm(x))
        x = F.dropout(x, p=0.1, training=self.training)
        x = self.lin(x)
        return F.log_softmax(x, dim=1)

class GCN2(torch.nn.Module):
    def __init__(self, dataset, hidden_channels, num_layers, alpha, theta,
                 shared_weights=True, dropout=0.0):
        super().__init__()

        self.lins = torch.nn.ModuleList()
        self.lins.append(Linear(dataset.num_features, hidden_channels))
        self.lins.append(Linear(hidden_channels, dataset.num_classes))
        self.adj_t_cache = None
        self.convs = torch.nn.ModuleList()
        for layer in range(num_layers):
            self.convs.append(
                GCN2Conv(hidden_channels, alpha, theta, layer + 1,
                         shared_weights, normalize=False))

        self.dropout = dropout

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        if self.adj_t_cache is None:
            self.adj_t_cache = torch_sparse.SparseTensor(row=edge_index[1], col=edge_index[0], value=torch.ones(data.edge_index.shape[1]).to(edge_index.device), sparse_sizes=(x.shape[0], x.shape[0]))
            self.adj_t_cache = gcn_norm(self.adj_t_cache)
            # self.adj_t_cache = adj_norm(self.adj_t_cache, norm='symmetric')
        x = F.dropout(x, self.dropout, training=self.training)
        x = x_0 = self.lins[0](x).relu()

        for conv in self.convs:
            x = F.dropout(x, self.dropout, training=self.training)
            x = conv(x, x_0, self.adj_t_cache)
            x = x.relu()

        x = F.dropout(x, self.dropout, training=self.training)
        x = self.lins[1](x)

        return F.log_softmax(x, dim=1)

class ConvNet(torch.nn.Module):
    def __init__(self, dataset):
        super(ConvNet, self).__init__()
        self.conv1 = SplineConv(dataset.num_features, 16, dim=1, kernel_size=2)
        self.conv2 = SplineConv(16, dataset.num_classes, dim=1, kernel_size=2)

    def forward(self, data):
        x, edge_index, edge_attr = data.x, data.edge_index, data.edge_attr
        x = F.dropout(x, training=self.training)
        x = F.elu(self.conv1(x, edge_index, edge_attr))
        x = F.dropout(x, training=self.training)
        x = self.conv2(x, edge_index, edge_attr)
        return F.log_softmax(x, dim=1)

class MLP(nn.Module):
    def __init__(self, in_size, out_size, hidden):
        super(MLP, self).__init__()
        self.input_layer = nn.Linear(in_size, hidden)
        # self.hidden_layer = nn.Linear(hidden, hidden)
        self.out_layer = nn.Linear(hidden, out_size)
        self.reset_parameters()
        # self.adj = torch.sparse_coo_tensor([np.arange(0, 4040), np.arange(0, 4040)], torch.ones(4040), size=(4040, 4040)).requires_grad_(False)
        # self.adj = torch.eye(4040).to_sparse().requires_grad_(False)
    def reset_parameters(self):
        self.input_layer.reset_parameters()
        # self.hidden_layer.reset_parameters()
        self.out_layer.reset_parameters()
    def forward(self, data):
        x = data.x
        x = self.input_layer(x)
        x = F.dropout(F.relu(x), p=0.5, training=self.training)
        x = self.out_layer(x)
        logits = F.log_softmax(x, dim=1)
        return logits
    def get_emb(self, data):
        x = data.x
        x = self.input_layer(x)
        x = F.relu(x)
        return x
    def get_logits(self, data):
        x = data.x
        x = self.input_layer(x)
        x = F.relu(F.dropout(x, p=0.5, training=self.training))
        logits = self.out_layer(x)
        return logits

class GCNNet(torch.nn.Module):
    def __init__(self, dataset, layer_num=2, hidden=16):
        super(GCNNet, self).__init__()
        self.convs = nn.ModuleList()
        if layer_num == 1:
            self.convs.append(
                GCNConv(dataset.num_features, dataset.num_classes)
            )
        else:
            for num in range(layer_num):
                if num == 0:
                    self.convs.append(GCNConv(dataset.num_features, hidden))
                elif num == layer_num - 1:
                    self.convs.append(GCNConv(hidden, dataset.num_classes))
                else:
                    self.convs.append(GCNConv(hidden, hidden))

    def reset_parameters(self):
        for conv in self.convs:
            conv.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                x = conv(x, edge_index)
            else:
                x = F.relu(conv(x, edge_index))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return F.log_softmax(x, dim=1)

    def get_emb(self, data):
        x, edge_index = data.x, data.edge_index
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                # x = conv(x, edge_index)
                continue
            else:
                x = F.relu(conv(x, edge_index))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return x
    def get_logits(self, data):
        x, edge_index = data.x, data.edge_index
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                x = conv(x, edge_index)
                # continue
            else:
                x = F.relu(conv(x, edge_index))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return x

class GATv2(torch.nn.Module):
    def __init__(self, in_channels, hidden_channels, out_channels, num_layers, heads,
                 dropout, att_dropout):
        super(GATv2, self).__init__()
        self.convs = torch.nn.ModuleList()
        self.convs.append(GATv2Conv(in_channels, hidden_channels, heads=heads, dropout=att_dropout, concat=True))

        self.bns = torch.nn.ModuleList()
        self.bns.append(torch.nn.BatchNorm1d(hidden_channels * heads))
        for _ in range(num_layers - 2):
            self.convs.append(GATv2Conv(hidden_channels * heads, hidden_channels, heads=heads, dropout=att_dropout, concat=True))
            self.bns.append(torch.nn.BatchNorm1d(hidden_channels * heads))
        self.convs.append(GATv2Conv(hidden_channels * heads, out_channels, heads=1, dropout=att_dropout, concat=False))

        self.dropout = dropout
        self.adj_t_cache = None

    def reset_parameters(self):
        for conv in self.convs:
            conv.reset_parameters()
        for bn in self.bns:
            bn.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index

        assert isinstance(edge_index, torch.Tensor)
        if  self.adj_t_cache == None:
            self.adj_t_cache = torch_sparse.SparseTensor(row=edge_index[1], col=edge_index[0], value=torch.ones(data.edge_index.shape[1]).to(edge_index.device), sparse_sizes=(x.shape[0], x.shape[0]))
            # self.adj_t_cache = adj_norm(self.adj_t_cache, norm='row')

        # add self loop
        if isinstance(edge_index, Tensor):
            num_nodes = x.size(0)
            edge_index, edge_attr = remove_self_loops(
                edge_index)
            edge_index, edge_attr = add_self_loops(
                edge_index, fill_value='mean',
                num_nodes=num_nodes)
        elif isinstance(edge_index, SparseTensor):
            if self.edge_dim is None:
                edge_index = set_diag(edge_index)
            else:
                raise NotImplementedError(
                    "The usage of 'edge_attr' and 'add_self_loops' "
                    "simultaneously is currently not yet supported for "
                    "'edge_index' in a 'SparseTensor' form")

        for i, conv in enumerate(self.convs[:-1]):
            x = conv(x, edge_index) # for GATv2Conv
            # x = self.bns[i](x)
            x = F.elu(x)
            x = F.dropout(x, p=self.dropout, training=self.training)
        x = self.convs[-1](x, edge_index) # for GATv2Conv

        return x.log_softmax(dim=-1)

class MLP(torch.nn.Module):
    # MLP
    def __init__(self, dim_in, dim_out, dim_hidden=64, layer_num=2, root_weight=True, \
                 use_norm=False, norm_mode='PN-SCS', norm_scale=1, log_softmax=False):
        super(MLP, self).__init__()
        self.layers = nn.ModuleList()
        if layer_num == 1:
            self.layers.append(
                Linear(dim_in, dim_out, weight_initializer='glorot')
            )
        else:
            for num in range(layer_num):
                if num == 0:
                    self.layers.append(Linear(dim_in, dim_hidden, weight_initializer='glorot'))
                elif num == layer_num - 1:
                    self.layers.append(Linear(dim_hidden, dim_out, weight_initializer='glorot'))
                else:
                    self.layers.append(Linear(dim_hidden, dim_hidden, weight_initializer='glorot'))
        if use_norm:
            self.norm = PairNorm(mode=norm_mode, scale=norm_scale)
        self.use_norm = use_norm
        self.log_softmax = log_softmax

    def reset_parameters(self):
        for layer in self.layers:
            layer.reset_parameters()

    def forward(self, x, edge_index):
        for ind, layer in enumerate(self.layers):
            if ind == len(self.layers) -1:
                x = layer(x)
            else:
                x = layer(x)
                if self.use_norm:
                    x = self.norm(x)
                x = F.relu(x)
                x = F.dropout(x, p=0.5, training=self.training)
        # return feature without log_softmax/softmax
        if self.log_softmax:
            x = F.log_softmax(x, dim=1)
        return x

class GAT(torch.nn.Module):
    def __init__(self, dataset, hidden=16, head=8):
        super(GAT, self).__init__()
        self.conv1 = GATConv(
            dataset.num_features,
            hidden,
            heads=head,
            concat=True,
            dropout=0.6)
        self.conv2 = GATConv(
            hidden * head,
            dataset.num_classes,
            heads=1,
            concat=False,
            dropout=0.6)

    def reset_parameters(self):
        self.conv1.reset_parameters()
        self.conv2.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        # x = F.dropout(x, p=0.6, training=self.training)
        x = F.elu(self.conv1(x, edge_index))
        x = F.dropout(x, p=0.6, training=self.training)
        x = self.conv2(x, edge_index)
        return F.log_softmax(x, dim=1)

    def get_emb(self, data):
        x, edge_index = data.x, data.edge_index
        # x = F.dropout(x, p=0.6, training=self.training)
        x = F.elu(self.conv1(x, edge_index))
        # x = F.dropout(x, p=0.6, training=self.training)
        # x = self.conv2(x, edge_index)
        return x

class GraphSAGE(torch.nn.Module):
    def __init__(self, dataset, layer_num=2, hidden=16, root_weight=True):
        super(GraphSAGE, self).__init__()
        self.convs = nn.ModuleList()
        if layer_num == 1:
            self.convs.append(
                SAGEConv(dataset.num_features, dataset.num_classes, root_weight=root_weight)
            )
        else:
            for num in range(layer_num):
                if num == 0:
                    self.convs.append(SAGEConv(dataset.num_features, hidden, root_weight=root_weight))
                elif num == layer_num - 1:
                    self.convs.append(SAGEConv(hidden, dataset.num_classes, root_weight=root_weight))
                else:
                    self.convs.append(SAGEConv(hidden, hidden, root_weight=root_weight))

    def reset_parameters(self):
        for conv in self.convs:
            conv.reset_parameters()

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        adj_sp = torch_sparse.SparseTensor(row=edge_index[1], col=edge_index[0], value=torch.ones(edge_index.shape[1]).to(x.device), sparse_sizes=(x.shape[0], x.shape[0]))
        # adj_sp = edge_index
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                x = conv(x, adj_sp)
            else:
                x = F.relu(conv(x, adj_sp))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return F.log_softmax(x, dim=1)

    def get_emb(self, data, layer_num=1):
        x, edge_index = data.x, data.edge_index
        adj_sp = torch_sparse.SparseTensor(row=edge_index[0], col=edge_index[1], value=torch.ones(edge_index.shape[1]).to(x.device), sparse_sizes=(x.shape[0], x.shape[0]))
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                # x = conv(x, adj_sp)
                continue
            else:
                x = F.relu(conv(x, adj_sp))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return x

    def get_logits(self, data, layer_num=1):
        x, edge_index = data.x, data.edge_index
        adj_sp = torch_sparse.SparseTensor(row=edge_index[0], col=edge_index[1], value=torch.ones(edge_index.shape[1]).to(x.device), sparse_sizes=(x.shape[0], x.shape[0]))
        for ind, conv in enumerate(self.convs):
            if ind == len(self.convs) -1:
                x = conv(x, adj_sp)
            else:
                x = F.relu(conv(x, adj_sp))
                x = F.dropout(x, p=0.5, training=self.training)
                # x = conv(x, edge_index)
        return x

# def adj_norm(adj, norm='row'):
#     if not adj.has_value():
#         adj = adj.fill_value(1., dtype=None)
#     # add self loop
#     adj = fill_diag(adj, 1.)
#     deg = sparsesum(adj, dim=1)
#     if norm == 'symmetric':
#         deg_inv_sqrt = deg.pow_(-0.5)
#         deg_inv_sqrt.masked_fill_(deg_inv_sqrt == float('inf'), 0.)
#         adj = mul(adj, deg_inv_sqrt.view(-1, 1)) # row normalization
#         adj = mul(adj, deg_inv_sqrt.view(1, -1)) # col normalization
#     elif norm == 'row':
#         deg_inv_sqrt = deg.pow_(-1)
#         deg_inv_sqrt.masked_fill_(deg_inv_sqrt == float('inf'), 0.)
#         adj = mul(adj, deg_inv_sqrt.view(-1, 1)) # row normalization
#     else:
#         raise NotImplementedError('Not implete adj norm: {}'.format(norm))
#     return adj

def adj_norm(adj, norm='row'):
    if not adj.has_value():
        adj = adj.fill_value(1., dtype=None)
    # add self loop
    adj = fill_diag(adj, 0.)
    adj = fill_diag(adj, 1.)
    deg = sparsesum(adj, dim=1)
    if norm == 'symmetric':
        deg_inv_sqrt = deg.pow_(-0.5)
        deg_inv_sqrt.masked_fill_(deg_inv_sqrt == float('inf'), 0.)
        adj = mul(adj, deg_inv_sqrt.view(-1, 1)) # row normalization
        adj = mul(adj, deg_inv_sqrt.view(1, -1)) # col normalization
    elif norm == 'row':
        deg_inv_sqrt = deg.pow_(-1)
        deg_inv_sqrt.masked_fill_(deg_inv_sqrt == float('inf'), 0.)
        adj = mul(adj, deg_inv_sqrt.view(-1, 1)) # row normalization
    else:
        raise NotImplementedError('Not implete adj norm: {}'.format(norm))
    return adj


from turtle import Turtle
FONT=("Courier",15,"normal")
ALIGN="center"
GAME_FONT=("Ubuntu",50,"bold")
MOVE_DISTANCE=30

class ScoreBoard(Turtle):
    def __init__(self,color,pos):
        super().__init__()
        self.color(color)
        self.penup()
        self.hideturtle()
        self.position=pos
        self.goto(self.position)
        self.moves=0
        self.dist=0
        self.update_score()

    def update_score(self):
        self.moves+=1
        self.dist=self.moves*MOVE_DISTANCE

    def prompt(self):
        self.clear()
        self.write(f"Moves: {self.moves} ",font=FONT,align=ALIGN)
        self.goto(self.position[0],self.position[1]-20)
        self.write(f"Distance: {self.dist}",font=FONT,align=ALIGN)
        self.goto(self.position)

    def game_over(self,winner):
        self.home()
        self.color("black")
        self.write("Game Over",font=GAME_FONT,align=ALIGN)
        self.goto(0,-60)
        self.write(f"{winner} wins!!",font=GAME_FONT,align=ALIGN)


# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8 compliant>

import logging

import bpy
import gpu
from gpu_extras.batch import batch_for_shader

log = logging.getLogger(__name__)

# Color constants

background_color = (0.18, 0.18, 0.18, 1.0)
hover_effect_color = (1.0, 1.0, 1.0, 0.05)
theme_selected_object = bpy.context.preferences.themes['Default'].view_3d.object_selected
theme_active_object = bpy.context.preferences.themes['Default'].view_3d.object_active
selection_color = (theme_active_object[0], theme_active_object[1], theme_active_object[2], 1.0)

# Shaders and batches

line_indices = ((0, 1), (1, 2), (2, 3), (3, 0))
rect_indices = ((0, 1, 2), (2, 1, 3))
rect_coords = ((0, 0), (1, 0), (1, 1), (0, 1))

ucolor_2d_shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
ucolor_2d_rect_batch = batch_for_shader(ucolor_2d_shader, 'TRI_FAN', {"pos": rect_coords})

ucolor_lines_rect_batch = batch_for_shader(
    ucolor_2d_shader, 'LINES', {"pos": rect_coords}, indices=line_indices
)

image_2d_shader = gpu.shader.from_builtin('2D_IMAGE')
image_2d_batch = batch_for_shader(
    image_2d_shader, 'TRI_FAN', {"pos": rect_coords, "texCoord": rect_coords}
)

def draw_background(size):
    """Draw a solid rectangle with the background color with the given size"""

    with gpu.matrix.push_pop():
        gpu.matrix.translate([0, 0])
        gpu.matrix.scale(size)

        ucolor_2d_shader.bind()
        ucolor_2d_shader.uniform_float("color", background_color)
        ucolor_2d_rect_batch.draw(ucolor_2d_shader)

def draw_hover_highlight(position, size):
    """Draw a rectangular highlight"""

    with gpu.matrix.push_pop():
        gpu.matrix.translate(position)
        gpu.matrix.scale(size)

        gpu.state.blend_set('ALPHA')

        ucolor_2d_shader.bind()
        ucolor_2d_shader.uniform_float("color", hover_effect_color)
        ucolor_2d_rect_batch.draw(ucolor_2d_shader)

        gpu.state.blend_set('NONE')

def draw_selected_frame(position, size):
    """Draw a rectangular frame"""

    with gpu.matrix.push_pop():
        gpu.matrix.translate(position)
        gpu.matrix.scale(size)

        ucolor_2d_shader.bind()
        ucolor_2d_shader.uniform_float("color", selection_color)
        ucolor_lines_rect_batch.draw(ucolor_2d_shader)

def draw_boolean_tag(position, size, color):

    with gpu.matrix.push_pop():
        gpu.matrix.translate(position)
        gpu.matrix.scale(size)

        # Render a colored rectangle
        gpu.state.blend_set('ALPHA')

        ucolor_2d_shader.bind()
        ucolor_2d_shader.uniform_float("color", color)
        ucolor_2d_rect_batch.draw(ucolor_2d_shader)

        gpu.state.blend_set('NONE')

def draw_thumbnails(thumbnail_images, size):

    for img in thumbnail_images:
        # Get the GPU image texture.
        texture = gpu.texture.from_image(img.id_image)

        # Push the position and image size (pop when out of scope).
        with gpu.matrix.push_pop():
            gpu.matrix.translate(img.pos)
            gpu.matrix.scale(size)

            # Bind the image shader and render
            image_2d_shader.bind()
            image_2d_shader.uniform_sampler("image", texture)
            image_2d_batch.draw(image_2d_shader)


#!/usr/bin/python3

# Script         Ops Challenge: Signature-based Malware Detection Part 1 of 3
# Purpose        Detection and remediation of malware is the core function
# Why            Learn how to use the import sys

import sys
# Get the file name to search for.
filename = input("Enter the file name to search for: ")
# Get the directory to search in.
directory = input("Enter the directory to search in: ")
# Check if the directory exists.
if not os.path.exists(directory):
    print("The directory does not exist.")
    sys.exit(1)
# Get a list of all the files in the directory.
files = os.listdir(directory)
# Search each file in the directory by name.
for file in files:
    # Check if the file name matches the file name to search for.
    if file == filename:
        # Print the file name and location.
        print(os.path.join(directory, file))
# Print how many files were searched and how many hits were found.
print("Number of files searched:", len(files))
print("Number of hits found:", len([file for file in files if file == filename]))


import numpy as np

n = 100
seeds = range(n)
algorithms = ["GE+GE","GE+PGE"]
def compare(info,best,i,j):
    if info[i] > info[j]:
        best[i] = True
    else:
        best[j] = True

with open('sh/plot_settings.txt','r') as f:
    with open('/home/cxl/Desktop/share/table.txt','w') as f_out:
        for i,line in enumerate( f.readlines() ):
            info = np.zeros(7)
            M,C,W = map(int,line.split(' '))
            for s in seeds:
                path = f'game/results/{M}-{C}-{W}/{algorithms[0]} 5-5/{s}/fitness.txt'
                with open(path,'r') as t:
                    info[0] += float(t.readline())
                path = f'game/results/{M}-{C}-{W}/{algorithms[0]} 5-5/{s}/time.txt'
                with open(path, 'r') as t:
                    info[2] += float(t.readline())
                path = f'game/results/{M}-{C}-{W}/{algorithms[0]} 5-5/{s}/bt_fit_ratio.txt'
                with open(path, 'r') as t:
                    info[1] += float(t.readline())
                if M <= 100:
                    path = f'game/results/{M}-{C}-{W}/{algorithms[1]} 5-5/{s}/fitness.txt'
                    with open(path, 'r') as t:
                        info[3] += float(t.readline())
                    path = f'game/results/{M}-{C}-{W}/{algorithms[1]} 5-5/{s}/time.txt'
                    with open(path, 'r') as t:
                        times = np.array(list(map(float, t.readlines()[:3])))
                        info[5] += times[0]
                        info[6] += times[1] + times[2]
                    path = f'game/results/{M}-{C}-{W}/{algorithms[1]} 5-5/{s}/bt_fit_ratio.txt'
                    with open(path, 'r') as t:
                        info[4] += float(t.readline())

            print(info)

            info /= n
            best = [False for _ in range(7)]
            if info[0] > info[3]:
                best[0] = True
            else:
                best[3] = True

            if info[1] > info[4]:
                best[1] = True
            else:
                best[4] = True

            info_str = ['' for _ in range(7)]
            info_str[0] = f'{info[0]:.3f}'
            info_str[2] = f'{info[2]:.3f}'
            info_str[1] = f'{100 * info[1]:.1f}\\%'
            if M <= 100:
                info_str[3] = f'{info[3]:.3f}'
                info_str[5] = f'{info[5]:.3f}'
                info_str[4] = f'{100 * info[4]:.1f}\\%'
                info_str[6] = f'{100 * info[6] / info[5]:.1f}\\%'
                if info[2] > info[5]:
                    best[5] = True
                else:
                    best[2] = True
            else:
                info_str[3:7] = ['-' for _ in range(4)]
                best[2] = True
            for index in range(len(info_str)):
                if best[index]:
                    info_str[index] = f'\\textbf{{{info_str[index]}}}'
            f_out.write(f'{i} & {M} & {C} & {W} & {" & ".join(info_str)} \\\\\n')


from phgl_imp import *
from .zqh_crg_ctrl_parameters import zqh_crg_ctrl_parameter
from zqh_tilelink.zqh_tilelink_node_module_main import zqh_tilelink_node_module
from .zqh_crg_ctrl_bundles import *

class zqh_crg_ctrl(zqh_tilelink_node_module):
    def set_par(self):
        super(zqh_crg_ctrl, self).set_par()
        self.p = zqh_crg_ctrl_parameter()

    def gen_node_tree(self):
        super(zqh_crg_ctrl, self).gen_node_tree()
        self.gen_node_slave(
            'crg_ctrl_slave',
            tl_type = 'tl_uh',
            bundle_p = self.p.gen_tl_bundle_p())
        self.p.crg_ctrl_slave.print_up()
        self.p.crg_ctrl_slave.print_address_space()

    def set_port(self):
        super(zqh_crg_ctrl, self).set_port()
        self.io.var(inp('clock_ref'))
        self.io.var(inp('reset_por'))
        self.io.var(zqh_crg_ctrl_cfg_io('cfg'))

    def main(self):
        super(zqh_crg_ctrl, self).main()
        self.gen_node_interface('crg_ctrl_slave')
        assert(self.tl_in[0].a.bits.data.get_w() >= 32)

        clock_ref_offset = 0x00
        core_pll_offset = 0x04
        eth_pll_offset = 0x08
        ddr_pll_offset = 0x0c
        reset_offsest = 0x10

        #{{{
        crg_cfg_mem_wr_valid = bits('crg_cfg_mem_wr_valid', init = 0)
        crg_cfg_mem_wr_data  = bits('crg_cfg_mem_wr_data', w = 32, init = 0)
        crg_cfg_mem_rd_valid = bits('crg_cfg_mem_rd_valid', init = 0)
        crg_cfg_mem_rd_data  = bits('crg_cfg_mem_rd_data', w = 32, init = 0)
        crg_cfg_mem_address  = bits('crg_cfg_mem_address', w = 32, init = 0)

        req_ready = bits('req_ready', init = 1)
        wr_resp_valid = bits('wr_resp_valid', init = 0)
        rd_resp_valid = bits('rd_resp_valid', init = 0)
        def func_reg_write(reg_ptr, fire, address, size, wdata, mask_bit,
            wr_valid = None, wr_data = None, access_address = None):
            with when(fire):
                wr_valid /= 1
                access_address /= address
            wr_data /= wdata
            return (req_ready, wr_resp_valid)
        def func_reg_read(reg_ptr, fire, address, size, mask_bit,
            rd_valid = None, rd_data = None, access_address = None):
            with when(fire):
                rd_valid /= 1
                access_address /= address
            return (req_ready, rd_resp_valid, rd_data.pack())
        def wr_process_gen(wr_valid, wr_data):
            return lambda a0, a1, a2, a3, a4, a5: func_reg_write(
                a0, a1, a2, a3, a4, a5, wr_valid, wr_data, crg_cfg_mem_address)
        def rd_process_gen(rd_valid, rd_data):
            return lambda a0, a1, a2, a3, a4: func_reg_read(
                a0, a1, a2, a3, a4, rd_valid, rd_data, crg_cfg_mem_address)
        self.cfg_reg(csr_reg_group(
            'crg_cfg_mem',
            offset = 0x000,
            size = 4,
            mem_size = 2**12,
            fields_desc = [
                csr_reg_field_desc(
                    'data', access = 'VOL', width = 32,
                    write = wr_process_gen(crg_cfg_mem_wr_valid, crg_cfg_mem_wr_data),
                    read = rd_process_gen(crg_cfg_mem_rd_valid, crg_cfg_mem_rd_data))]))
        #}}}

        #tile clock domain -> clock_ref domian sync
        req_sync = async_ready_valid('req_sync',
            gen = lambda _: bits(_, w = 41)) #[wr_rd_flag, address, data]
        req_sync.io.enq_clock /= self.io.clock
        req_sync.io.enq_reset /= self.io.reset
        req_sync.io.deq_clock /= self.io.clock_ref
        req_sync.io.deq_reset /= self.io.reset_por
        req_sync.io.deq.ready /= 1

        #clock_ref domian -> tile clock domain sync
        resp_sync = async_ready_valid('resp_sync',
            gen = lambda _: bits(_, w = 33)) #[wr_rd_flag, data]
        resp_sync.io.enq_clock /= self.io.clock_ref
        resp_sync.io.enq_reset /= self.io.reset_por
        resp_sync.io.deq_clock /= self.io.clock
        resp_sync.io.deq_reset /= self.io.reset
        resp_sync.io.deq.ready /= 1

        #
        #tile clock domain action
        #{{{
        #request
        req_sync.io.enq.valid /= crg_cfg_mem_wr_valid | crg_cfg_mem_rd_valid
        req_sync.io.enq.bits /= cat([
            crg_cfg_mem_wr_valid,
            crg_cfg_mem_address[7:0],
            crg_cfg_mem_wr_data])
        req_ready /= req_sync.io.enq.ready

        #response
        crg_cfg_mem_rd_data /= resp_sync.io.deq.bits[31:0]
        wr_resp_valid /= resp_sync.io.deq.fire() & resp_sync.io.deq.bits[32]
        rd_resp_valid /= resp_sync.io.deq.fire() & ~resp_sync.io.deq.bits[32]
        #}}}

        #
        #clock_ref domain action
        #{{{
        clock_ref_cfg_reg = reg_r(
            'clock_ref_cfg_reg',
            w = 32,
            clock = self.io.clock_ref,
            reset = self.io.reset_por)

        core_pll_cfg_reg = zqh_crg_ctrl_core_pll_cfg('core_pll_cfg_reg').as_reg(
            tp = 'reg_rs',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)
        core_pll_cfg_reg.div_r.rs_vl = value(1, w = 8)
        core_pll_cfg_reg.mul.rs_vl = value(1, w = 8)
        core_pll_cfg_reg.div_q.rs_vl = value(1, w = 8)
        core_pll_cfg_reg.bypass.rs_vl = value(1, w = 1)
        core_pll_lock_reg = reg_r(
            'core_pll_lock_reg',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)

        eth_pll_cfg_reg = zqh_crg_ctrl_eth_pll_cfg('eth_pll_cfg_reg').as_reg(
            tp = 'reg_rs',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)
        eth_pll_cfg_reg.div_r.rs_vl = value(1, w = 8)
        eth_pll_cfg_reg.mul.rs_vl = value(1, w = 8)
        eth_pll_cfg_reg.div_q.rs_vl = value(1, w = 8)
        eth_pll_cfg_reg.bypass.rs_vl = value(1, w = 1)
        eth_pll_cfg_reg.en.rs_vl = value(1, w = 1)
        eth_pll_lock_reg = reg_r(
            'eth_pll_lock_reg',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)

        ddr_pll_cfg_reg = zqh_crg_ctrl_ddr_pll_cfg('ddr_pll_cfg_reg').as_reg(
            tp = 'reg_rs',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)
        ddr_pll_cfg_reg.div_r.rs_vl = value(1, w = 8)
        ddr_pll_cfg_reg.mul.rs_vl = value(1, w = 8)
        ddr_pll_cfg_reg.div_q.rs_vl = value(1, w = 8)
        ddr_pll_cfg_reg.bypass.rs_vl = value(1, w = 1)
        ddr_pll_cfg_reg.en.rs_vl = value(1, w = 1)
        ddr_pll_lock_reg = reg_r(
            'ddr_pll_lock_reg',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)

        reset_cfg_reg = zqh_crg_ctrl_reset_cfg('reset_cfg_reg').as_reg(
            tp = 'reg_r',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)

        crg_cfg_mem_reg_wr_flag = reg_r(
            'crg_cfg_mem_reg_wr_flag',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)
        crg_cfg_mem_reg_rd_flag = reg_r(
            'crg_cfg_mem_reg_rd_flag',
            clock = self.io.clock_ref,
            reset = self.io.reset_por)
        crg_cfg_mem_reg_address = reg(
            'crg_cfg_mem_reg_address',
            w = 8,
            clock = self.io.clock_ref,
            reset = self.io.reset_por)

        with when(req_sync.io.deq.fire()):
            address = req_sync.io.deq.bits[39:32]
            is_wr = req_sync.io.deq.bits[40]
            crg_cfg_mem_reg_wr_flag /= is_wr
            crg_cfg_mem_reg_rd_flag /= ~is_wr
            crg_cfg_mem_reg_address /= address
            with when(is_wr):
                with when(address == clock_ref_offset):
                    clock_ref_cfg_reg /= req_sync.io.deq.bits[31:0]
                with when(address == core_pll_offset):
                    core_pll_cfg_reg /= req_sync.io.deq.bits[31:0]
                with when(address == eth_pll_offset):
                    eth_pll_cfg_reg /= req_sync.io.deq.bits[31:0]
                with when(address == ddr_pll_offset):
                    ddr_pll_cfg_reg /= req_sync.io.deq.bits[31:0]
                with when(address == reset_offsest):
                    reset_cfg_reg /= req_sync.io.deq.bits[31:0]

        resp_sync.io.enq.valid /= crg_cfg_mem_reg_wr_flag | crg_cfg_mem_reg_rd_flag
        resp_sync.io.enq.bits /= cat([
            crg_cfg_mem_reg_wr_flag,
            sel_map(
                crg_cfg_mem_reg_address,
                [
                    (clock_ref_offset, clock_ref_cfg_reg.pack().u_ext(32)),
                    (
                        core_pll_offset,
                        cat([core_pll_lock_reg, core_pll_cfg_reg.pack().u_ext(31)])),
                    (
                        eth_pll_offset,
                        cat([eth_pll_lock_reg, eth_pll_cfg_reg.pack().u_ext(31)])),
                    (
                        ddr_pll_offset,
                        cat([ddr_pll_lock_reg, ddr_pll_cfg_reg.pack().u_ext(31)])),
                    (reset_offsest, reset_cfg_reg.pack().u_ext(32))])])

        with when(resp_sync.io.enq.fire()):
            crg_cfg_mem_reg_wr_flag /= 0
            crg_cfg_mem_reg_rd_flag /= 0
        #}}}

        self.io.cfg.clock_ref_cfg /= clock_ref_cfg_reg
        self.io.cfg.core_pll_cfg /= core_pll_cfg_reg
        self.io.cfg.eth_pll_cfg /= eth_pll_cfg_reg
        self.io.cfg.ddr_pll_cfg /= ddr_pll_cfg_reg
        self.io.cfg.reset_cfg /= reset_cfg_reg
        core_pll_lock_reg /= self.io.cfg.core_pll_lock
        eth_pll_lock_reg /= self.io.cfg.eth_pll_lock
        ddr_pll_lock_reg /= self.io.cfg.ddr_pll_lock


# -*- coding: utf-8 -*-
# -*- Python Version: 2.7 -*-

"""GHCompo Interface: HBPH - Set Model Project Data."""

try:
    from typing import Optional, List, Dict
except ImportError:
    pass  # IronPython 2.7

try:
    from honeybee import model
except ImportError as e:
    raise ImportError("\nFailed to import honeybee:\n\t{}".format(e))

try:
    from honeybee_ph.team import ProjectTeamMember, ProjectTeam
except ImportError as e:
    raise ImportError("\nFailed to import honeybee_ph:\n\t{}".format(e))

try:
    from honeybee_ph_rhino import gh_io
except ImportError as e:
    raise ImportError("\nFailed to import honeybee_ph_rhino:\n\t{}".format(e))

class GHCompo_SetProjectData(object):
    def __init__(
        self, _IGH, _customer, _building, _owner, _designer, _model, *args, **kwargs
    ):
        # type: (gh_io.IGH, ProjectTeamMember, ProjectTeamMember, ProjectTeamMember, ProjectTeamMember, model.Model, List, Dict) -> None
        self.IGH = _IGH
        self.customer = _customer
        self.building = _building
        self.owner = _owner
        self.designer = _designer
        self.model = _model

    def run(self):
        # type: () -> Optional[model.Model]
        if not self.model:
            return None

        # -- Make a new team
        existing_team = self.model.properties.ph.team  # type: ProjectTeam # type: ignore
        new_team = ProjectTeam()
        new_team.customer = self.customer or existing_team.customer
        new_team.building = self.building or existing_team.building
        new_team.owner = self.owner or existing_team.owner
        new_team.designer = self.designer or existing_team.designer

        # -- Set the HB-model's Team
        model_ = self.model.duplicate()  # type: model.Model # type: ignore
        model_.properties.ph.team = new_team

        return model_


import tkinter as tk
from configurations import *
import controller
import os

assets_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'pieces_image/'))
print (assets_folder) # ပုံများကို သိမ်း ထားသော ဖိုင်တည်နေရာ path ကိုရရှိရန်

class View:
	images = {} # စစ်တုရင် နယ်အရုပ်များ သိမ်းဆည်းထားရန်အတွက်
	board_color_1 = BOARD_COLOR_1
	board_color_2= BOARD_COLOR_2

	def __init__(self, parent, controller):
		self.controller = controller
		self.parent = parent
		self.create_chess_base() # အရုပ်များမပါသော စစ်တုရင် ခုံ ၊ လိုအပ်သောစာတမ်း ၊ menubar များကိုထည့်သွင်း
		self.canvas.bind("<Button-1>", self.on_square_clicked) # chess board မှာ အကွက်များ၏ row, column သိရှိနိုင်ရန်အတွက်
		self.start_new_game() # စစ်တုရင်ခုံ ပေါ်တွင် သက်ဆိုင်ရာ နယ်ရုပ်များကို သတ်မှတ်ထားသော နေရာများတွင် နေရာ ချ ရန်အတွက်

	def create_chess_base(self):
		self.create_top_menu() # အပေါ်က menu bar အတွက်
		self.create_canvas() # chess ခုံ တည်ဆောက်ရန် အတွက် canvas ဆွဲ
		self.draw_board() # canvas ပေါ်တွင် chess ခုံ ရေးဆွဲ
		self.create_bottom_frame() #

	#=================== chess ခုံ တည်ဆောက်ရန် အတွက် ၅၁၂ ၅၁၂ pixel ရှိသော canvas  တည်ဆောက် ============
	def create_canvas(self):
		canvas_width = NUMBER_OF_COLUMNS * DIMENSION_OF_EACH_SQUARE # 8 x 64 = 512
		canvas_height = NUMBER_OF_ROWS * DIMENSION_OF_EACH_SQUARE # 8 x 64 = 512
		self.canvas = tk.Canvas(self.parent, width=canvas_width, height=canvas_height) # canvas class ကို root window နှင့် ချိတ်ဆက်ရန်အတွက်
		self.canvas.pack(padx=8, pady=8) # canvas ကို နေရာချရန်အတွက်

	#============================= draw board ==================================
	def draw_board(self):
		current_color = BOARD_COLOR_2
		for row in range(NUMBER_OF_ROWS):
			current_color = self.get_alternate_color(current_color)
			for col in range(NUMBER_OF_COLUMNS):
				x1, y1 = self.get_x_y_coordinate(row, col)
				x2, y2 = x1 + DIMENSION_OF_EACH_SQUARE, y1 + DIMENSION_OF_EACH_SQUARE
				self.canvas.create_rectangle(x1, y1, x2, y2, fill=current_color)
				current_color = self.get_alternate_color(current_color)

	def get_x_y_coordinate(self, row, col):
		x = (col * DIMENSION_OF_EACH_SQUARE)
		y = ((7 - row) * DIMENSION_OF_EACH_SQUARE)
		return (x,y)

	def get_alternate_color(self, current_color):
		if current_color == self.board_color_2:
			next_color = self.board_color_1
		else:
			next_color = self.board_color_2

		return next_color

	# ================= to know cell position (x,y) using mouse click ===============
	def on_square_clicked(self, event):
		clicked_row, clicked_column = self.get_clicked_row_column(event)
		print ('Hey you clicked on', clicked_row, clicked_column)

	def get_clicked_row_column(self, event):
		col_size = row_size = DIMENSION_OF_EACH_SQUARE
		print (f"x:{event.x}, y:{event.y}") # mouse position (x,y) ကို သိချင်လို့
		clicked_column = event.x // col_size
		clicked_row = 7 - (event.y // row_size) # အောက်ကနေစတဲ့ အကွက် နံပါတ် လိုချင်လို့ စုစုပေါင်းကွက်အရေအတွက် ထဲက နုတ်လိုက်တာ

		return (clicked_row, clicked_column)

	#================ Create Menu bar ===========================
	def create_top_menu(self):
		self.menu_bar = tk.Menu(self.parent) # this is main menu bar
		self.create_file_menu()
		self.create_edit_menu()

	def create_file_menu(self):
		self.file_menu = tk.Menu(self.menu_bar, tearoff=0)
		self.file_menu.add_command(
			label="New Game", command=self.on_new_game_menu_clicked) #  menu ဘားပေါ်မှာ menu name (New Game) အမည်နှင့်ထည့်

		self.menu_bar.add_cascade(label="File", menu=self.file_menu)
		self.parent.config(menu=self.menu_bar)

	def on_new_game_menu_clicked(self):
		pass

	def create_edit_menu(self):
		self.edit_menu = tk.Menu(self.menu_bar, tearoff=0)

		self.edit_menu.add_command(
			label="Preference", command=self.on_preference_menu_clicked)
		self.menu_bar.add_cascade(label='Edit', menu=self.edit_menu)
		self.parent.config(menu=self.menu_bar)

	def on_preference_menu_clicked(self):
		pass

	# =================== ကစားသူများအား အသိပေးကြော်ငြော် ရန် အတွက် စာရေးရန် နေရာ ===================
	def create_bottom_frame(self):
		self.bottom_frame = tk.Frame(self.parent, height=64)
		self.info_label = tk.Label(self.bottom_frame, text='  White to start the Game  ', fg=BOARD_COLOR_2)

		self.info_label.pack(side=tk.RIGHT, padx=8, pady=8)
		self.bottom_frame.pack(fill="x", side="bottom")

	#=================== စစ်တုရင်မှ အရုပ်များ ကို ရေးဆွဲရန် posisition(x,y) နှင့် သတ်ဆိုင်ရာ အရုပ်သတ်မှတ်ခြင်း နှင့် model data နှင့် ချိတ်ဆက်ခြင်း =======================
	def start_new_game(self):
		self.controller.reset_game_data()
		self.controller.reset_to_initial_locations() # controller မှတစ်ဆင့် model မှ data ကိုရယူရန်အတွက်
		self.draw_all_pieces()

	def draw_single_piece(self, position, piece):
		x, y = self.controller.get_numeric_notation(position) # x, y --> (0,1) ကို ကိန်းဂဏန်း ဖြင့် ရရှိရန်အတွက်

		if piece:
			filename = f"{assets_folder}/{piece.name.lower()}_{piece.color}.png"
			if filename not in self.images: # filename ဖြင့် images(dict) ထဲတွင် သိမ်းဆည်းရန်အတွက်
				self.images[filename] = tk.PhotoImage(file=filename)

			# for k, v in self.images.items():
			# 	print ('images files -->', k,v)

			x0, y0 = self.calculate_piece_coordinate(x, y) # နယ်ရုပ် ထားရမည့် တည်နေရာရရှိရန် အတွက်
			self.canvas.create_image(x0, y0, image=self.images[filename], tags=("occupied"), anchor="c")

	def calculate_piece_coordinate(self, row, col): # နယ်ရုပ်များကို စစ်တုရင်ခုံပေါ်တွင် ထားရှိရန်အတွက် pixel position ရရှိရန်အတွက်
		x0 = (col * DIMENSION_OF_EACH_SQUARE) + int(DIMENSION_OF_EACH_SQUARE/2)
		y0 = ((7-row) * DIMENSION_OF_EACH_SQUARE) + int (DIMENSION_OF_EACH_SQUARE/2)
		# print ("pixel position of pieces -> ", x0, y0)
		return (x0, y0)

	def draw_all_pieces(self):
		self.canvas.delete("occupied")
		for position, piece in self.controller.get_all_pieces_on_chess_board():
			self.draw_single_piece(position, piece)

def main(controller):
    root = tk.Tk()
    root.title("Chess")
    View(root, controller)
    root.mainloop()

def init_new_game():
    game_controller = controller.Controller()
    main(game_controller)

if __name__ == "__main__":
    init_new_game()


class Solution:
    def minFlipsMonoIncr(self, s: str) -> int:
        if len(s) == 1: return 0

        cnt_0 = s.count('0')
        cnt_1 = len(s) - cnt_0

        left_0 = 0
        left_1 = 0

        res = min(cnt_0, cnt_1)

        for i in range(len(s)):

            if s[i] == '0':
                left_0 += 1
            else:
                left_1 += 1

            right_0 = cnt_0 - left_0

            res = min(res, left_1 + right_0)

        return res

Medium/Flip String to Monotone Increasing/flip-string-to-monotone-increasing.py


import sys

input = sys.stdin.readline
sys.setrecursionlimit(10**7)

INF = 1<<60
MOD = 10**9+7
#MOD = 998244353

def main():
    n, m = map(int, input().split())
    edges = [[]*n for _ in range(n)]
    dist = [[INF]*n for _ in range(n)]

    for _ in range(m):
        a, b, c = map(int, input().split())
        a -= 1
        b -= 1
        dist[a][b] = c
        edges[a].append((b, c))

    for i in range(n):
        dist[i][i] = 0

    ans = 0

    for k in range(n):
        for i in range(n):
            for j in range(n):
                dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j])
                if dist[i][j] < INF:
                    ans += dist[i][j]

    print(ans)

if __name__ == '__main__':
    main()


from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.http.request import Request
from bushwick.items import BushwickItem

class MySpider(BaseSpider):
    name = "bushwick"
    allowed_domains = ["bushwickdaily.com"]
    start_urls = ["http://bushwickdaily.com/2013/03/sunday-read-its-who-we-are-by-cat-agonis/"]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)

        next_page = hxs.select("//div[@class='post-button-holder']/div[@class='post-button-older-wrap']/a[@class='post-button-older']/@href").extract()
        if not not next_page:
            yield Request(next_page[0], self.parse)

        category = hxs.select("//div[@class='post group']/p[@class='category-text']/a/text()").extract()

        headline = hxs.select("//div[@class='post group']/h2[@class='post-head']/text()").extract()

        metatext = hxs.select("div[@class='post group']/p[@class='meta-text']/text()").extract()

        author = hxs.select("//div[@class='post group']/p[@class='meta-text']/span[@class='written']/a/text()").extract()

        body = hxs.select("//div[@class='post group']/div[@class='entry']/p/text()").extract()

        about = hxs.select("//div[@class='post group']/div[@class='entry']/div[@class='wp-biographia-container-top']/div[@class='wp-biographia-text']/p/text()").extract()

        tags = hxs.select("//div[@class='post group']/div[@class='tags']/a/text()").extract()

        items = []

        for item in headline:
            item = BushwickItem()
            item ["category"] = category
            item ["headline"] = headline
            item ["metatext"] = metatext
            item ["author"] = author
            item ["body"] = body
            item ["about"] = about
            item ["tags"] = tags
            items.append(item)
        for item in items:
            yield item


from math import pi, log
from functools import wraps

import torch
from torch import nn, einsum
import torch.nn.functional as F

from einops import rearrange, repeat

# helpers
def exists(val):
    return val is not None

def default(val, d):
    return val if exists(val) else d

def cache_fn(f):
    cache = None
    @wraps(f)
    def cached_fn(*args, _cache = True, **kwargs):
        if not _cache:
            return f(*args, **kwargs)
        nonlocal cache
        if cache is not None:
            return cache
        cache = f(*args, **kwargs)
        return cache
    return cached_fn

# helper classes

class PreNorm(nn.Module):
    def __init__(self, dim, fn, context_dim = None):
        super().__init__()
        self.fn = fn
        self.norm = nn.LayerNorm(dim)
        self.norm_context = nn.LayerNorm(context_dim) if exists(context_dim) else None

    '''
        x : 表示中间隐式数组
        kwargs : 多余参数
            'context' - 表示原数组
    '''
    def forward(self, x, **kwargs):
        x = self.norm(x)
        # 判断是否存在'context'，若不存在，则说明是self-attention，若存在，说明是cross-attention
        if exists(self.norm_context):
            context = kwargs['context']
            normed_context = self.norm_context(context)
            kwargs.update(context = normed_context)

        return self.fn(x, **kwargs)

class GEGLU(nn.Module):
    def forward(self, x):
        x, gates = x.chunk(2, dim = -1)
        return x * F.gelu(gates)

class FeedForward(nn.Module):
    def __init__(self, dim, mult = 4):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(dim, dim * mult * 2),
            GEGLU(),
            nn.Linear(dim * mult, dim)
        )

    def forward(self, x):
        return self.net(x)
# 注意力网络
class Attention(nn.Module):
    def __init__(self, query_dim, context_dim = None, heads = 8, dim_head = 64):
        super().__init__()
        inner_dim = dim_head * heads
        context_dim = default(context_dim, query_dim)
        # QK除的比例，目的是计算softmax数值不会太大
        self.scale = dim_head ** -0.5
        # attention的头大小
        self.heads = heads
        # 产生Q以及K，V的线性层
        self.to_q = nn.Linear(query_dim, inner_dim, bias = False)
        self.to_kv = nn.Linear(context_dim, inner_dim * 2, bias = False)
        self.to_out = nn.Linear(inner_dim, query_dim)
    # 进行，attention
    def forward(self, x, context = None, mask = None):
        h = self.heads      # attention的头维度大小
        # 通过query数组求MLP得到Q数组
        q = self.to_q(x)
        context = default(context, x)       # 原数组，若context不存在，则使用Query数组（说明是self-attention）
        temp = self.to_kv(context)          # 通过对原组进行MLP，求出query维度 * 2的向量temp
        k,v = temp.chunk(2, dim = -1)       # 得到向量temp进行分裂，生成key和value
        # 根据cross_attention的头数量，来重塑Q,K,V的形状
        q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> (b h) n d', h = h), (q, k, v))

        # 爱因斯坦求和，本质是矩阵相乘，目的是求出Q*K，并乘以1/Query的维度开根号，以缩小取值，得到Q和K的比例分数
        sim = einsum('b i d, b j d -> b i j', q, k) * self.scale
        # attention, what we cannot get enough of，得到QK的softmax分数
        attn = sim.softmax(dim = -1)
        # 再将QK(softmax)与V矩阵相乘，求出QKV
        out = einsum('b i j, b j d -> b i d', attn, v)
        out = rearrange(out, '(b h) n d -> b n (h d)', h = h)
        return self.to_out(out)

# Convolutional Position Encoding
class ConvPosEnc(nn.Module):
    def __init__(self, dim_q, dim_content, k=3):
        super(ConvPosEnc, self).__init__()
        self.proj_q = nn.Conv1d(
            in_channels=dim_q,
            out_channels=dim_q,
            kernel_size=k,
            stride=1,
            padding=k//2,
            groups=dim_q
        )

        self.proj_content = nn.Conv1d(
            in_channels=dim_content,
            out_channels=dim_content,
            kernel_size=k,
            stride=1,
            padding=k // 2,
            groups=dim_content
        )

    def forward(self,q,content):
        q = q.permute(0,2,1)
        q = self.proj_q(q) + q
        q = q.permute(0,2,1)

        # B,C,H,W = content.shape
        content = content.permute(0, 2, 1)
        content = self.proj_content(content) + content
        content = content.permute(0,2,1)

        return q,content

# main class
class PerceiverIO(nn.Module):
    def __init__(
        self,
        depth,                                  # Process的层数，可以设置为0
        dim,                                    # image dim
        latent_dim = 512,                       # PC dim
        cross_heads = 1,                        # Encoder的头大小
        latent_heads = 8,                       # Process的头大小
        cross_dim_head = 64,                    # Encoder和Decoder中计算过程中的维度
        latent_dim_head = 64,                   # Process计算过程中的维度
        weight_tie_layers = False,
        pe=False
    ):
        super().__init__()

        self.pe = pe
        if(pe):
            # position encoding
            self.cpe = ConvPosEnc(
                dim_q=latent_dim,
                dim_content=dim
            )

        # Encoder部分，不一定是一层
        self.cross_attend_blocks = nn.ModuleList([
            PreNorm(latent_dim, Attention(latent_dim, dim, heads = cross_heads, dim_head = cross_dim_head), context_dim = dim),
            PreNorm(latent_dim, FeedForward(latent_dim))
        ])
        # self.cross_attend_blocks =  PreNorm(latent_dim, Attention(latent_dim, dim, heads = cross_heads, dim_head = cross_dim_head), context_dim = dim)
        # Process部分，多层
        get_latent_attn = lambda: PreNorm(latent_dim, Attention(latent_dim, heads = latent_heads, dim_head = latent_dim_head))
        get_latent_ff = lambda: PreNorm(latent_dim, FeedForward(latent_dim))
        get_latent_attn, get_latent_ff = map(cache_fn, (get_latent_attn, get_latent_ff))

        self.layers = nn.ModuleList([])
        cache_args = {'_cache': weight_tie_layers}

        for i in range(depth):
            self.layers.append(nn.ModuleList([
                get_latent_attn(**cache_args),
                get_latent_ff(**cache_args)
            ]))
        # # Decoder部分，只能为一层
        # self.decoder_cross_attn = PreNorm(queries_dim, Attention(queries_dim, latent_dim, heads = cross_heads, dim_head = cross_dim_head), context_dim = latent_dim)
        # self.decoder_ff = PreNorm(queries_dim, FeedForward(queries_dim)) if decoder_ff else None
        # # 将最后结果进行重塑为指定想要的形状
        # self.to_logits = nn.Linear(queries_dim, logits_dim) if exists(logits_dim) else nn.Identity()

    def forward(
        self,
        data,                           # Image特征
        mask = None,
        queries_encoder = None,         # PointCloud特征
    ):
        b, *_, device = *data.shape, data.device
        # PointCloud特征
        x = queries_encoder

        # cpe
        if(self.pe):
            x,data = self.cpe(
                q=x,
                content=data,
            )

        # ---- Encoder过程 ----
        cross_attn, cross_ff = self.cross_attend_blocks
        # cross_attn = self.cross_attend_blocks
        # 经过Attention得到Query与原Query相加，维度不变
        x = cross_attn(x, context = data, mask = mask) + x
        # x = cross_attn(x, context = data, mask = mask)
        # 其目的是让特征较重要的部分，更加重要
        x = cross_ff(x) + x
        # ---- Encoder过程 ----

        #  ---- Process过程 ----
        for self_attn, self_ff in self.layers:
            x = self_attn(x) + x
            x = self_ff(x) + x
        # ---- Process过程 ----

        return x

        # # ---- Decoder过程 ----
        # if not exists(queries_decoder):
        #     return x
        # # cross attend from decoder queries to latents
        # latents = self.decoder_cross_attn(queries_decoder, context = x)
        # # optional decoder feedforward
        # if exists(self.decoder_ff):
        #     latents = latents + self.decoder_ff(latents)
        # # final linear out
        # return self.to_logits(latents)
        # # ---- Decoder过程 ----


zenb = 5
ae = 1
def fakt(x):
	global ae
	ae = ae + 1
	print( "ae: ", ae)
	y = 1
	y = y + 1
	print( "y: ", y)
	if x==1:
		return 1
	else:
		x=(x*fakt(x-1))
		return x

print(zenb, "zenbakiaren faktoriala ", fakt(zenb), "da")


# 147. Insertion Sort List
#
# Sort a linked list using insertion sort.

class ListNode(object):
    def __init__(self, x):
        self.val = x
        self.next = None

    def __iter__(self):
        item = self
        while item is not None:
            yield item.val
            item = item.next

class Solution(object):
    def sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head: return None
        curr = head
        dummy = ListNode(0)
        dummy.next = head
        while curr.next:
            if curr.next.val < curr.val:
                pre = dummy
                while pre.next.val < curr.next.val:
                    pre = pre.next
                tmp = curr.next
                curr.next = tmp.next
                tmp.next = pre.next
                pre.next = tmp
            else:
                curr = curr.next
        return dummy.next

if __name__ == "__main__":
    sol = Solution()
    node1 = ListNode(6)
    node2 = ListNode(5)
    node3 = ListNode(4)
    node4 = ListNode(3)
    node5 = ListNode(2)
    node6 = ListNode(1)
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    node5.next = node6
    res = sol.sortList(node1)
    assert list(res) == [1,2,3,4,5,6]


import difflib
import os
import argparse
import sys
import yaml
from time import gmtime, strftime
from pprint import pprint
from jinja2 import Environment, FileSystemLoader

def ignore_things(line):
    things_to_ignore = ['Troubleshooting','user admin group administrators password','user operator group operators password']
    if line.startswith ('!'):
        return False
    for thing in things_to_ignore:
        if thing in line:
            #print(line)
            return False
    return True

def compare (directory,pre_running_file,post_running_file,device,differences,no_differences,error_state,tstamp):
    """ see if there is a diff if so print a file with diff """
    print (pre_running_file)
    print (post_running_file)
    try:
        with open (pre_running_file) as f:
            pre_running_time = f.readline()
            #print(pre_running_time)
        with open (post_running_file) as f:
            post_running_time = f.readline()
            #print(post_running_time)
        with open (post_running_file) as f:
            post_running_config = f.readlines()[1:]
            #print(post_running_config)
        with open (pre_running_file) as f:
            pre_running_config = f.readlines()[1:]
            #print(pre_running_config)
            #running_config = f.readlines()

        f1 = filter(ignore_things, pre_running_config)
        f2 = filter(ignore_things, post_running_config)
        the_same = (all(x == y for x, y in zip(f1, f2)))

        if not the_same:
            differences=differences.append(device)
            difference2 = difflib.HtmlDiff(tabsize=2,wrapcolumn=80)
            file_name=directory+'/'+device+'_diff'+'.html'
            with open(file_name, "w") as fp:
                html = difference2.make_file(fromlines=pre_running_config, tolines=post_running_config,
                                            fromdesc="Pre Running Config - "+str(pre_running_time),
                                            todesc="Post Running Config - "+str(post_running_time),
                                            context="True", numlines=5)
                fp.write(html)
        elif the_same:
            no_differences=no_differences.append(device)
        else:
            print('error')
    except:
        print('error')
        error_state=error_state.append(device)
    return

def get_list_of_devices (ticket):
    config_dumps = 'change_data/'+ticket
    switch_list = [name for name in os.listdir(config_dumps) if (os.path.isdir
                  (os.path.join(config_dumps, name)) and 'bak' not in name)]
    return switch_list

def make_final_report (directory,differences,no_differences,error_state,tstamp,device_dictionary,var_diff):
    """Template out report"""
    file_loader = FileSystemLoader('templates')
    env = Environment(loader=file_loader)
    template = env.get_template('final_report_html.j2')
    final_report = template.render(differences=differences,no_differences=no_differences,error_state=error_state,
                                    device_dictionary=device_dictionary,var_diff=var_diff)
    with open(directory+'/'+'final_report'+'.html', 'w', encoding='utf8') as filehandler:
        filehandler.write(final_report)
    print ('Report is stored here: '+ directory)
    return

def compare_variables(vars_pre,vars_post):
    var_diff = {}
    values_changed = []
    new_key = []
    deleted_key = []
    for k in vars_pre:
        if k in vars_post:
            if vars_pre[k]==vars_post[k]:
                pass
            else:
                cgd = k+' - Pre: '+vars_pre[k]+' / Post: '+vars_post[k]
                values_changed.append(cgd)
        else:
            rm = k+': '+vars_pre[k]
            deleted_key.append(rm)
    for k in vars_post:
        if k not in vars_pre:
            add = k+': '+vars_post[k]
            new_key.append(add)
    var_diff['variables_changed'] = values_changed
    var_diff['new_variables'] = new_key
    var_diff['deleted_variables'] = deleted_key
    #var_diff = DeepDiff(vars_pre,vars_post)
    pprint(var_diff)
    return var_diff

def main():
    """ Main function """
    try:
        parser = argparse.ArgumentParser()
        parser.add_argument('-t', required=True, dest='ticket', help='REQUIRED - Ticket Number')
        args = parser.parse_args()
        ticket = args.ticket
    except:
        parser.print_help()
        sys.exit(0)

    # Create directory to store report and diffs
    tstamp=strftime("%Y-%m-%d_%H_%M_%S", gmtime())
    directory= 'change_data/'+ticket

    list_of_devices = get_list_of_devices(ticket)

    with open(directory+'/pre_switch_info.yml', 'r') as file:
        pre_info = yaml.load(file, Loader=yaml.SafeLoader)

    with open(directory+'/post_switch_info.yml', 'r') as file:
        post_info = yaml.load(file, Loader=yaml.SafeLoader)

    device_dictionary = {}
    for site in pre_info:
        for switch in pre_info[site]:
            device_dictionary[switch]={}
            device_dictionary[switch]['pre']={}
            device_dictionary[switch]['pre']=pre_info[site][switch]
    for site in post_info:
        for switch in post_info[site]:
            device_dictionary[switch]['post']={}
            device_dictionary[switch]['post']=post_info[site][switch]

    no_differences = []
    differences = []
    error_state = []
    var_diff={}

    for device in list_of_devices:
        pre_running_file = 'change_data/'+ticket+'/'+device+'/pre/running_config.txt'
        post_running_file = 'change_data/'+ticket+'/'+device+'/post/running_config.txt'
        preserial=device_dictionary[device]['pre']['serial']
        postserial=device_dictionary[device]['pre']['serial']
        pre_vars = device_dictionary[device]['pre']['variables'][preserial]
        post_vars = device_dictionary[device]['post']['variables'][postserial]
        #pprint(pre_vars)
        #pprint(post_vars)
        var_diff[device]=compare_variables(pre_vars,post_vars)
        compare (directory,pre_running_file,post_running_file,device,differences,no_differences,error_state,tstamp)

    print ("DEVICES WITH DIFFERENCES")
    print(differences)
    print('----')
    print ("DEVICES WITH NO DIFFERENCES")
    print(no_differences)
    print('----')
    print ("DEVICES WITH COMPARE ERROR")
    print(error_state)
    make_final_report(directory,differences,no_differences,error_state,tstamp,device_dictionary,var_diff)

if __name__ == "__main__":
    main()