import pygame
from pygame.locals import *
import numpy as np
import copy
import csv
import os
import re
from queue import PriorityQueue
from tkinter import Tk
from tkinter import filedialog as fd
import platform
import sys

class Simulation:
    def __init__(self, filename = '', load_map = False, load_qmap = False):
        self.screen = None
        self.dim = self.width, self.height = 800, 600
        self.fps = 30
        self.size = 16#20#16 #Size of the Grid-matrix
        self.grid_size = 450 #resolution grid
        self.origin = (300,100)
        self.grid = [[0 for i in range(self.size)] for j in range(self.size)] #empty grid
        self.backup_grid = [[0 for i in range(self.size)] for j in range(self.size)]
        self.q_map = [[{'up':0,'down':0,'right':0,'left':0} for i in range(self.size)] for j in range(self.size)]
        self.moves= ['right', 'down', 'up', 'left']
        self.iterations = 1500#1320 #Higher this to raise the exploration time of the ai (random mode is gonna last longer)
        self.episode = 0
        self.discount = 0.97 #
        self.learn_rate = 0.8 #
        self.target_reward = 100 #Reward for finding the goal
        self.gift_reward = 25 #Reward for the purple gifts
        self.epsilon = 50 #150 #Lower this to raise the exploration time of the ai (random mode is gonna last longer)
        self.action = ''
        self.reward = {}
        self.actions = 0
        self.action_limit = 700 #300 #Limit of moves per episode
        self.episode_limit = 90 #Limit of the episodes
        self.mode = ''
        self.num_walls = int((self.size*self.size)/3) #Number of obstacles
        self.num_gift = 3 #Number of gifts
        self.dist_reward = 0 #Do not change
        self.dist_rew = 0 #Reward for getting closer (no need to use)
        self.distance_old = 0
        self.neg_reward = -100 #Negative reward if q_map is initialized by self.init_q_map()
        self.stop = False
        self.p_queue = PriorityQueue() #PriorityQueue
        self.f_val = {(i,j):float('inf') for i in range(self.size) for j in range(self.size)} #h_val + g_val -> init. cells with high weight
        self.g_val = {(i,j):float('inf') for i in range(self.size) for j in range(self.size)} #actual distance start, cell
        self.D = 1 #Minimal cost for one step
        self.pl_goal_distance = 12 #Minimal distance between start and goal cell (Is used by self.random_grid)
        self.goal = (0,0) #position goal, gets assigned by self.random_grid
        self.start = (0,0) #position start, gets assigned by self.random_grid
        self.current = (0,0) #position current, gets assigned by self.random_grid
        self.options = [[{'up':0,'down':0,'right':0,'left':0} for i in range(self.size)] for j in range(self.size)]
        self.path = [] #a* - path
        self.show_path = False
        self.show_ai_path = False
        self.ai_path = []
        self.copy_path = False
        self.check_epsiode = 35 #Check episode
        self.load_qmap = load_qmap #Change to True if a qmap should be loaded
        self.saved_qmap_name = filename #Name of the saved q_map which should be loaded
        self.ld_map = load_map #Change to True if a map should be loaded
        self.saved_map_name = filename #Name of the map which should be loaded
        self.save_qmap = False
        self.map_name = ''
        #self.general_txt = ''
        self.root = Tk()
        self.steps_ai = self.action_limit

    def init_q_map(self):
        valide_cells = [0,2,3,4]
        for i in range(len(self.grid)):
            for j in  range(len(self.grid[i])):
                if self.grid[i][j] != 1:
                    if i != 0: #not at upper boundary
                        if i != len(self.grid)-1: #not at lower boundary
                            if j != 0: #not at left boundary
                                if j != len(self.grid[i])-1: #not at right,left,upper,lower boundary
                                    for key in self.moves:
                                        if self.q_map[i][j][key] != -self.target_reward:
                                            self.q_map[i][j][key] = 0

                                else: #not at left,upper,lower boundary
                                    if self.q_map[i][j][key] != self.neg_reward:
                                        self.q_map[i][j][key] = 0

                                    self.q_map[i][j]['right'] = self.neg_reward
                            else: #at left boundary
                                if j != len(self.grid[i])-1: #not at upper,lower boundary
                                    if self.q_map[i][j][key] != self.neg_reward:
                                        self.q_map[i][j][key] = 0

                                    self.q_map[i][j]['left'] = self.neg_reward
                                else: #not at upper,lower boundary
                                    self.q_map[i][j]['up'] = 0
                                    self.q_map[i][j]['down'] = 0
                                    self.q_map[i][j]['left'] = self.neg_reward
                                    self.q_map[i][j]['right'] = self.neg_reward
                        else: #at lower boundary
                            if j != 0: #not at left boundary
                                if j != len(self.grid[i])-1: #not at upper,right,left boundary
                                    for key in self.moves:
                                        if self.q_map[i][j][key] != self.neg_reward:
                                            self.q_map[i][j][key] = 0

                                        self.q_map[i][j]['down'] = self.neg_reward
                                else: #not at upper,left boundary
                                    for key in self.moves:
                                        if self.q_map[i][j][key] != self.neg_reward:
                                            self.q_map[i][j][key] = 0

                                    self.q_map[i][j]['right'] = self.neg_reward
                                    self.q_map[i][j]['down'] = self.neg_reward
                            else: #at left boundary
                                if j != len(self.grid[i])-1: #not at upper, right boundary
                                    self.q_map[i][j]['up'] = 0
                                    self.q_map[i][j]['right'] = 0
                                    self.q_map[i][j]['down'] = self.neg_reward
                                    self.q_map[i][j]['left'] = self.neg_reward
                                else: #not at upper boundary
                                    self.q_map[i][j]['up'] = 0
                                    self.q_map[i][j]['down'] = self.neg_reward
                                    self.q_map[i][j]['left'] = self.neg_reward
                                    self.q_map[i][j]['right'] = self.neg_reward
                    else: #at the upper boundary
                        if i != len(self.grid)-1: #not at the lower boundary
                            if j != 0: #not at the lower,left boundary
                                if j != len(self.grid[i])-1: #not at the lower,right,left boundary
                                    for key in self.moves:
                                        if self.q_map[i][j][key] != self.neg_reward:
                                            self.q_map[i][j][key] = 0

                                        self.q_map[i][j]['up'] = self.neg_reward
                                else: #not at the lower,left boundary
                                    self.q_map[i][j]['down'] = 0
                                    self.q_map[i][j]['left'] = 0
                                    self.q_map[i][j]['right'] = self.neg_reward
                                    self.q_map[i][j]['up'] = self.neg_reward
                            else: #at the left boundary
                                if j != len(self.grid[i])-1: #not at the lower,right boundary
                                    self.q_map[i][j]['down'] = 0
                                    self.q_map[i][j]['right'] = 0
                                    self.q_map[i][j]['left'] = self.neg_reward
                                    self.q_map[i][j]['up'] = self.neg_reward
                                else: #at the right boundary
                                    self.q_map[i][j]['down'] = 0
                                    self.q_map[i][j]['up'] = self.neg_reward
                                    self.q_map[i][j]['right'] = self.neg_reward
                                    self.q_map[i][j]['left'] = self.neg_reward
                        else: #at the lower boundary
                            if j != 0: #not at the left boundary
                                if j != len(self.grid[i])-1: #not at the left, right boundary
                                    self.q_map[i][j]['right'] = 0
                                    self.q_map[i][j]['left'] = 0
                                    self.q_map[i][j]['up'] = self.neg_reward
                                    self.q_map[i][j]['down'] = self.neg_reward
                                else: #at the right boundary
                                    self.q_map[i][j]['left'] = 0
                                    self.q_map[i][j]['right'] = self.neg_reward
                                    self.q_map[i][j]['up'] = self.neg_reward
                                    self.q_map[i][j]['down'] = self.neg_reward
                            else: #at the left boundary
                                if j != len(self.grid[i])-1: #not at the right bundary
                                    self.q_map[i][j]['right'] = 0
                                    self.q_map[i][j]['left'] = self.neg_reward
                                    self.q_map[i][j]['up'] = self.neg_reward
                                    self.q_map[i][j]['down'] = self.neg_reward
                else:
                    if i != 0: #mark upper cell
                        if self.grid[i-1][j] in valide_cells:
                            self.q_map[i-1][j]['down'] = self.neg_reward
                    if i != len(self.grid)-1: #mark lower cell
                        if self.grid[i+1][j] in valide_cells:
                            self.q_map[i+1][j]['up'] = self.neg_reward
                    if j != 0: #mark left cell
                        if self.grid[i][j-1] in valide_cells:
                            self.q_map[i][j-1]['right'] = self.neg_reward
                    if j != len(self.grid[i])-1: #mark right cell
                        if self.grid[i][j+1] in valide_cells:
                            self.q_map[i][j+1]['left'] = self.neg_reward

    def random_grid(self):
        for _ in range(self.num_walls):
            self.grid[np.random.randint(0,self.size)][np.random.randint(0,self.size)] = 1

        for _ in range(self.num_gift):
            self.grid[np.random.randint(0,self.size)][np.random.randint(0,self.size)] = 4

        idx_player = (np.random.randint(0,self.size), np.random.randint(0,self.size))
        idx_goal = (np.random.randint(0,self.size), np.random.randint(0,self.size))

        while np.sqrt((idx_player[0] - idx_goal[0])**2 + (idx_player[1] - idx_goal[1])**2) < self.pl_goal_distance:
            idx_player = (np.random.randint(0,self.size), np.random.randint(0,self.size))
            idx_goal = (np.random.randint(0,self.size), np.random.randint(0,self.size))

        self.grid[idx_player[0]][idx_player[1]] = 2
        self.grid[idx_goal[0]][idx_goal[1]] = 3

        self.start = (idx_player[0], idx_player[1])
        self.goal = (idx_goal[0], idx_goal[1])

    def save_map(self, map_type):
        if platform.system() == 'Windows':
            file_path = os.path.realpath(__file__).split('\\') # for windows
        else:
            file_path = os.path.realpath(__file__).split('/') #for mac
        file_path = '/'.join([file_path[i] for i in range(len(file_path)-1)])
        file_list = [f for f in os.listdir(file_path) if os.path.isfile(os.path.join(file_path, f))]
        maps = []

        if map_type == "grid":
            for file in file_list:
                if re.search(fr'(map)(.*)',file):
                    maps.append(re.search(fr'(map)(.*)',file).group())

            if maps:
                maps = [a.split('.') for a in maps]
                maps = int(max([a[0][-1] for a in maps if a[0][-1].isnumeric()])) + 1
            else:
                maps = 1

            self.map_name = f'map{maps}'.split('.')[0]

            with open(os.path.join(file_path, f'map{maps}.csv'), 'w', newline='') as csvfile:
                writer = csv.writer(csvfile, delimiter=' ',quotechar='|', quoting=csv.QUOTE_MINIMAL)
                for row in self.backup_grid:
                    writer.writerow(row)

        else:
            for file in file_list:
                if re.search(fr'(qmap)(.*)',file):
                    maps.append(re.search(fr'(qmap)(.*)',file).group())

            if maps:
                maps = [a.split('.') for a in maps]
                maps = int(max([a[0][-1] for a in maps if a[0][-1].isnumeric()])) + 1
            else:
                maps = 1

            with open(os.path.join(file_path, f'qmap{maps}-{self.map_name}.csv'), 'w', newline='') as csvfile:
                writer = csv.writer(csvfile, delimiter=' ',quotechar='|', quoting=csv.QUOTE_MINIMAL)
                for row in self.q_map:
                    writer.writerow(row)

    def load_map(self, name, map_type):
        file_path = os.path.realpath(__file__).split('/')
        file_path = '/'.join([file_path[i] for i in range(len(file_path)-1)])
        loaded_map = []
        loaded_qmap = []
        i = 0

        if map_type == 'grid':
            map_name = name + '.csv'
            with open(os.path.join(file_path, f'{map_name}'), newline='') as csvfile:
                reader = csv.reader(csvfile, delimiter=' ', quotechar='|')
                for row in reader:
                    loaded_map.append(list(map(int, row)))
                    if 2 in list(map(int, row)):
                        self.start = (i, list(map(int, row)).index(2))
                    if 3 in list(map(int, row)):
                        self.goal = (i, list(map(int, row)).index(3))

                    i += 1

            self.size = len(loaded_map)
            return loaded_map

        else:
            map_name = name.split('-')[1] + '.csv'
            qmap_name = name + '.csv'

            with open(os.path.join(file_path, f'{qmap_name}'), newline='') as csvfile:
                reader = csv.reader(csvfile, delimiter=' ', quotechar='|')
                for row in reader:
                    loaded_qmap.append([eval(k) for k in row])

            with open(os.path.join(file_path, f'{map_name}'), newline='') as csvfile:
                reader = csv.reader(csvfile, delimiter=' ', quotechar='|')
                for row in reader:
                    loaded_map.append(list(map(int, row)))
                    if 2 in list(map(int, row)):
                        self.start = (i, list(map(int, row)).index(2))
                    if 3 in list(map(int, row)):
                        self.goal = (i, list(map(int, row)).index(3))

                    i += 1

            self.size = len(loaded_map)

            return loaded_map, loaded_qmap

    def init(self):
        pygame.init()
        pygame.display.set_caption("Shortest-Path Reinforcement learning")

        self.screen = pygame.display.set_mode(self.dim)
        self.isRunning = True
        self.screen.fill((255,255,255))

        self.clock = pygame.time.Clock()
        if self.ld_map:
            self.map_name = self.saved_map_name
            self.grid = copy.deepcopy(self.load_map(self.map_name, 'grid')) #load map
        else:
            self.random_grid()

        if self.load_qmap:
            self.grid, self.q_map = copy.deepcopy(self.load_map(self.saved_qmap_name, 'qmap')) #load qmap
            self.iterations = 0

        '''
        self.grid = [
        [0, 0, 0, 0, 1, 0, 0, 0, 0],
        [0, 2, 0, 0, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0, 0],
        [0, 0, 0, 0, 1, 0, 0, 0, 3],
        [0, 0, 0, 0, 1, 0, 0, 0, 0]]
        #1 = Obstacle
        #2 = Player
        #3 = Goal
        #4 = Bomb
        #5 = Treasure

        self.start = (1,1)
        self.goal = (7,8)
        self.size = 9
        '''

        self.backup_grid = copy.deepcopy(self.grid)

        #self.init_q_map()
        self.grid_options()

        self.a_star()

    def update_Q_values(self, indicies_new, cell_type, move, indicies_old):
        #Q1 = self.target_reward
        #Q2 = (1-self.learn_rate)*self.q_map[indicies_old[0]][indicies_old[1]][move] + self.learn_rate*(self.gift_reward+(self.discount**self.actions)*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)])
        #Q3 = (1-self.learn_rate)*self.q_map[indicies_old[0]][indicies_old[1]][move] + self.learn_rate*(0+(self.discount**self.actions)*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)])

        #Q-Learning
        Q1 = (1-self.learn_rate)*self.q_map[indicies_old[0]][indicies_old[1]][move] + self.learn_rate*(self.target_reward+self.discount*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)])
        Q2 = (1-self.learn_rate)*self.q_map[indicies_old[0]][indicies_old[1]][move] + self.learn_rate*(self.gift_reward+self.discount*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)])
        Q3 = (1-self.learn_rate)*self.q_map[indicies_old[0]][indicies_old[1]][move] + self.learn_rate*(0+self.discount*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)])

        #print(self.q_map[indicies_old[0]][indicies_old[1]][move])
        #MDP
        #Q1 = self.target_reward + (self.discount)*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)]
        #Q2 = Q1 = self.gift_reward + (self.discount)*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)]
        #Q3 = (self.discount)*self.q_map[indicies_new[0]][indicies_new[1]][max(self.q_map[indicies_new[0]][indicies_new[1]], key=self.q_map[indicies_new[0]][indicies_new[1]].get)]

        if cell_type == 3:
            return Q1 + self.learn_rate*self.dist_reward
        elif cell_type == 4:
            return Q2 + self.learn_rate*self.dist_reward
        else:
            return Q3 + self.learn_rate*self.dist_reward

    def learn(self):
        epsilon = self.iterations/(self.episode*self.epsilon+1)
        p = np.random.uniform(0.3, 1)#np.random.uniform(0, 1)
        action = ''
        moves = {'up': (self.current[0] - 1, self.current[1]), 'down': (self.current[0] + 1, self.current[1]), 'right': (self.current[0], self.current[1] + 1), 'left': (self.current[0], self.current[1] - 1)}
        options = []

        if self.q_map[self.start[0]][self.start[1]][max(self.q_map[0][self.start[1]], key=self.q_map[self.start[0]][self.start[1]].get)] > 20:
            self.iterations = 0

        if p < epsilon:
            self.mode = 'exploration'
            #action = np.random.choice(self.moves)

            options = [k for k in self.moves if moves[k] in self.path]

            if np.random.uniform(0, 0.9) < 0.4 and options:#if np.random.uniform(0, 0.9) < 0.4 and options:
                self.action = np.random.choice(options)
            else:
                self.action = np.random.choice(self.moves)

        else:
            self.mode = 'policy'
            for i in range(len(self.grid)):
                if 2 in self.grid[i]:
                    idx = self.grid[i].index(2)
                    self.action = max(self.q_map[i][idx], key=self.q_map[i][idx].get)

    def placeObjects(self):
        cellBorder = 6
        celldimX = celldimY = (self.grid_size/self.size) - (cellBorder*2)
        for row in range(len(self.grid)):
            for column in range(len(self.grid)):
                obj = self.grid[column][row]
                if(obj == 1):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (0,0,0))
                elif(obj == 2):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (0,0,255))
                elif(obj == 3):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (0,255,0))
                elif(obj == 4):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (255,0,255))
                elif(obj == 5):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (255,255,0))
                elif(obj == 6):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (0,255,255))
                elif(obj == 7):
                    self.drawObstacles(self.origin[0] + (celldimY*row) + cellBorder + (2*row*cellBorder) + 1,
                        self.origin[1] + (celldimX*column) + cellBorder + (2*column*cellBorder) + 1, celldimX, celldimY, (50,100,50))

    def drawObstacles(self, x, y, size_x, size_y, color):
        pygame.draw.rect(self.screen, color, (x, y, size_x, size_y))

    def drawGrid(self, dim):
        #Border of the grid
        pygame.draw.rect(self.screen, (0,0,0), pygame.Rect(self.origin[0], self.origin[1], self.grid_size, self.grid_size,),  2)

        #Cell size
        cell_size = self.grid_size/self.size

        for i in range(dim):
            pygame.draw.line(self.screen, (0,0,0), (self.origin[0] + (cell_size * i), self.origin[1]), (self.origin[0] + (cell_size * i), self.grid_size + self.origin[1]), 2)
        #Horiz
            pygame.draw.line(self.screen, (0,0,0), (self.origin[0], self.origin[1] + (cell_size*i)), (self.origin[0] + self.grid_size, self.origin[1] + (cell_size*i)), 2)

    def heuristic(self, pnt1, pnt2):
        #Manhattan distance is used!
        dx = abs(pnt1[0] - pnt2[0])
        dy = abs(pnt1[1] - pnt2[1])

        return (self.D * (dx + dy))

    def grid_options(self):
        valide_cells = [0,2,3,4]
        for i in range(len(self.grid)):
            for j in  range(len(self.grid[i])):
                if self.grid[i][j] != 1:
                    if i != 0: #not at upper boundary
                        if i != len(self.grid)-1: #not at lower boundary
                            if j != 0: #not at left boundary
                                if j != len(self.grid[i])-1: #not at right,left,upper,lower boundary
                                    for key in self.moves:
                                        if self.options[i][j][key] != -1:
                                            self.options[i][j][key] = 0

                                else: #not at left,upper,lower boundary
                                    if self.options[i][j][key] != -1:
                                        self.options[i][j][key] = 0

                                    self.options[i][j]['right'] = -1
                            else: #at left boundary
                                if j != len(self.grid[i])-1: #not at upper,lower boundary
                                    if self.options[i][j][key] != -1:
                                        self.options[i][j][key] = 0

                                    self.options[i][j]['left'] = -1
                                else: #not at upper,lower boundary
                                    self.options[i][j]['up'] = 0
                                    self.options[i][j]['down'] = 0
                                    self.options[i][j]['left'] = -1
                                    self.options[i][j]['right'] = -1
                        else: #at lower boundary
                            if j != 0: #not at left boundary
                                if j != len(self.grid[i])-1: #not at upper,right,left boundary
                                    for key in self.moves:
                                        if self.options[i][j][key] != -1:
                                            self.options[i][j][key] = 0

                                        self.options[i][j]['down'] = -1
                                else: #not at upper,left boundary
                                    for key in self.moves:
                                        if self.options[i][j][key] != -1:
                                            self.options[i][j][key] = 0

                                    self.options[i][j]['right'] = -1
                                    self.options[i][j]['down'] = -1
                            else: #at left boundary
                                if j != len(self.grid[i])-1: #not at upper, right boundary
                                    self.options[i][j]['up'] = 0
                                    self.options[i][j]['right'] = 0
                                    self.options[i][j]['down'] = -1
                                    self.options[i][j]['left'] = -1
                                else: #not at upper boundary
                                    self.options[i][j]['up'] = 0
                                    self.options[i][j]['down'] = -1
                                    self.options[i][j]['left'] = -1
                                    self.options[i][j]['right'] = -1
                    else: #at the upper boundary
                        if i != len(self.grid)-1: #not at the lower boundary
                            if j != 0: #not at the lower,left boundary
                                if j != len(self.grid[i])-1: #not at the lower,right,left boundary
                                    for key in self.moves:
                                        if self.options[i][j][key] != -1:
                                            self.options[i][j][key] = 0

                                        self.options[i][j]['up'] = -1
                                else: #not at the lower,left boundary
                                    self.options[i][j]['down'] = 0
                                    self.options[i][j]['left'] = 0
                                    self.options[i][j]['right'] = -1
                                    self.options[i][j]['up'] = -1
                            else: #at the left boundary
                                if j != len(self.grid[i])-1: #not at the lower,right boundary
                                    self.options[i][j]['down'] = 0
                                    self.options[i][j]['right'] = 0
                                    self.options[i][j]['left'] = -1
                                    self.options[i][j]['up'] = -1
                                else: #at the right boundary
                                    self.options[i][j]['down'] = 0
                                    self.options[i][j]['up'] = -1
                                    self.options[i][j]['right'] = -1
                                    self.options[i][j]['left'] = -1
                        else: #at the lower boundary
                            if j != 0: #not at the left boundary
                                if j != len(self.grid[i])-1: #not at the left, right boundary
                                    self.options[i][j]['right'] = 0
                                    self.options[i][j]['left'] = 0
                                    self.options[i][j]['up'] = -1
                                    self.options[i][j]['down'] = -1
                                else: #at the right boundary
                                    self.options[i][j]['left'] = 0
                                    self.options[i][j]['right'] = -1
                                    self.options[i][j]['up'] = -1
                                    self.options[i][j]['down'] = -1
                            else: #at the left boundary
                                if j != len(self.grid[i])-1: #not at the right bundary
                                    self.options[i][j]['right'] = 0
                                    self.options[i][j]['left'] = -1
                                    self.options[i][j]['up'] = -1
                                    self.options[i][j]['down'] = -1
                else:
                    if i != 0: #mark upper cell
                        if self.grid[i-1][j] in valide_cells:
                            self.options[i-1][j]['down'] = -1
                    if i != len(self.grid)-1: #mark lower cell
                        if self.grid[i+1][j] in valide_cells:
                            self.options[i+1][j]['up'] = -1
                    if j != 0: #mark left cell
                        if self.grid[i][j-1] in valide_cells:
                            self.options[i][j-1]['right'] = -1
                    if j != len(self.grid[i])-1: #mark right cell
                        if self.grid[i][j+1] in valide_cells:
                            self.options[i][j+1]['left'] = -1

    def a_star(self):
        #neighbour {(idx1, idx2) : type}

        current = (0,0)
        new = (0,0)

        self.f_val[self.start] = self.heuristic(self.start, self.goal)
        self.g_val[self.start] = 0

        g_temp = 0
        f_temp = 0

        temp = {}
        path = {}

        self.p_queue.put((self.f_val[self.start], self.heuristic(self.start, self.goal), self.start))

        while not self.p_queue.empty():
            current = self.p_queue.get()[2]

            if current == self.goal:
                break

            directions = [k for k,v in self.options[current[0]][current[1]].items() if v == 0]

            for direction in directions:
                if current[0] != 0 and current[1] != 0:
                    moves = {'up': (current[0] - 1, current[1]), 'down': (current[0] + 1, current[1]), 'right': (current[0], current[1] + 1), 'left': (current[0], current[1] - 1)}
                elif current[0] == 0:
                    moves = {'up': (0, current[1]), 'down': (current[0] + 1, current[1]), 'right': (current[0], current[1] + 1), 'left': (current[0], current[1] - 1)}
                elif current[1] == 0:
                    moves = {'up': (0, current[1]), 'down': (current[0] + 1, current[1]), 'right': (current[0], current[1] + 1), 'left': (current[0], 0)}

                new = moves[direction]
                g_temp = self.g_val[current] + 1
                f_temp = self.heuristic(new, self.goal) + g_temp

                if new in list(self.f_val.keys()):
                    if f_temp < self.f_val[new]:
                        self.g_val[new] = g_temp
                        self.f_val[new] = f_temp
                        self.p_queue.put((self.f_val[new], self.heuristic(new, self.goal), new))
                        temp[new] = current

        cell = self.goal

        while cell != self.start:
            if cell not in temp.keys():
                print('a* failed!')
                os.execv(sys.executable, ['python'] + sys.argv) #restart program
                break
            path[temp[cell]] = cell
            cell = temp[cell]

        self.path = [path[k] for k in dict(reversed(list(path.items()))).keys()]
        self.path.insert(0, self.start)

    def draw_path(self, path, color):
        cell_size = self.grid_size/self.size

        #pygame.draw.circle(self.screen, (255, 153, 0), ((self.origin[0]+(cell_size*path[0][1] + 0.5*cell_size), self.origin[1] + (cell_size*path[0][0] + 0.5*cell_size))), 5, width=2)

        #start_cell:
        #Horz
        pygame.draw.line(self.screen, (255, 153, 0), (self.origin[0]+(cell_size*path[0][1]), self.origin[1] + (cell_size*path[0][0])), (self.origin[0] + (cell_size*path[0][1]+cell_size), self.origin[1] + (cell_size*path[0][0])), 2)
        pygame.draw.line(self.screen, (255, 153, 0), (self.origin[0]+(cell_size*path[0][1]), self.origin[1] + (cell_size*path[0][0]+cell_size)), (self.origin[0] + (cell_size*path[0][1]+cell_size), self.origin[1] + (cell_size*path[0][0]+cell_size)), 2)

        #Vert
        pygame.draw.line(self.screen, (255, 153, 0), (self.origin[0]+(cell_size*path[0][1]), self.origin[1] + (cell_size*path[0][0])), (self.origin[0] + (cell_size*path[0][1]), self.origin[1] + (cell_size*path[0][0]+cell_size)), 2)
        pygame.draw.line(self.screen, (255, 153, 0), (self.origin[0]+(cell_size*path[0][1]+cell_size), self.origin[1] + (cell_size*path[0][0])), (self.origin[0] + (cell_size*path[0][1]+cell_size), self.origin[1] + (cell_size*path[0][0]+cell_size)), 2)

        #goal_cell:
        #Horz
        pygame.draw.line(self.screen, (102, 0, 204), (self.origin[0]+(cell_size*path[-1][1]), self.origin[1] + (cell_size*path[-1][0])), (self.origin[0] + (cell_size*path[-1][1]+cell_size), self.origin[1] + (cell_size*path[-1][0])), 2)
        pygame.draw.line(self.screen, (102, 0, 204), (self.origin[0]+(cell_size*path[-1][1]), self.origin[1] + (cell_size*path[-1][0]+cell_size)), (self.origin[0] + (cell_size*path[-1][1]+cell_size), self.origin[1] + (cell_size*path[-1][0]+cell_size)), 2)

        #Vert
        pygame.draw.line(self.screen, (102, 0, 204), (self.origin[0]+(cell_size*path[-1][1]), self.origin[1] + (cell_size*path[-1][0])), (self.origin[0] + (cell_size*path[-1][1]), self.origin[1] + (cell_size*path[-1][0]+cell_size)), 2)
        pygame.draw.line(self.screen, (102, 0, 204), (self.origin[0]+(cell_size*path[-1][1]+cell_size), self.origin[1] + (cell_size*path[-1][0])), (self.origin[0] + (cell_size*path[-1][1]+cell_size), self.origin[1] + (cell_size*path[-1][0]+cell_size)), 2)

        for i in range(len(path)-1):
            """
            if self.grid[cell[0]][cell[1]] != 3:
                self.grid[cell[0]][cell[1]] = 7
            """

            if path[i][1] != path[i+1][1]: #step horizonally
                pygame.draw.line(self.screen, color, (self.origin[0]+(cell_size*path[i][1] + 0.5*cell_size), self.origin[1] + (cell_size*path[i][0] + 0.5*cell_size)), (self.origin[0] + (cell_size*path[i+1][1] + 0.5*cell_size), self.origin[1] + (cell_size*path[i+1][0] + 0.5*cell_size)), 2)

            else: #step vertically
                pygame.draw.line(self.screen, color, (self.origin[0]+(cell_size*path[i][1] + 0.5*cell_size), self.origin[1] + (cell_size*path[i][0] + 0.5*cell_size)), (self.origin[0] + (cell_size*path[i+1][1] + 0.5*cell_size), self.origin[1] + (cell_size*path[i+1][0] + 0.5*cell_size)), 2)

    def event(self, event):
        if event.type == pygame.QUIT:
            self.isRunning = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            pos_mouse = pygame.mouse.get_pos()
            if pos_mouse[0] > 10 and pos_mouse[0] < 10+85 and pos_mouse[1] > 475 and pos_mouse[1] < 475+25:
                grid_map = fd.askopenfilename(title = "Select the map you want to load",filetypes = (("Map files", ".csv"),))
                if grid_map:
                    self.__init__(filename = grid_map.split('/')[-1].split('.')[0], load_map = True)
                    self.init()
            if pos_mouse[0] > 150 and pos_mouse[0] < 150+102 and pos_mouse[1] > 475 and pos_mouse[1] < 475+25:
                qmap = fd.askopenfilename(title = "Select the qmap you want to load",filetypes = (("Q-Map files", ".csv"),))
                if qmap:
                    self.__init__(filename = qmap.split('/')[-1].split('.')[0], load_qmap = True)
                    self.init()

        elif event.type == pygame.KEYDOWN:
            if event.key == K_LEFT:
                self.check_status('left')

            if event.key == K_RIGHT:
                self.check_status('right')

            if event.key == K_DOWN:
                self.check_status('down')

            if event.key == K_UP:
                self.check_status('up')

            if event.key == K_s:
                self.save_map('grid')
                #self.general_txt = self.draw_general_txt(f'Saving map: {self.map_name}...')

            if event.key == K_b:
                self.stop = not self.stop
                self.action = ''

            if event.key == K_o:
                self.show_path = not self.show_path

            if event.key == K_a:
                self.show_ai_path = not self.show_ai_path

            if event.key == K_l:
                self.save_qmap = not self.save_qmap

    def reset(self):
        self.episode += 1
        self.actions = 0
        self.points = 0

        self.grid = copy.deepcopy(self.backup_grid)

    def check_distance(self):
        epsilon = (self.iterations+500)/(self.episode*self.epsilon+1)
        p = np.random.uniform(0.3, 1)
        idx_player = copy.deepcopy(self.start)
        idx_goal = copy.deepcopy(self.goal)

        for i in range(len(self.grid)):
            if 2 in self.grid[i]:
                idx_player = (self.grid[i].index(2), i)
            if 3 in self.grid[i]:
                idx_goal = (self.grid[i].index(3), i)

            #distance = np.sqrt((idx_player[0] - idx_goal[0])**2 + (idx_player[1] - idx_goal[1])**2)
            distance = float(self.heuristic(idx_player, idx_goal)) # Manhattan distance

            if distance == 0:
                distance = 0.00001

            if (distance - self.distance_old) > 0: #distance got bigger
                self.distance_old = distance
                if p < epsilon:
                    self.dist_reward = -1*self.dist_rew*1*distance/10
            elif (distance - self.distance_old) == 0:
                self.distance_old = distance
                if p < epsilon:
                    self.dist_reward = self.dist_rew
            elif (distance - self.distance_old) < 0: #distance got smaller
                self.distance_old = distance
                if p < epsilon:
                    self.dist_reward = self.dist_rew/distance

    def check_status(self, command):
        visited = 5
        if self.actions > self.action_limit:
            self.reset()

        for i in range(len(self.grid)):
            if 2 in self.grid[i]:
                idx = self.grid[i].index(2)
                self.current = (idx, i)
                self.current = (i, idx)
                self.reward = self.q_map[i][idx]
                if command == 'right':
                    #check if player is at the lower border or if there is a wall above
                    if idx != (len(self.grid[i])-1) and self.grid[i][idx+1] != 1:
                        #check if player is on the win-flag
                        if self.grid[i][idx+1] == 3:
                            self.ai_path.append(self.goal)
                            self.ai_path.insert(0, self.start)
                            if len(self.ai_path) < self.steps_ai: self.steps_ai = len(self.ai_path)

                            self.actions += 1
                            self.q_map[i][idx]['right'] = self.update_Q_values((i, idx+1), 3, 'right', (i, idx))
                            self.grid[i][idx] = 3
                            self.reset()
                            break

                        self.ai_path.append((i,idx+1))

                        self.actions += 1
                        self.q_map[i][idx]['right'] = self.update_Q_values((i, idx+1), 0, 'right', (i, idx))
                        self.grid[i][idx+1] = 2
                        self.grid[i][idx] = visited

                #check if player is at the left border or if there is a wall on the left side
                elif command == 'left':
                    if idx != 0 and self.grid[i][idx-1] != 1:
                        #check if player is on the win-flag
                        if self.grid[i][idx-1] == 3:
                            self.ai_path.append(self.goal)
                            self.ai_path.insert(0, self.start)
                            if len(self.ai_path) < self.steps_ai: self.steps_ai = len(self.ai_path)

                            self.actions += 1
                            self.q_map[i][idx]['left'] = self.update_Q_values((i, idx-1), 3, 'left', (i, idx))
                            self.grid[i][idx] = 3
                            self.reset()
                            break

                        self.ai_path.append((i,idx-1))

                        self.actions += 1
                        self.q_map[i][idx]['left'] = self.update_Q_values((i, idx-1), 0, 'left', (i, idx))
                        self.grid[i][idx-1] = 2
                        self.grid[i][idx] = visited

                #check if player is at the lower border or if there is a wall above
                elif command == 'up':
                    if i != 0:
                        if self.grid[i-1][idx] != 1:
                            #check if player is on the win-flag
                            if self.grid[i-1][idx] == 3:
                                self.ai_path.append(self.goal)
                                self.ai_path.insert(0, self.start)
                                if len(self.ai_path) < self.steps_ai: self.steps_ai = len(self.ai_path)

                                self.actions += 1
                                self.q_map[i][idx]['up'] = self.update_Q_values((i-1, idx), 3, 'up', (i, idx))
                                self.grid[i][idx] = 3
                                self.reset()
                                break

                            self.ai_path.append((i-1,idx))

                            self.actions += 1
                            self.q_map[i][idx]['up'] = self.update_Q_values((i-1, idx), 0, 'up', (i, idx))
                            self.grid[i-1][idx] = 2
                            self.grid[i][idx] = visited

        #check if player is at the lower border or if there is a wall underneath
        if command == 'down':
            for i in range(len(self.grid)-1, -1, -1):
                if 2 in self.grid[i]:
                    idx = self.grid[i].index(2)
                    self.current = (i, idx)
                    if i != len(self.grid)-1:
                        if self.grid[i+1][idx] != 1:
                            #check if player is on the win-flag
                            if self.grid[i+1][idx] == 3:
                                self.ai_path.append(self.goal)
                                self.ai_path.insert(0, self.start)
                                if len(self.ai_path) < self.steps_ai: self.steps_ai = len(self.ai_path)

                                self.actions += 1
                                self.q_map[i][idx]['down'] = self.update_Q_values((i+1, idx), 3, 'down', (i, idx))
                                self.grid[i][idx] = 3
                                self.reset()
                                break

                            self.ai_path.append((i+1,idx))

                            self.actions += 1
                            self.q_map[i][idx]['down'] = self.update_Q_values((i+1, idx), 0, 'down', (i, idx))
                            self.grid[i+1][idx] = 2
                            self.grid[i][idx] = visited

    def draw_txt(self, txt, pos):
        self.screen.blit(txt, pos)

    def draw_general_txt(self, txt, time):
        return pygame.font.Font('freesansbold.ttf', 20).render(f'{txt}', True, (0, 0, 0))

    def draw(self):
        self.screen.fill((255,255,255))
        text = pygame.font.Font('freesansbold.ttf', 20).render(f'Episodes:  {str(self.episode)}', True, (0, 0, 0))
        text_1 = pygame.font.Font('freesansbold.ttf', 20).render(f'Actions:  {str(self.actions)}', True, (0, 0, 0))
        text_2 = pygame.font.Font('freesansbold.ttf', 20).render(f'Action:  {str(self.action)}', True, (0, 0, 0))
        text_3 = pygame.font.Font('freesansbold.ttf', 20).render(f'Reward:  {str({key : round(self.reward[key], 0) for key in self.reward})}', True, (0, 0, 0))
        text_4 = pygame.font.Font('freesansbold.ttf', 20).render(f'Mode:  {str(self.mode)}', True, (0, 0, 0))
        text_5 = pygame.font.Font('freesansbold.ttf', 20).render(f'Distance:  {str(round(self.distance_old, 0))}', True, (0, 0, 0))
        text_6 = pygame.font.Font('freesansbold.ttf', 20).render(f'Save-Qmap:  {str(self.save_qmap)}', True, (0, 0, 0))
        text_7 = pygame.font.Font('freesansbold.ttf', 20).render(f'Map_name:  {str(self.map_name)}', True, (0, 0, 0))
        text_8 = pygame.font.Font('freesansbold.ttf', 20).render(f'Steps a*:  {str(len(self.path))}', True, (0, 0, 0))
        text_9 = pygame.font.Font('freesansbold.ttf', 20).render(f'Steps AI:  {str(self.steps_ai)}', True, (0, 0, 0))
        text_10 = pygame.font.Font('freesansbold.ttf', 20).render(f'Commands:', True, (100, 100, 0))
        text_11 = pygame.font.Font('freesansbold.ttf', 20).render(f'S - Save map', True, (75, 75, 75))
        text_12 = pygame.font.Font('freesansbold.ttf', 20).render(f'L - Save qmap', True, (75, 75, 75))
        text_13 = pygame.font.Font('freesansbold.ttf', 20).render(f'O - toggle a* visualization', True, (75, 75, 75))
        text_14 = pygame.font.Font('freesansbold.ttf', 20).render(f'B - toggle learning', True, (75, 75, 75))
        #text_10 = self.general_txt

        self.draw_txt(text, (10, 25))
        self.draw_txt(text_1, (10, 50))
        self.draw_txt(text_2, (10, 75))
        self.draw_txt(text_3, (200, 25))
        self.draw_txt(text_4, (10, 125))
        self.draw_txt(text_5, (10, 100))
        self.draw_txt(text_6, (10, 150))
        self.draw_txt(text_8, (10, 200))
        self.draw_txt(text_9, (10, 225))
        self.draw_txt(text_10, (10, 300))
        self.draw_txt(text_11, (10, 325))
        self.draw_txt(text_12, (10, 350))
        self.draw_txt(text_13, (10, 375))
        self.draw_txt(text_14, (10, 400))

        pygame.draw.rect(self.screen, (0,0,0), (10, 475, 85, 25),2)
        pygame.draw.rect(self.screen, (100,0,0), (12, 477, 82, 22))
        btn_load_txt = pygame.font.Font('freesansbold.ttf', 16).render(f'Load map', True, (0, 0, 0))
        self.draw_txt(btn_load_txt, (15, 480))

        pygame.draw.rect(self.screen, (0,0,0), (150, 475, 102, 25),2)
        pygame.draw.rect(self.screen, (100,0,0), (152, 477, 99, 22))
        btn_load_txt = pygame.font.Font('freesansbold.ttf', 16).render(f'Load Q-Map', True, (0, 0, 0))
        self.draw_txt(btn_load_txt, (155, 480))

        if self.map_name:
            self.draw_txt(text_7, (10, 175))

        self.drawGrid(self.size)
        self.placeObjects()

        if self.show_path:
            self.draw_path(self.path, (50,100,50))

        if self.episode > self.check_epsiode or self.show_ai_path:
            self.draw_path(self.ai_path, (100,0,0))

        pygame.display.update()

    def execute(self):
        if self.init() == False:
            self.isRunning = False

        while self.isRunning and self.episode < self.episode_limit:
            for event in pygame.event.get():
                self.event(event)

            if not self.stop:
                self.learn()

            if self.episode == self.check_epsiode:
                self.copy_path = True
            else:
                self.copy_path = False

            self.check_status(self.action)
            self.check_distance()
            self.root.withdraw()
            self.draw()
            self.clock.tick(self.fps)

        if len(self.path) == len(self.ai_path):
            print('Optimal Path found!')

        if self.save_qmap:
            self.save_map("qmap")
        pygame.quit()

if __name__ == "__main__":
    np.seterr(over='raise')
    p = Simulation()
    p.execute()


import pandas as pd
import numpy as np

from konlpy.tag import Okt
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from sklearn.preprocessing import LabelEncoder
from tensorflow.keras.utils import to_categorical
import pickle
from tensorflow.keras.models import load_model

pd.set_option('display.unicode.east_asian_width', True)
# data load
df = pd.read_csv('./crawling/movie_new.csv')
X = df['summary']
Y = df['genre']

# target labeling
with open('./models/movie_encoder_2000.pickle', 'rb') as f:
    encoder = pickle.load(f)
labeled_Y = encoder.transform(Y)
label = encoder.classes_
onehot_Y = to_categorical(labeled_Y)
print(labeled_Y[:5])
print(label)
print(onehot_Y)

# 형태소 분리, 한 글자/불용어 제거
okt = Okt()
stopwords = pd.read_csv('../../PRJ_Movie_for_you-1/crawling_data/stopwords.csv', index_col=0)
for i in range(len(X)):
    X[i] = okt.morphs(X[i], stem=True)
    words = []
    for word in X[i]:
        if len(word) > 1:
            if word not in list(stopwords['stopword']):
                words.append(word)
    X[i] = ' '.join(words)
print(X[:5])

# titles tokenizing
with open('./models/movie_token_500.pickle', 'rb') as f:
    token = pickle.load(f)
tokened_X = token.texts_to_sequences(X)
print(tokened_X[:5])

for i in range(len(tokened_X)):
    if 500 < len(tokened_X[i]):
        tokened_X[i] = tokened_X[i][:500]

# padding
X_pad = pad_sequences(tokened_X, 500)
print(X_pad[:5])

model = load_model('./models/movie_genre_classification_model.h5')
pred = model.predict(X_pad)
sample = 6
print('pred is ', pred[sample])
print('actual is ', onehot_Y[sample])
print('Target :', label[np.argmax(onehot_Y[sample])])
pred = pred[sample].tolist()
acc = 0
ans = []
while acc < 0.99:
    ans.append(label[pred.index(max(pred))])
    acc = acc + max(pred)
    pred[pred.index(max(pred))] = 0
print('Prediction after learning is ', ans)


import sys
import time
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
import pyqtgraph.exporters as exporters
import pyqtgraph as pg
from PyQt5 import uic, QtCore
import equations as formulas

class MyInterface(QMainWindow):
    def __init__(self):
        super(MyInterface, self).__init__()
        uic.loadUi('interface_SBD.ui', self)

        # define attributes
        self.vehicle_mass = 500.0  # minimum 500Kg
        self.velocities = []  # first value must be defined by user through interface
        self.deceleration = 0.0
        self.road_type = ""
        self.road_condition = ""
        self.road_inclination = 0
        self.positions = [0.0]
        self.initial_b_t = 0.0  # starting braking time
        self.initial_b_p = 0.0  # starting braking position

        # clock to measure at specific time the distance "driven"
        self.sample_time = 0.1  # 0.1sec
        self.times = [0.0]
        self.timer = QtCore.QTimer()  # Setup a timer to update the graph.
        self.timer.setInterval(int(self.sample_time * 1000))
        self.timer.timeout.connect(self.update_plot)

        # design graph
        # self.position_plot.setTitle(text='Simulation Breaking Distance', axis='top')
        labelStyle = {'color': '#FFF', 'font-size': '11pt'}
        self.position_plot.setLabel(text='Time', units='s', axis='bottom', **labelStyle)
        self.position_plot.setLabel(text='Position', units='m', axis='left', **labelStyle)
        pg.setConfigOption('background', 'w')
        self.velocity_plot.setLabel(text='Time', units='s', axis='bottom', **labelStyle)
        self.velocity_plot.setLabel(text='Velocity', units='m/s', axis='left', **labelStyle)

        # adding action to simulation button
        self.simulation_button.clicked.connect(self.simulate)

        # adding action to simulation button
        self.break_button.clicked.connect(self.press_break)

        # adding action to clear button
        self.clear_button.clicked.connect(self.clear_plot)

        # adding action to export button
        self.export_button.clicked.connect(self.export_plot)

    def initialize_parameters(self):
        # initialize parameters to recalculate a new brake distance
        self.times = [0.0]
        self.positions = [0.0]
        self.velocities = []
        self.deceleration = 0.0
        self.road_inclination = 0.0
        self.position_plot.clear()
        self.velocity_plot.clear()
        self.brake_distance_box.setValue(0)
        self.brake_time_box.setValue(0)

    def simulate(self):
        self.initialize_parameters()  # initialize parameters

        # assign user-parameters to the attributes
        self.vehicle_mass = self.mass_value.value()
        self.velocities.append(round(self.velocity_value.value() * 1000 / 3600, 2))  # change velocity into in m/s
        self.road_type = self.road_type_value.currentText()
        self.road_condition = self.road_condition_value.currentText()
        self.road_inclination = self.inclination_value.value()

        if formulas.get_friction_coefficient(self.road_type, self.road_condition) != 0:
            # enable/disable buttons
            self.simulation_button.setEnabled(False)
            self.break_button.setEnabled(True)
            self.export_button.setEnabled(False)
            self.timer.start()  # start clock

        else:
            msg = QMessageBox()
            msg.setWindowTitle("Warning: road conditions does not match!")
            msg.setText("Select proper road conditions")
            msg.setIcon(QMessageBox.Warning)
            msg.exec_()

    def update_plot(self):
        # calculate next time to sample
        self.times.append(self.times[-1] + self.sample_time)

        # get current position and add into an array of positions to plot it afterwards
        self.positions.append(formulas.get_position(self.positions[-1], self.velocities[-1], self.deceleration,
                                                    self.sample_time, ))

        # get the current velocity and # add into an array of velocities to plot it afterwards
        self.velocities.append(formulas.get_velocity(self.velocities[-1], self.deceleration, self.sample_time))

        # plot positions and velocities against time
        self.position_plot.plot(self.times, self.positions)  # plot time vs position
        self.velocity_plot.plot(self.times, self.velocities)  # plot time vs velocity

        if self.velocities[-1] <= 0.0:  # vehicle has stopped
            self.timer.stop()  # stop sample clock
            # show brake parameters on the interface
            self.brake_distance_box.setValue(self.positions[-1] - self.initial_b_p)
            self.brake_time_box.setValue(self.times[-1] - self.initial_b_t)

    def press_break(self):
        # enable/disable buttons
        self.simulation_button.setEnabled(True)
        self.break_button.setEnabled(False)
        self.clear_button.setEnabled(True)
        self.export_button.setEnabled(True)

        # Calculate final distance-brake parameters
        f_c = formulas.get_friction_coefficient(self.road_type, self.road_condition)
        self.deceleration = formulas.get_deceleration(f_c, self.road_inclination)

        # set a vertical line to delimit the starting brake point
        self.initial_b_t = self.times[-1]  # set initial brake time
        brake_time = pg.InfiniteLine(self.initial_b_t, pen=({'color': [255, 0, 0, 100], 'width': 2.5}))
        self.initial_b_p = self.positions[-1]  # set initial brake position
        brake_pos = pg.InfiniteLine(self.initial_b_p, angle=0, pen=({'color': [255, 0, 0, 100], 'width': 2.5}))
        brake_vel = pg.InfiniteLine(self.initial_b_t, pen=({'color': [255, 0, 0, 100], 'width': 2.5}))
        self.position_plot.addItem(brake_time)
        self.position_plot.addItem(brake_pos)
        self.velocity_plot.addItem(brake_vel)

    def clear_plot(self):
        self.initialize_parameters()

    def export_plot(self):
        brake_distance = exporters.ImageExporter(self.position_plot.plotItem)
        velocity = exporters.ImageExporter(self.velocity_plot.plotItem)
        # save to file
        brake_distance.export('brake_distance.png')
        velocity.export('velocity.png')

if __name__ == "__main__":
    app = QApplication(sys.argv)
    interface = MyInterface()
    interface.show()
    sys.exit(app.exec_())


# Import libraries
import numpy as np
import matplotlib.pyplot as plt
from numpy import *
import os
import mesa_reader as mr
from scipy.optimize import curve_fit

# PATH DIRECTORY
PATH1_wd = '/Users/tranghuynh/Dropbox/LSU/Fall_2022/ASTR4750/project3/1M_star/LOGS_1_wd/'
PATH15_wd = '/Users/tranghuynh/Dropbox/LSU/Fall_2022/ASTR4750/project3/1M_star/LOGS_15_wd/'
PATH1_H = '/Users/tranghuynh/Dropbox/LSU/Fall_2022/ASTR4750/project3/1M_star/LOGS1_cntr_H_frac/'
PATH15_H = '/Users/tranghuynh/Dropbox/LSU/Fall_2022/ASTR4750/project3/1M_star/LOGS_15_cntr_H_frac/'
f1 = 'history.data'
f15 = 'history.data'
profile1 = 'profile3.data'
profile15 = 'profile1.data'
profile1_wd = 'profile100.data'

################################### BODY ##########################################
# Load data from LOGS using mesa_reader
os.chdir(PATH1_wd)
if os.path.exists(PATH1_wd):
    h = mr.MesaData(f1)
    p1_wd = mr.MesaData(profile1_wd)

os.chdir(PATH1_H)
if os.path.exists(PATH1_H):
    p1 = mr.MesaData(profile1)

os.chdir(PATH15_wd)
if os.path.exists(PATH15_wd):
    h15 = mr.MesaData(f15)

os.chdir(PATH15_H)
if os.path.exists(PATH15_H):
    p15 = mr.MesaData(profile15)

#Import data for 1 solar mass
ages = h.data('star_age')
log_dt = h.data('log_dt')
log_Teff = h.data('log_Teff')
log_L = h.data('log_L')
rho_c = h.data('center_Rho')
T_c = h.data('center_T')
# print(shape(T_c), '1M')
# print('T_c =', T_c)
# print('\n')

# Model for 15 solar mass

# Import data for 15 solar mass
ages15 = h15.data('star_age')
log_dt15 = h15.data('log_dt')
log_Teff15 = h15.data('log_Teff')
log_L15 = h15.data('log_L')
rho_c15 = h15.data('center_Rho')
T_c15 = h15.data('center_T')
# print(shape(T_c15), '15M')
# print('T_c15 = ', T_c15)

# HR Diagram plot for 1M
plt.figure(1)
plt.plot(h.log_Teff, h.log_L, 'b-', label = ' 1 solar mass')
plt.plot(h15.log_Teff, h15.log_L, 'r-', label = ' 15 solar mass')
plt.title('HR Diagram for 1M and 15M models')
plt.xlabel('log Effective Temperature')
plt.ylabel('log Luminosity')
legend = plt.legend(loc='lower right',shadow='True')
plt.minorticks_on()
# plt.show()

# Evolution of central density versus central temperature
plt.figure(2)
plt.plot(T_c, rho_c,'b-', label = ' 1 solar mass' )
plt.title('Evolution of Central Density versus Central Temperature ')
plt.xlabel(' Central Temperature')
plt.ylabel(' Cenral Density')
legend = plt.legend(loc='lower right',shadow='True')
plt.minorticks_on()
# plt.show()

plt.figure(3)
plt.plot(T_c15, rho_c15,'r-', label = ' 15 solar mass' )
plt.title('Evolution of Central Density versus Central Temperature ')
plt.xlabel(' Central Temperature')
plt.ylabel(' Cenral Density')
legend = plt.legend(loc='lower right',shadow='True')
plt.minorticks_on()
# plt.show()

# PART B
# Load profile data

# Retrieve profile data for 1M for xa_central_lower_limit(1) = 0.6
log_P = p1.logP
# P = 10 ** log_P
log_rho = p1.logRho
# rho = 10 ** log_rho

#Retrieve profile data for 15M for xa_central_lower_limit(1) = 0.6
log_P15 = p15.logP
log_rho15 = p15.logRho
# P15 = 10 ** log_P15
# rho15 = 10 ** log_rho15

# Retrieve profile data for 1M of white draft stage
log_P_wd = p1_wd.logP
log_rho_wd = p1_wd.logRho

## MAKE PLOT FOR TESTING
# plt.figure(4)
# plt.plot(rho15, P15, label = ' 15 solar mass ')
# plt.xlabel(' Density ')
# plt.ylabel(' Pressure ')
# legend = plt.legend(loc='lower right',shadow='True')
# plt.show()

# #Define EOS function
def eos(log_rho, gamma):
    return log_rho*gamma
# y_mod = eos(trunc_rho15, 0.05) #*1e10
# #Perform the fit	(LINEAR)
fit,cov = curve_fit(eos,log_rho,log_P)
fit15,cov15 = curve_fit(eos, log_rho15, log_P15)
fit_wd, cov_wd = curve_fit(eos, log_rho_wd,log_P_wd)
n1 = 1./(fit - 1.)
n15 = 1./(fit15 - 1.)
n1_wd = 1./(fit_wd - 1.)
print("The polytropic index for 1 solar mass is ", n1 , ", where gamma =", fit, "+/-", cov)
print("The polytropic index for 15 solar mass is ", n15, ", where gamma =", fit15, "+/-", cov15)
print("The polytropic index for 1 solar mass in wd stage is ", n1_wd , ", where gamma =", fit_wd, "+/-", cov_wd)

#Fit Plot for 1M with central limit = 0.6
plt.figure(4)
plt.plot(log_rho, log_P, 'r-', label = 'data')
plt.plot(log_rho, eos(log_rho, abs(fit)), 'b-', label = 'fit')
plt.title('Equation of State for 1M when x_central_mass_fraction > 0.6')
plt.xlabel(' Log Density ')
plt.ylabel(' Log Pressure ')
legend = plt.legend(loc='lower right',shadow='True')
# plt.show()

#Fit Plot for 15M with central limit = 0.6
plt.figure(5)
plt.plot(log_rho15, log_P15, 'r-', label = 'data')
plt.plot(log_rho15, eos(log_rho15, abs(fit15)), 'b-', label = 'fit')
plt.title('Equation of State for 15M when x_central_mass_fraction > 0.6')
plt.xlabel(' Log Density ')
plt.ylabel(' Log Pressure ')
legend = plt.legend(loc='lower right',shadow='True')

#Fit Plot for 1M at white dwarf stage
plt.figure(6)
plt.plot(log_rho_wd, log_P_wd, 'r-', label = 'data')
plt.plot(log_rho_wd, eos(log_rho_wd, abs(fit_wd)), 'b-', label = 'fit')
plt.title('Equation of State for 1M at white dwarf stage')
plt.xlabel(' Log Density ')
plt.ylabel(' Log Pressure ')
legend = plt.legend(loc='lower right',shadow='True')
plt.show()


#python version 3.9.7
#opncv-python version = 4.5.4.60
#mediapipe version = 0.8.9.1

import cv2
from mpFaceSimplified import mpFace
import math

cam = cv2.VideoCapture(0)
# cam = cv2.VideoCapture("http://192.168.1.3:4747/video")# connecting to ip cam
width = int(cam.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cam.get(cv2.CAP_PROP_FRAME_HEIGHT))
#print(width,height)

cam.set(cv2.CAP_PROP_FPS, 30)
cam.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))

radius = 2
red = (0,0,255)
green = (0,255,0)
blue = (255,0,0)
yellow = (0,255,255)

faceLm = mpFace()

#For connecting range of dots
def connectPoints(indx1,indx2):
    for i in range(indx1,indx2):
        if i==(indx2-1):
            cv2.line(frame,(face[i][0],face[i][1]),(face[indx1][0],face[indx1][1]),green,1)
            break
        cv2.line(frame,(face[i][0],face[i][1]),(face[i+1][0],face[i+1][1]),green,1)
#Finding length between two points
def findRadius(pt1,pt2):
    x1,y1 = (pt1[0],pt1[1])
    x2,y2 = (pt2[0],pt2[1])
    radius = math.sqrt(((y2-y1)*(y2-y1))+((x2-x1)*(x2-x1)))
    return radius

while True:
    a, frame = cam.read()

    faces = faceLm.faceLandmarksSimplified(frame)
    # for face in faces:
    #     for lm in face:
    #         cv2.circle(frame,lm,radius,green,-1)
    for face in faces:
        #print(len(face))
        for indx in range(0,len(face)):# Total Landmarks = 141
            cv2.circle(frame,(face[indx][0],face[indx][1]),radius,red,-1)
            # print(face[indx])
        connectPoints(0,10)#Left Eyebrow (0->9)
        connectPoints(10,20)#right Eyebrow (10->19)
        connectPoints(20,36)#Left Eye (20->35)
        connectPoints(36,52)#Right Eye (36->51)
        connectPoints(52,72)#iner Lip (52->71)
        connectPoints(72,92)#outer Lip (72->91)
        connectPoints(92,128)#face boundary (92->127)

        cv2.circle(frame,(face[128][0],face[128][1]),3,yellow,-1)#left pupil (centre->128,adjacent->129)
        rl=findRadius(face[128],face[129])#left iris radius
        cv2.circle(frame,(face[128][0],face[128][1]),int(rl),blue,1)

        cv2.circle(frame,(face[133][0],face[133][1]),3,yellow,-1)#right pupil (centre->133,adjacent->134)
        rr=findRadius(face[133],face[134])#right iris radius
        cv2.circle(frame,(face[133][0],face[133][1]),int(rr),blue,1)

    cv2.imshow('Webcam', frame)
    if cv2.waitKey(1) & 0xff == ord('q'): # to quit the camera press 'q'
        print('end')
        break
cam.release()
cv2.destroyAllWindows()


from transformers import AutoModelForCausalLM, AutoTokenizer

checkpoint = "bigscience/bloomz-7b1"  # "bigscience/bloom"

tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForCausalLM.from_pretrained(
    checkpoint, torch_dtype="auto", device_map="auto", load_in_8bit=True
)

inputs = tokenizer.encode(
    "Question: What is Prompt engineering?\n Answer: Let's think step by step.",
    return_tensors="pt",
).to("cuda")
outputs = model.generate(inputs, max_new_tokens=100, min_new_tokens=30)

for out in outputs:
    print(tokenizer.decode(out))


# Examples of Python Keywords
# False
# True
# None
# and
# or
# not
# if
# else
# elif
# while
# for
# in
# break
# continue
# def
# return
# class
# try
# except
# finally
# import
# from
# as
# with
# raise
# assert
# lambda

# False, True, and None:
# False and True are Boolean values representing the logical values of false and true, respectively.
# # None represents the absence of a value and is often used to indicate the absence of a return value in functions.

is_active = False
is_valid = True
result = None

# and, or, and not:
# and, or, and not are logical operators used for combining and negating conditions.
a = True
b = False

if a and b:
    print("Both a and b are true")

if a or b:
    print("Either a or b is true")

if not b:
    print("b is false")

# if, else, and elif:
# if, else, and elif are used for conditional statements and control the flow of the program based on specific conditions.
num = 10

if num > 0:
    print("Number is positive")
elif num < 0:
    print("Number is negative")
else:
    print("Number is zero")

# while and for:
# while and for are used for loop statements to iterate over a sequence of values until a certain condition is met.
count = 0
while count < 5:
    print("Count:", count)
    count += 1

numbers = [1, 2, 3]
for num in numbers:
    print("Using for", num)

# break and continue:
# break is used to exit a loop prematurely, while continue is used to skip the remaining code in the current iteration and move to the next one.
for num in range(5):
    if num == 3:
        break
    print("Using break", num)

for num in range(5):
    if num == 3:
        continue
    print("Using continue", num)

# def and return:
# def is used to define user-defined functions.
# return is used to specify the value that a function should return.
def add_numbers(a, b):
    return a + b

result = add_numbers(2, 3)
print(result)

# class:
# class is used to define a class, which is a blueprint for creating objects.
class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

circle = Circle(5)
print("Area is: ", circle.area())

# try, except, and finally:
# try, except, and finally are used for exception handling to catch and handle potential errors in code execution.
try:
    num = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero")
finally:
    print("Execution complete")

# import and from:
# import and from are used to include modules or specific functions from modules into the current program.
import math
print(math.sqrt(25))

from datetime import datetime
current_time = datetime.now()
print(current_time)

# as:
# as is used for aliasing, allowing you to give an alternate name to a module or object.
import numpy as np
array = np.array([1, 2, 3])
total = np.sum(array)
print(total)

# with:
# with is used in the context manager construct to ensure proper acquisition and release of resources.
with open("file.txt", "r") as file:
    content = file.read()
    print(content)

# assert:
# assert is used for debugging purposes to check if a condition is true. If it's false, an AssertionError is raised.
num = 10

assert num > 0, "Number should be positive"
print("Assertion passed")

# lambda:
# lambda is used to define anonymous functions, also known as lambda functions.
multiply = lambda x, y: x * y
result = multiply(3, 4)
print(result)

# raise:
# raise is used to raise an exception explicitly.
age = -5
if age < 0:
    raise ValueError("Age cannot be negative")


import matplotlib.pyplot as plt

from EixampleEnergy.tool import load_shapefile
from EixampleEnergy.drawers.drawer import Drawer
from EixampleEnergy.drawers.drawer_map import DrawerMap
from EixampleEnergy.drawers.drawer_stacked_bar import DrawerStackedBar

def clean_data(df):
    df = df[df['build_date'] > 1900]
    df['build_date_10'] = df['build_date'].apply(lambda date: date - (date % 10))
    return df

def main():
    df = load_shapefile('../data/BCN_Private_communities/BCN_Private_communities_4326.shp')
    df = clean_data(df)
    cmap = plt.cm.RdYlGn.reversed()
    drawer_map = DrawerMap(full_df=df,
                           color_col="E_certific",
                           xlim=(2.05, 2.23),
                           # ylim=(41.313, 41.47),
                           bg_img='../out/background_greyscale.tif',
                           cmap=cmap)
    drawer_stacked = DrawerStackedBar(full_df=df,
                                      xcol='build_date_10',
                                      group_col='E_certific',
                                      xlabel="Build year",
                                      ylabel="Energy Certificate",
                                      cmap=cmap)

    drawer_map.download_bg('../out/bg.tif')
    exit()

    drawer = Drawer(full_df=df,
                    drawers=[drawer_map],
                    # drawers=[drawer_map, drawer_stacked],
                    time_col='build_date_10',
                    dpi=600,
                    # dpi=72,
                    save_dir_path='../out/building_cert2/map/')

    # drawer.draw_anime(save_anim_imgs=True, show=False)
    drawer.draw_static()

if __name__ == '__main__':
    main()


import pyautogui
import webbrowser
import time
from datetime import datetime

while True:
    now =datetime.now()

    if now.strftime("%H%M%S") == "184730":
        webbrowser.get("C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s").open_new(
        "https://zoom.us")

        time.sleep(7)
        pyautogui.click(1435, 150)
        time.sleep(6)
        pyautogui.click(945, 750)
        time.sleep(6)
        pyautogui.click(916, 590)

    if now.strftime("%H%M%S") == "184800":
        webbrowser.get("C:/Program Files (x86)/Google/Chrome/Application/chrome.exe %s").open_new(
        "https://zoom.us")

    break

        # pyautogui.hotkey('alt', 'v')
        # pyautogui.hotkey('alt', 'a')


from django.contrib import admin
from django.urls import path,include
from django.conf import settings
from django.conf.urls.static import static
from django.contrib.staticfiles.urls import staticfiles_urlpatterns

import debug_toolbar

from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
   openapi.Info(
      title="Movie Database API",
      default_version='v1',
      description="A sample Movie Database API",
      terms_of_service="http://localhost:8000",
      contact=openapi.Contact(email="vipin6673@gmail.com"),
      license=openapi.License(name="BSD License"),
   ),
   public=True,
   permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/',include('api.urls')),

    # for openapi
    path('api-auth/',include('rest_framework.urls')),
    path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
    path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

# for serving static files
urlpatterns+=static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns+=static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += staticfiles_urlpatterns()

if settings.DEBUG:
   urlpatterns+=[
      path('__debug__/', include(debug_toolbar.urls)),
   ]