from PyQt5.Qt import *
from UI.catalog_registration import Ui_MainWindow
import sys
from databaselink2 import connect

class CatalogPane(Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("期刊管理系统")
        self.mode = "catalog"
        self.setupUi(self)
        self.retranslateUi(self)

    def Return(self):
        self.return_signal.emit(self.mode)

    def Submit(self):
        row_count = self.new_catalog.rowCount()
        column_count = self.new_catalog.columnCount()
        catalogs = []  # 入库登记内容
        for row in range(row_count):
            if self.new_catalog.item(row, 0) is None:
                continue
            catalog = []
            for col in range(column_count):
                item = self.new_catalog.item(row, col)
                if item is None:
                    QMessageBox.warning(self, "登记提示", "录入信息不完整！请重试",
                                        QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
                    return
                catalog.append(item.text())
            catalogs.append(catalog)  # 逐条记录添加
        print(catalogs)

        insert_success = connect.catalog_register(catalogs)
        if insert_success:
            QMessageBox.information(self, "登记提示", "登记成功！",
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
        else:
            QMessageBox.information(self, "登记提示", "登记失败！请重试",
                                    QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

    def AddLine(self):
        self.new_catalog.setRowCount(self.new_catalog.rowCount()+1)

    return_signal = pyqtSignal(str)

if __name__ == "__main__":
    app = QApplication(sys.argv)

    window = CatalogPane()
    window.show()

    sys.exit(app.exec_())


#!/usr/bin/python
from random import random

from phue import Bridge

b = Bridge('192.168.1.15')

# If the app is not registered and the button is not pressed, press the button and call connect() (this only needs to be run a single time)
b.connect()

# Prints if light 1 is on or not

while 1:
    command = {'transitiontime' : 1, 'on' : True, 'bri' : 100, 'xy': [random(), random()]}
    b.set_light(3, command)


# Создание собственных объектов itrable
# 1
# Мы уже использовали ф-ю range(), которая возвращает последовательность чисел,
# в диапазоне, заданном параметрами этой ф-и

for number in range(1, 10):
    print(number)

# Создадим класс, повторяющий функционал ф-и range()

# class MyRange():
#     def __init__(self, start, end):
#         self.start = start
#         self.end = end

# Теперь мы можем создать объекты этого класса
# first_range = MyRange(1, 10)
# Но, на данный момент этот класс не являкется iterable
# Если мы вызовем для него iter()
# iter(first_range)
# Получим ошибку: TypeError: 'MyRange' object is not iterable
# Что надо сделать, чтобы этот класс стал iterable?
# Для этого в этом классе нужно имплементировать метод iter -> 1/1

class MyRange():
    def __init__(self, start, end):
        self.start = start
        self.end = end
        self.current = start  # <- 2. Инициализируем его значением Start.
        # То есть, изначально, мы поместим первый элемент последовательности в переменную current -> 3

# 1/1
# Этот метод должен возврщать iterator

    def __iter__(self):
        # return 1  # - так не пойдет, получим TypeError: iter() returned non-iterator of type 'int'
        # так как тут мы возвращаем не итератор, а целое число, объект типа 'int'
        # но, если здесь мы вернем любой итератор, например, полученный из строки,
        # мы можем из любого iterable получить iterator (лист, тьюпл, словарь, сет)
        # return iter('hi')
        # Здесь никакой ошибки не получаем, так как мы возвращаем объект - стринговый итератор
        # все работает корректно, но, для нашего случая это не подходит, потому что нам нужно, чтобы
        # итерация происходила в диапазоне start - end. Поэтому сделаем по другому.
        # здесь мы будем возвращать параметр self, то есть сам вновь созданный объект
        return self
        # Но, сейчас этот объект еще не является итератором, и, чтобы он им стал,
        # надо имплементировать метод next()

    def __next__(self):
        # и здесь уже нам надо реализовывать логику - получить последовательнолсь от start до end
        # и последовательно возвращать эти элементы этой последовательности
        # поэтому введем еще один параметр self.current вконструкторе -> 2
        # -> 3
        # Далее будем проверять
        if self.current < self.end:
            # создаем переменную и присваиваем ей self.current
            number = self.current  # это первый элемент последовательности на данный момент
            self.current += 1
            return number  # -> 3/1
        # 4
        raise StopIteration
        #  и теперь мы получим эту последовательность

# -> 3/1
# Дальше попробуем использовать это в цикле
first_range = MyRange(20, 30)
for number in first_range:
    print(number)
# Получаем бесконечный цикл
# Для того, чтобы не было бесконечного цикла, в конце надо выбросить исключение -> 4

# Мы рассмотрели работу этих двух методов __iter__ и __next__ с целью понять, как можно их
# имплиментировать в свой класс, чтобы сделать класс iterable


# Desafío 2: ANALIZADOR DE TEXTOS

# Crear un programa que le pida al usuario ingresar un texto y luego 3 letras de su interés; a partir de ello que se analice:

frase =(input("Ingrese el texto: "))
fm = frase.lower()
l1 = input("Ingrese primera letra: ")
l2 = input("Ingrese segunda letra: ")
l3 = input("Ingrese tercera letra: ")

# 1°) Cantidad de veces que aparece cada letra

letras = [l1.lower(),l2.lower(),l3.lower()]
for i in letras:
    print("La letra ",i," aparece ",fm.count(i),"veces.")

# 2°) Cantidad total de palabras en el texto

palabras = frase.split(" ")
print("La cantidad de palabras que tiene el texto ingresado es: ",len(palabras))

# 3°) Primera y última letra que aparecen en el mismo

print(f'La primera letra es {frase[0]}, y la última letra es {frase[-1]}')

# 4°) Mostrar el texto en orden inverso

palabras.reverse()
print("El texto en orden inverso es: ",palabras)

# 5°) Indicar si la palabra "Python" aparece en el texto

posibilidades = {
    True : "existe",
    False : "no existe"
}

yes_python = "python" in fm

print("En la frase introducida la palabra Python",posibilidades[yes_python])


assignments = []

"""Initializing values of rows and columns."""
digits = '123456789'
rows = 'ABCDEFGHI'
cols = digits

def cross(A, B):
    "Cross product of elements in A and elements in B."
    return [a+b for a in A for b in B]

"""Creating lists for a diagonal sudoku."""
squares = cross(rows, cols)
row_list = [cross(r, cols) for r in rows]
col_list = [cross(rows, c) for c in cols]
box_list = [cross(rs, cs) for rs in ['ABC', 'DEF', 'GHI'] for cs in ['123', '456', '789']]
diag_list = [[x+y for x,y in zip(rows, cols)],[x+y for x,y in zip(rows, cols[::-1])]]

unit_list = row_list + col_list + box_list + diag_list

"""Creating dictionaries for units and peers."""
units = dict((s, [u for u in unit_list if s in u]) for s in squares)
peers = dict((s, set(sum(units[s],[]))-set([s])) for s in squares)

def assign_value(values, box, value):
    """
    Please use this function to update your values dictionary!
    Assigns a value to a given box. If it updates the board record it.
    """

    # Don't waste memory appending actions that don't actually change any values
    if values[box] == value:
        return values

    values[box] = value
    if len(value) == 1:
        assignments.append(values.copy())
    return values

def naked_twins(values):
    """Eliminate values using the naked twins strategy.
    Args:
        values(dict): a dictionary of the form {'box_name': '123456789', ...}

    Returns:
        the values dictionary with the naked twins eliminated from peers.
    """

    # Find all instances of naked twins
    for unit in unit_list:
        potential_twins = {}
        # Get all boxes which contain the same pair of values: '11', '37' etc.
        for value_pair in cross(digits, digits):
            potential_twins[value_pair] = [box for box in unit if values[box] == value_pair]
        for x,y in potential_twins.items():
            if len(y) == 2:
                for box in unit:
                    if box not in y:
                        values = assign_value(values, box, values[box].replace(x[0],''))
                        values = assign_value(values, box, values[box].replace(x[1],''))

    return values

def grid_values(grid):
    """
    Convert grid into a dict of {square: char} with '123456789' for empties.
    Args:
        grid(string) - A grid in string form.
    Returns:
        A grid in dictionary form
            Keys: The boxes, e.g., 'A1'
            Values: The value in each box, e.g., '8'. If the box has no value, then the value will be '123456789'.
    """
    chars = []
    for c in grid:
        if c in '0.':
            chars.append(digits)
        else:
            chars.append(c)
    assert len(chars) == 81
    return dict(zip(squares, chars))

def display(values):
    """
    Display the values as a 2-D grid.
    Args:
        values(dict): The sudoku in dictionary form
    """
    width = 1+max(len(values[s]) for s in squares)
    line = '+'.join(['-'*(width*3)]*3)
    for r in rows:
        print(''.join(values[r+c].center(width)+('|' if c in '36' else '')
                      for c in cols))
        if r in 'CF': print(line)
    return

def eliminate(values):
    solved_values = [box for box in values.keys() if len(values[box]) == 1]
    for box in solved_values:
        digit = values[box]
        for peer in peers[box]:
            values = assign_value(values, peer, values[peer].replace(digit,''))
    return values

def only_choice(values):
    for unit in unit_list:
        for digit in '123456789':
            dplaces = [box for box in unit if digit in values[box]]
            if len(dplaces) == 1:
                values = assign_value(values, dplaces[0], digit)
    return values

def reduce_puzzle(values):
    solved_values = [box for box in values.keys() if len(values[box]) == 1]
    stalled = False
    while not stalled:
        solved_values_before = len([box for box in values.keys() if len(values[box]) == 1])

        # Iterate through Eliminate, Only_Choice, and Naked_Twins strategies
        values = eliminate(values)
        values = only_choice(values)
        values = naked_twins(values)

        solved_values_after = len([box for box in values.keys() if len(values[box]) == 1])
        stalled = solved_values_before == solved_values_after
        # Sanity check
        if len([box for box in values.keys() if len(values[box]) == 0]):
            return False
    return values

def search(values):
    # First, reduce the puzzle using the previous function
    values = reduce_puzzle(values)
    if values is False:
        return False
    if all(len(values[s]) == 1 for s in squares):
        return values
    # Choose one of the unfilled squares with the fewest possibilities
    n,s = min((len(values[s]), s) for s in squares if len(values[s]) > 1)
    # Use recursion to solve each sudoku and return that answer that is not False
    for value in values[s]:
        new_sudoku = values.copy()
        new_sudoku[s] = value
        attempt = search(new_sudoku)
        if attempt:
            return attempt

def solve(grid):
    """
    Find the solution to a Sudoku grid.
    Args:
        grid(string): a string representing a sudoku grid.
            Example: '2.............62....1....7...6..8...3...9...7...6..4...4....8....52.............3'
    Returns:
        The dictionary representation of the final sudoku grid. False if no solution exists.
    """
    values = grid_values(grid)
    values = search(values)
    return values

if __name__ == '__main__':
    diag_sudoku_grid = '2.............62....1....7...6..8...3...9...7...6..4...4....8....52.............3'

    display(solve(diag_sudoku_grid))

    try:
        from visualize import visualize_assignments
        visualize_assignments(assignments)

    except SystemExit:
        pass
    except:
        print('We could not visualize your board due to a pygame issue. Not a problem! It is not a requirement.')


import pandas as pd
import requests
import zipfile
import os
import re
import datetime
import numpy as np

def unzip(arg):
    zf = zipfile.ZipFile(arg)
    return [zf.read(name) for name in zf.namelist()]

def extract_date(arg):
    arg = re.findall(string=str(arg), pattern='[0-9]{6}')[0] + '01'
    dt = pd.to_datetime(arg)

    i = 32
    next_dt = dt + datetime.timedelta(i)
    while next_dt.month != dt.month:
        next_dt = dt + datetime.timedelta(i)
        i -= 1
    return dt + datetime.timedelta(i + 1)

def get_line_for_portfolio_group(arg, text_to_find=''):
    for elem in range(0, len(arg)):
        if text_to_find in arg[elem]:
            return elem

    return elem

def industry_portfolio_csv(N_portfolios=49, cleanup=True, weighting='equal'):
    """

    :param N_portfolios:
    :param cleanup:
    :return:
    """

    if weighting=='value':
        text_to_find = 'Average Value Weighted Returns'
    elif weighting=='equal':
        text_to_find = 'Average Equal Weighted Returns'
    url = 'https://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/{N}_Industry_Portfolios_CSV.zip'.format(
        N=N_portfolios)

    resp = requests.get(url=url)

    fdir = os.path.expanduser('~') + '/temp/'
    fname = os.path.split(url)[1]
    fpath = fdir + fname

    f = open(fpath, 'wb')
    f.write(resp.content)
    f.close()

    uz = unzip(open(fpath, 'rb'))

    if cleanup:
        os.unlink(fpath)

    lines = str(uz[0]).split('\\r\\n')
    line_for_group = get_line_for_portfolio_group(lines,text_to_find)

    lines = lines[line_for_group+1:]

    lines = [l.split(',') for l in lines]

    df = pd.DataFrame(lines[1:], columns=lines[0])

    first_line_break = df[df.iloc[:, 0] == ''].index[0]

    df = df.iloc[0:first_line_break, :]

    df.index = df.iloc[:, 0].apply(extract_date)
    del df['']
    df = df.replace(' -99.99', np.nan)
    df = df.astype(float)

    return df / 100.

if __name__ == '__main__':
    industry_portfolio_csv()


import os
import json
from tracemalloc import start
import discord
from discord.ext import commands
import asyncio

INITIAL_EXTENSIONS = [
    'cogs.talk_and_question',
    'cogs.get_image',
    ]

try:
    intents = discord.Intents.all()
    bot = commands.Bot(command_prefix='??',intents=intents)
except Exception as  e:
    print(e)

if os.path.exists('token.json') :
    pass
else :
    check_token = {'token': 'plz replace tihs text'}
    check_1PSID = {'1PSID': 'plz replace tihs text'}
    with open('token.json', 'w') as f:
     jsondata = [check_token, check_1PSID]
     json.dump(jsondata, f, indent=2)
     print('token.json created plz edit it file. file location is RootDirectory/token.json\r\n')
     exit()

@bot.event
async def on_ready():
    print(f'complete logging in! {bot.user}')
    try:
         await bot.tree.sync()
    except Exception as e:
        print(e)

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return

    if message.content.startswith('$こんにちは'):
        await message.channel.send('こんにちは！')

with open('token.json', 'r') as f:
     data = json.load(f)
bot_token = data[0]['token']
try:
 async def load_extension():
  for cog in INITIAL_EXTENSIONS:
   await bot.load_extension(cog)
except Exception as  e:
    print(e)

async def main():
 async with bot:
  await load_extension()
  await bot.start(bot_token)
try:
   asyncio.run(main())
except Exception as e:
    print(e)
    exit()


from typing import List
class DSU:
    def __init__(self, N):
        self.pre = [i for i in range(N)]

    def find(self, root):
        if self.pre[root] != root: self.pre[root] = self.find(self.pre[root])
        return self.pre[root]

    def union(self, x, y):
        xroot = self.find(x)
        yroot = self.find(y)
        if xroot != yroot:
            self.pre[x] = yroot
            self.pre[xroot] = yroot

class Solution:
    def removeStones(self, stones: List[List[int]]) -> int:
        N = len(stones)
        dsu = DSU(20000)
        for x, y in stones: dsu.union(x, y + 10000)

        return N - len(set(dsu.find(x) for x, y in stones))

if __name__ == '__main__':
    solution = Solution()
    print(solution.removeStones([[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]))


# -*- coding: utf-8 -*-
"""Project Euler: Problem 61

Find the sum of the only ordered set of six cyclic 4-digit numbers
for which each polygonal type: triangle, square, pentagonal, hexagonal,
heptagonal, and octagonal, is represented by a different number
in the set.

https://projecteuler.net/problem=61
"""
from typing import List
import itertools

def generate_4digit_figurate_number(sides: int) -> List[int]:
    """Generates all 4-digit figurate number for a given number of sides

    Args:
        sides: the number of "sides" for the figurate number;
               e.g. 3 for triangular, 8 for octagonal, etc.

    Returns:
        List of all 4-digit figurate numbers
    """
    if not 2 < sides < 9:
        return []
    figurate_list = []
    figurate_number = 0
    n = 1
    while True:
        if sides == 3:
            figurate_number = n * (n + 1) // 2
        if sides == 4:
            figurate_number = n ** 2
        if sides == 5:
            figurate_number = n * (3 * n - 1) // 2
        if sides == 6:
            figurate_number = n * (2 * n - 1)
        if sides == 7:
            figurate_number = n * (5 * n - 3) // 2
        if sides == 8:
            figurate_number = n * (3 * n - 2)

        if 10000 > figurate_number > 999:
            figurate_list.append(figurate_number)
        elif figurate_number > 10000:
            return figurate_list
        n += 1

def is_cyclical(n: int, m: int) -> bool:
    """Finds if n and m are cyclical numbers

    Args:
        n: first number to check (looks at last two digits)
        m: second number to check (looks at first two digits)

    Returns:
        True if first two digits of m equal last two digits of n
    """
    if n % 100 == m // 100:
        return True
    else:
        return False

def find_cyclicals(numbers: List[int], comparator: int) -> List[int]:
    """Finds all numbers in a list that are cyclicals of a comparator.

    Args:
        numbers: list to search through
        comparator: number of which cyclicals to find

    Returns:
        List of all cyclicals of the number
    """
    return [n for n in numbers if is_cyclical(comparator, n)]

def main():
    numbers = [generate_4digit_figurate_number(n) for n in range(3, 9)]
    possible_permutations = list(itertools.permutations(range(0, 6)))
    possibilities = []
    for order in possible_permutations:
        cyclical_groups = []
        # Find initial list
        for item in numbers[order[0]]:
            for n in find_cyclicals(numbers[order[1]], item):
                cyclical_groups.append([item, n])
        # Generate further steps
        for cycle in cyclical_groups:
            for i in range(2, 6):
                for n in find_cyclicals(numbers[order[i]], cycle[-1]):
                    cycle.append(n)
        # Trim non-6 element lists
        cyclical_groups = [c for c in cyclical_groups if (len(c) == 6)]
        # See if all elements are cyclical (also checks first and last elements' cycle)
        # For some reason the find_cyclicals function returns non-cyclical combinations
        cyclical_groups = [c for c in cyclical_groups if all([is_cyclical(c[i], c[i + 1]) for i in range(-1, 5)])]
        for c in cyclical_groups:
            possibilities.append(c)
    # Sum possibilities and return the set (only unique value)
    print(set([sum(p) for p in possibilities]))

if __name__ == '__main__':
    main()


import pickle
import traceback
import datetime

# Global Colours
BLACK = "#000000"
COMMANDERROR = "#ff3030"
INFO = "#636363"

class CircularQueue():
  """
  A custom circular queue implementation.
  """
  def __init__(self, maxSize):
    if maxSize < 1:
      raise ValueError("Queue size must be at least 1")
    self.data = [''] * maxSize
    self.rear = -1
    self.front= 0
    self.size = 0
    self.maxSize = maxSize

  def enQueue(self, item):
    """
    Add an item to the queue.

    Args:
      item (*): Item to add to the queue.
    """
    if self.size == self.maxSize:
      raise ValueError("Cannot enqueue when the queue is full")
    else:
      self.rear = (self.rear + 1) % self.maxSize
      self.data[self.rear] = item
      self.size = self.size + 1

  def deQueue(self):
    """
    Removes an item from the queue.

    Returns:
      (*): The item at the front of the queue.
    """
    self.front += 1
    self.size -= 1
    return self.data[self.front-1]

  def isFull(self):
    """ Determines if the queue is full. """
    return self.size == self.rear

  def isEmpty(self):
    """ Determines if the queue is empty. """
    return self.size == 0

class Message():
  """
  Represents a message.

  Args:
    senderId (int): The user id of the message sender.
    senderName (string, optional): The username of the
    contents (string, optional): The actual message content
    timeSent (string, optional): The time that the message was sent.
    recipientId (int, optional): The user id of the user that sent the message.
    colour (string, optional): The colour to display the message as.
    messageId (int, optional): The id of the message.
    edited (bool, optional): Denotes whether the message has been edited.
  """
  def __init__(self, senderId="", senderName="", contents="", timeSent="", recipientId=1, colour="#000000", messageId="", edited=False):
    self.senderId = senderId
    self.senderName = senderName
    self.contents = contents
    self.timeSent = timeSent
    self.recipientId = recipientId
    self.colour = colour
    self.messageId = messageId
    self.edited = edited

def hashString(string):
  """
  Custom implementation of a simple one way hashing algorithm

  Args:
    string (string): The string to hash.

  Returns:
    (string): The hashed string.
  """
  bitValueChunk = ""
  bitSum = 0

  for char in string:
    bitSum += ord(char)
    bitValue = format(ord(char), 'b') # Convert char to binary
    bitValueChunk += bitValue # Append to 'binary chunk'

  n = 9
  bitValues = [bitValueChunk[i:i+n] for i in range(0, len(bitValueChunk), n)] # Split 'binary chunk' into list of 9 bit binary numbers

  moddedBitChunk = ""
  for bitValue in bitValues:
    bitValue = int(bitValue)
    moddedBitValue = bitValue + (bitValue % 37) # Modulo is a one way function, so we modulo by a prime as the core of the hash. This is the step that ensures the hash is unidirectional
    moddedBitValue = moddedBitValue * bitSum # Multiply by sum of the ascii values of the chars to ensure similar input strings look different
    moddedBitChunk += format(moddedBitValue, 'b') # Convert into binary again

  n = 6 # 6 bit chunks to avoid strange characters
  moddedBitValues = [moddedBitChunk[i:i+n] for i in range(0, len(moddedBitChunk), n)] # Split modded 'binary chunk' into list of 8 bit binary numbers

  hashed = ""
  for moddedBitValue in moddedBitValues:
    hashed += chr(int(moddedBitValue, 2) + 33) # Convert binary value into decimal value then into the corresponding character, skipping the first 33 as they are non-printing/whitespace

  return hashed

def integerMergeSort(mergelist):
  """
  Custom implementation of a mergesort algorithm for integers.

  Args:
    mergeList (list of int): The list to sort.

  Returns:
    (list of int): The sorted list.
  """
  if len(mergelist) > 1:
      mid = len(mergelist) // 2 # Perform integer division
      lefthalf = mergelist[:mid] # Left half of merglist into lefthalf
      righthalf = mergelist[mid:] # Right half of merglist into righthalf
      lefthalf = MergeSort(lefthalf)
      righthalf = MergeSort(righthalf)

      i = 0
      j = 0
      k = 0
      while i < len(lefthalf) and j < len(righthalf):
          if lefthalf[i] < righthalf[j]:
              mergelist[k] = lefthalf[i]
              i += 1
          else:
              mergelist[k] = righthalf[j]
              j += 1
          k += 1

      # Check if left half has elements not merged
      while i < len(lefthalf):
          mergelist[k] = lefthalf[i] # If so, add to mergelist
          i += 1
          k += 1
      # Check if right half has elements not merged
      while j < len(righthalf):
          mergelist[k] = righthalf[j] # If so, add to mergelist
          j += 1
          k += 1
  return mergelist

def stringListMergeSort(mergelist):
  """
  Custom implementation of a mergesort algorithm for strings.

  Args:
    mergeList (list of string): The list to sort.

  Returns:
    (list of string): The sorted list.
  """
  if len(mergelist) > 1:
    mid = len(mergelist) // 2 # Perform integer division
    lefthalf = mergelist[:mid] # Left half of merglist into lefthalf
    righthalf = mergelist[mid:] # Right half of merglist into righthalf
    lefthalf = stringListMergeSort(lefthalf)
    righthalf = stringListMergeSort(righthalf)

    i = 0
    j = 0
    k = 0
    while i < len(lefthalf) and j < len(righthalf):
        l = 0
        while ord(lefthalf[i][l]) == ord(righthalf[j][l]) and l < len(lefthalf[i])-1 and l < len(righthalf[j])-1: # If the charachers are the same, we must look at the next one until the end
            l += 1
        if ord(lefthalf[i][l]) < ord(righthalf[j][l]):
            mergelist[k] = lefthalf[i]
            i += 1
        else:
            mergelist[k] = righthalf[j]
            j += 1
        k += 1

    # Check if left half has elements not merged
    while i < len(lefthalf):
        mergelist[k] = lefthalf[i] # If so, add to mergelist
        i += 1
        k += 1
    # Check if right half has elements not merged
    while j < len(righthalf):
        mergelist[k] = righthalf[j] # If so, add to mergelist
        j += 1
        k += 1
  return mergelist

def reportError(exception="", logger=None):
  """ Easier name for traceback.print_exc(). """
  traceback.print_exc()
  if logger != None:
    logger.log(repr(exception))

def getDateTime():
  """ Gets the current time in yy/mm/dd HH:MM format. """
  return datetime.datetime.now().strftime("%y-%m-%d %H:%M")

def formatUsername(name):
  """
  Formats a string to confirm with username display style.

  Args:
    name (string): The name to format.

  Returns:
    (string): The formatted string.
  """
  if name == "" or name == "SERVER":
    return ""
  else:
    return "<" + name + ">: "

def formatDateTime(time):
  """
  Formats a string to confirm with time display style.

  Args:
    time (string): The time to format.

  Returns:
    (string): The formatted string.
  """
  if time == "":
    return ""
  else:
    return "" + time + " | "

def generateJoinLeaveMessage(direction, username):
  """
  Generates a standard message notifying of when users join/leave the server.

  Args:
    direction (string): Contains whether the user 'joined' or 'left' the server.
    username (string): The user who joined or left.

  Returns:
    (Message): The generated message.
  """
  return Message(1, "SERVER", "_" + username + " has " + direction + " the server_", getDateTime(), colour=INFO)

def debugPrint(message, debug):
  """
  Conditional Print depending on whether launched in debug mode or not.

  Args:
    message (string): The message to print.
    debug (bool): Whether the message should be printed.
  """
  if debug:
    print(message)

def encode(packet):
  """ Better name for pickle.dumps() """
  return pickle.dumps(packet)
def decode(packet):
  """ Better name for pickle.loads() """
  return pickle.loads(packet)


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()


class Solution(object):
    def hammingWeight(self, n):
        """
        :type n: int
        :rtype: int
        """
        # O(32) ~ O(1) Time complexity solution.

        result = 0
        # We loop through the bits of the number.
        while n > 0:
            # We add the rightmost bit to the result.
            result += n & 1 # equivalent to result += n % 2
            # Then we shift right to check the next rightmost bit in the
            # next iteration.
            n = n >> 1
        return result


import random
import time
from rich.console import Console
from rich.table import Table
import os
from rich import print
from rich.layout import Layout
from rich.markdown import Markdown

class Render:

    def table(self,
                CPU_Temperature="N/A",
                CPU_Usage="N/A",
                RAM_Usage="N/A",
                Cipher_Key="N/A",
                Cipher_Text="N/A",
                Decrypted_text="N/A",
                Brocker_IP="N/A",
                Proxy_IP="N/A",
                User="N/A",
                User_ATTRIBUTE="N/A",
                Transmission_Time = "N/A",
                Decrypt_Time = "N/A",
                Outsourcing_Time = "N/A",
                Local_Decrypt_time = "N/A",
                Total_Time="N/A",
            ):
        os.system('clear')
        Decrypt_Setup_Time = str(float(Decrypt_Time) - (float(Outsourcing_Time)+float(Local_Decrypt_time)))
        # Table 1
        table = Table()
        table.add_column("", justify="right", style="cyan", no_wrap=True)
        table.add_column("Subscriber <- Broker <- Publisher", justify="left", style="green")
        table.add_row("User", User)
        table.add_row("User attribute", User_ATTRIBUTE,end_section=True)
        table.add_row("Remote Device", "Raspberry Pi 3 Model A+", style="gold3")
        table.add_row("CPU Temperature", CPU_Temperature + " °C",style="gold3")
        table.add_row("CPU Usage", CPU_Usage +" %",style="gold3")
        table.add_row("RAM Usage", RAM_Usage +" %",style="gold3")
        table.add_row("Decrypted text", Decrypted_text,style="gold3")
        table.add_row("Cipher AES Key", Cipher_Key,style="gold3")
        table.add_row("Cipher Text", Cipher_Text,style="gold3")
        table.add_row("Brocker IP", Brocker_IP,style="gold3")
        table.add_row("Proxy IP", Proxy_IP,style="gold3")
        table.add_row("Transmission Time", Transmission_Time+" s",style="gold3")
        table.add_row("Decrypt setup Time", Decrypt_Setup_Time+" s",style="bright_cyan")
        table.add_row("Outsourcing Decrypt Time", Outsourcing_Time+" s",style="bright_cyan")
        table.add_row("Local Decrypt time", Local_Decrypt_time+" s",style="bright_cyan")
        table.add_row("Decrypt total Time", Decrypt_Time+" s",style="bright_red")
        table.add_row("Total Time", Total_Time+" s",style="bright_red")
        # Table 2
        # table2 = Table()
        # table2.add_column("Cipher AES Key", justify="center", style="cyan", no_wrap=True)
        # table2.add_row(Cipher_Key)
        # layout = Layout()
        # layout.split_column(
        #     Layout(table),
        #     Layout(table2)
        # )
        print(table)

if __name__ == '__main__':
    while True:
        os.system('clear')
        render = Render()
        render.table("50","50","50","AAA")
        time.sleep(2)


# R004
# Created by JKChang
# 01/03/2017, 10:31
# Tag: Date count
# Description: Count the days for a certain date.

def monthDay(month):
    swithcher = {
        1: 31,
        2: 28,
        3: 31,
        4: 30,
        5: 31,
        6: 30,
        7: 31,
        8: 31,
        9: 30,
        10: 31,
        11: 30,
        12: 31
    }
    return swithcher.get(month)

res = 0

leap = False
year = int(input('pls input year: '), )
if year < 0:
    print('illegal year')
if (year % 400 == 0) or ((year % 4 == 0) and (year % 100 != 0)):
    leap = True

month = int(input('pls input month: '), )
if (month < 0) or (month > 12):
    print('illegal month')

for mon in range(1, month):
    res += monthDay(mon)

day = int(input('pls input the day: '), )
res += day

if (month > 2) and leap:
    res += 1

print('it is the %dth day.' % res)


#================================================================
#
#   File name   : indicators.py
#   Author      : PyLessons
#   Created date: 2021-01-20
#   Website     : https://pylessons.com/
#   GitHub      : https://github.com/pythonlessons/RL-Bitcoin-trading-bot
#   Description : Used to plot 5 indicators with OHCL bars
#
#================================================================
import pandas as pd
from ta.trend import SMAIndicator, macd, PSARIndicator
from ta.volatility import BollingerBands
from ta.momentum import rsi
from utils import Plot_OHCL

def AddIndicators(df):
    # Add Simple Moving Average (SMA) indicators
    df["sma7"] = SMAIndicator(close=df["Close"], window=7, fillna=True).sma_indicator()
    df["sma25"] = SMAIndicator(close=df["Close"], window=25, fillna=True).sma_indicator()
    df["sma99"] = SMAIndicator(close=df["Close"], window=99, fillna=True).sma_indicator()

    # Add Bollinger Bands indicator
    indicator_bb = BollingerBands(close=df["Close"], window=20, window_dev=2)
    df['bb_bbm'] = indicator_bb.bollinger_mavg()
    df['bb_bbh'] = indicator_bb.bollinger_hband()
    df['bb_bbl'] = indicator_bb.bollinger_lband()

    # Add Parabolic Stop and Reverse (Parabolic SAR) indicator
    indicator_psar = PSARIndicator(high=df["High"], low=df["Low"], close=df["Close"], step=0.02, max_step=2, fillna=True)
    df['psar'] = indicator_psar.psar()

    # Add Moving Average Convergence Divergence (MACD) indicator
    df["MACD"] = macd(close=df["Close"], window_slow=26, window_fast=12, fillna=True) # mazas

    # Add Relative Strength Index (RSI) indicator
    df["RSI"] = rsi(close=df["Close"], window=14, fillna=True) # mazas

    return df

if __name__ == "__main__":
    df = pd.read_csv('./pricedata.csv')
    df = df.sort_values('Date')
    df = AddIndicators(df)

    test_df = df[-400:]

    Plot_OHCL(df)


import sys
sys.stdin = open('input.txt')

# 도식화한 지도에서 A도시에서 B도시로 가는 길이 존재하는지 조사하려고 한다.
# 길 중간 중간에는 최대 2개의 갈림길이 존재하고,
# 모든 길은 일방 통행으로 되돌아오는 것이 불가능하다.
# 다음과 같이 길이 주어질 때,
# A도시에서 B도시로 가는 길이 존재하는지 알아내라.

#  - A와 B는 숫자 0과 99으로 고정된다.
#  - 모든 길은 순서쌍으로 나타내어진다.
#  - 가는 길의 개수와 상관없이 한가지 길이라도 존재한다면 길이 존재하는 것이다.
#  - 단 화살표 방향을 거슬러 돌아갈 수는 없다.

# 출발점은 0, 도착점은 99으로 표현된다.
# 정점(분기점)의 개수는 98개(출발점과 도착점 제외)를 넘어가지 않으며,
# 한 개의 정점에서 선택할 수 있는 길의 개수도 2개를 넘어가지 않는다.

# 검사를 진행할 함수를 생성한다.
def DFS(start):
    # 스택을 시작지점으로 설정하고 시작한다.
    # 이전에 방문한 곳인지 확인하기 위하여
    # visited 배열을 만들어준다.
    stack = [start]
    visited = [0] * 100
    # stack이 있다면, 반복을 수행한다.
    # 시작 지점은 반복 시작 시, 스택의 마지막 값으로 한다.
    while stack:
        start = stack.pop()
        # 중간에 b 도시에 도착한다면,
        # 더이상 조사하지 않고 1을 출력한다.
        if start == 99:
            return print(f'#{tc} 1')
        # 같은 곳을 다시 방문하지 않도록
        # visited의 스타트를 1로 표시한다.
        if visited[start] == 0:
            visited[start] = 1
            # 스타트 위치에서 next로 이동가능하고, next가 0이라면 이동
            for next in range(1, 100):
                if matrix[start][next] == 1 and visited[next] == 0:
                    # 다음 조사 대상에 next를 추가한다.
                    stack.append(next)

    # 만약 스택이 없다면 0을 반환한다.
    return print(f'#{tc} 0')

# 총 10 번 동안 반복을 진행한다.
for q in range(10):
    # 첫 줄에는 테스트 케이스의 번호와 길의 개수가 주어진다.
    tc, e = list(map(int, input().split()))
    # 다음 줄에는 길의 방향과 정보가 주어진다.
    data = list(map(int, input().split()))
    # 데이터는 100칸 이므로 100*100 매트릭스를 만들어준다.
    matrix = [[0]*(100) for _ in range(100)]
    # 길의 갯수 동안 데이터를 순회하며
    # 각 데이터 목록에서 두개씩 읽어 매트릭스에 길을 표시한다.
    for i in range(e):
        matrix[data[i * 2]][data[i * 2 + 1]] = 1
    # 함수를 호출해 검사한다.
    DFS(0)


import sys
from collections import defaultdict
from enum import Enum

class Color(Enum):
    WHITE = 0,
    GRAY = 1,
    BLACK = 2

def top_sort(edges, s, entry, result):
    entry[s] = Color.GRAY
    for v in edges[s]:
        if entry[v] == Color.WHITE:
            top_sort(edges, v, entry, result)
    entry[s] = Color.BLACK
    result.append(s)

if __name__ == '__main__':
    line = sys.stdin.readline().split()
    n = int(line[0])
    m = int(line[1])
    edges = defaultdict(list)
    for _ in range(m):
        line = sys.stdin.readline().split()
        u = int(line[0])
        v = int(line[1])
        edges[u].append(v)
    for key in edges.keys():
        edges[key].sort(reverse=True)
    entry = [Color.WHITE] * (n + 1)
    order = []
    for i in range(1, n + 1):
        if entry[i] is Color.WHITE:
            top_sort(edges, i, entry, order)
    order.reverse()
    print(" ".join(map(str, order)))


# Lets follow our procedure to solve this question:
'''
Definition - can be understood from question (https://leetcode.com/explore/learn/card/fun-with-arrays/527/searching-for-items-in-an-array/3250/)

Data -
  - Input - a array that contains some intergers
  - output - return true if double exist, else False
  - Edge case - there could be one zero or zero available in array, need to consider this carefully.
  - assumptions - array would always have atleast 2 elements
       -  2 <= arr.length <= 500
       -  -10^3 <= arr[i] <= 10^3

Pseudo code -
  - sort array (time complexity - n log n)
  - run through each element of array and apply BSA
    - also make sure, i != j (this is critical edge case for 0, because 0*2 is also 0)
'''

# Actual Code
# Solution 1 -
class Solution:
    def checkIfExist(self, arr: List[int]) -> bool:
        arr.sort() # n log n
        for i in range(len(arr)):
            lo = 0
            hi = len(arr) - 1
            target_val = arr[i]*2
            while lo <= hi:
                mid = (lo+hi) // 2
                mid_val = arr[mid]
                print('arr_val=',arr[i], 'target=',target_val, 'lo=', lo, 'hi=', hi, 'mid=',mid)
                if target_val == mid_val and i != mid:
                    return True
                elif mid_val < target_val:
                    lo = mid+1
                else:
                    hi = mid-1
        return False


from flask import make_response
from app.utils.http_code import HTTP_404_NOT_FOUND,HTTP_500_INTERNAL_SERVER_ERROR
from flask import jsonify

def handle_404_error(error):
    """ Return 404 error in json for api"""

    return make_response(
        jsonify({
            'message': {
                'error' :'Not found'
            }
        }),
        HTTP_404_NOT_FOUND
    )

def handle_500_error(error):
    """ Return 500 error in json for api"""

    return make_response(
        jsonify({
            'message': {
                'error' :'Internal Server Error'
            }
        }),
        HTTP_500_INTERNAL_SERVER_ERROR
    )


import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.svm import LinearSVC
from sklearn.pipeline import Pipeline
import numpy as np
from sklearn.model_selection import GridSearchCV
import nltk
from nltk.stem.snowball import SnowballStemmer
import matplotlib.pyplot as plt
from sklearn.feature_selection import chi2
from sklearn.linear_model import SGDClassifier
from sklearn.metrics import confusion_matrix
import seaborn as sns

class SurveyAgent:
    def __init__(self, dataPath):
        self.df = pd.read_csv(dataPath, encoding='utf-8')
        col = ['label', 'text']
        self.df = self.df[col]
        self.df = self.df[pd.notnull(self.df['text'])]
        self.df.columns = ['label', 'text']
        #
        self.df.text = self.df.text.apply(lambda x: x.strip().encode().decode())
        self.df = self.df[~self.df.text.str.contains("duplicate")]
        #
        self.df['category_id'] = self.df['label'].factorize(sort=True)[0]
        self.category_id_df = self.df[['label', 'category_id']].drop_duplicates().sort_values('category_id')
        self.category_to_id = dict(self.category_id_df.values)
        self.labels = self.df.category_id
        id_to_category = dict(self.category_id_df[['category_id', 'label']].values)
        self.X_train, self.X_test, self.y_train, self.y_test, self.indices_train, self.indices_test = train_test_split(self.df.text, self.df.label, self.df.index, test_size=0.10, random_state=45)
        self.df.head()

    def graphClasses(self):
        fig = plt.figure(figsize=(8,6))
        self.df.groupby('label').text.count().plot.bar(ylim=0)
        plt.show()

    def getNgrams(self, N):
        self.tfidf = TfidfVectorizer(sublinear_tf=True, min_df=5, norm='l2', encoding='utf-8', ngram_range=(1, 2), stop_words='english')
        self.features = self.tfidf.fit_transform(self.df.text).toarray()
        self.labels = self.df.category_id
        self.features.shape
        for label, category_id in sorted(self.category_to_id.items()):
            features_chi2 = chi2(self.features, self.labels == category_id)
            indices = np.argsort(features_chi2[0])
            feature_names = np.array(self.tfidf.get_feature_names())[indices]
            unigrams = [v for v in feature_names if len(v.split(' ')) == 1]
            bigrams = [v for v in feature_names if len(v.split(' ')) == 2]
            print("# '{}':".format(label))
            print("  . Most correlated unigrams:\n. {}".format('\n. '.join(unigrams[-N:])))
            print("  . Most correlated bigrams:\n. {}".format('\n. '.join(bigrams[-N:])))

    def PipelineNB(self):
        text_clf = Pipeline([('Tfidvect', TfidfVectorizer()), ('clf', MultinomialNB(fit_prior=False))])
        text_clf = text_clf.fit(self.X_train, self.y_train)
        predicted = text_clf.predict(self.X_test)
        print("Accuracy with NB = " + str(np.mean(predicted == self.y_test)))
        return text_clf

    def PipelineSVM(self):
        text_clf_svm = Pipeline([('Tfidvect', TfidfVectorizer()),
                                 ('clf-svm', SGDClassifier(loss='hinge', penalty='l2',alpha=1e-3, max_iter=5, random_state=45, shuffle=True))])
        text_clf_svm = text_clf_svm.fit(self.X_train, self.y_train)
        predicted_svm = text_clf_svm.predict(self.X_test)
        print("Accuracy with SVM = " + str(np.mean(predicted_svm == self.y_test)))
        return text_clf_svm

    def PipelineLSCV(self):
        text_clf_lscv = Pipeline([('Tfidvect', TfidfVectorizer()), ('clf', LinearSVC())])
        text_clf_lscv = text_clf_lscv.fit(self.X_train, self.y_train)
        predicted_lscv = text_clf_lscv.predict(self.X_test)
        print("Accuracy with LSCV = " + str(np.mean(predicted_lscv == self.y_test)))
        return text_clf_lscv

    def gridSearchNB(self):
        parameters = {'vect__ngram_range': [(1, 1), (1, 2)], 'tfidf__use_idf': (True, False), 'clf__alpha': (1e-2, 1e-3)}
        gs_clf = GridSearchCV(self.text_clf, parameters, n_jobs=-1)
        gs_clf = gs_clf.fit(self.X_train, self.y_train)
        print(gs_clf.best_score_)
        print(gs_clf.best_params_)

    def gridSearchSVM(self):
        parameters_svm = {'vect__ngram_range': [(1, 1), (1, 2)], 'tfidf__use_idf': (True, False),'clf-svm__alpha': (1e-2, 1e-3)}
        gs_clf_svm = GridSearchCV(self.text_clf_svm, parameters_svm, n_jobs=-1)
        gs_clf_svm = gs_clf_svm.fit(self.X_train, self.y_train)
        print(gs_clf_svm.best_score_)
        print(gs_clf_svm.best_params_)

    def nltkModel(self):
        ##nltk.download()
        stemmer = SnowballStemmer("english", ignore_stopwords=True)

        class StemmedCountVectorizer(CountVectorizer):
            def build_analyzer(self):
                analyzer = super(StemmedCountVectorizer, self).build_analyzer()
                return lambda doc: ([stemmer.stem(w) for w in analyzer(doc)])

        stemmed_count_vect = StemmedCountVectorizer(stop_words='english')

        text_mnb_stemmed = Pipeline([('vect', stemmed_count_vect), ('tfidf', TfidfTransformer()),
                                     ('mnb', MultinomialNB(fit_prior=False))])

        text_mnb_stemmed = text_mnb_stemmed.fit(self.X_train, self.y_train)

        predicted_mnb_stemmed = text_mnb_stemmed.predict(self.X_test)

        print("Accuracy with nltk: " + str(np.mean(predicted_mnb_stemmed == self.y_test)))
        return text_mnb_stemmed

    def graphHeatMap(self, model):
        print("Generating graph")
        model_pred = model.predict(self.X_test)
        conf_mat = confusion_matrix(self.y_test, model_pred)
        fig, ax = plt.subplots(figsize=(10,10))
        sns.heatmap(conf_mat, annot=True, fmt='d', xticklabels=self.category_id_df.label.values, yticklabels=self.category_id_df.label.values)
        plt.ylabel('Actual')
        plt.xlabel('Predicted')
        plt.show()

###############################################
dataPath = "data\survey14DBV2.csv"
Survey13 = SurveyAgent(dataPath)
model = Survey13.PipelineLSCV()
##Survey13.graphClasses()
##Survey13.getNgrams(10)
##Survey13.graphHeatMap(Survey13.PipelineNB())
##Survey13.graphHeatMap(Survey13.PipelineSVM())
##Survey13.graphHeatMap(Survey13.PipelineLSCV())
##Survey13.gridSearchNB()
##Survey13.gridSearchSVM()
##Survey13.graphHeatMap(Survey13.nltkModel())


# Fill in the missing code below

count = 0
num = 0
while num != 10:
    num = int(input("Input an int: ")) # You can move this line but not change it
    if num != 10:
        count += num

print(count)


from __future__ import absolute_import

import sys
import os
import contextlib

try:
    from json import JSONDecodeError
except ImportError:
    JSONDecodeError = ValueError

from web3.utils.compat import (
    Timeout,
    threading,
    socket,
)

from .base import JSONBaseProvider

@contextlib.contextmanager
def get_ipc_socket(ipc_path, timeout=0.1):
    if sys.platform == 'win32':
        # On Windows named pipe is used. Simulate socket with it.
        from web3.utils.windows import NamedPipe

        pipe = NamedPipe(ipc_path)
        with contextlib.closing(pipe):
            yield pipe
    else:
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.connect(ipc_path)
        sock.settimeout(timeout)
        with contextlib.closing(sock):
            yield sock

def get_default_ipc_path(testnet=False):
    if testnet:
        testnet = "testnet"
    else:
        testnet = ""

    if sys.platform == 'darwin':
        return os.path.expanduser(os.path.join(
            "~",
            "Library",
            "Ethereum",
            testnet,
            "geth.ipc",
        ))
    elif sys.platform.startswith('linux'):
        return os.path.expanduser(os.path.join(
            "~",
            ".ethereum",
            testnet,
            "geth.ipc",
        ))
    elif sys.platform == 'win32':
        return "\\\\.\\pipe\\geth.ipc"
    else:
        raise ValueError(
            "Unsupported platform '{0}'.  Only darwin/linux2/win32 are "
            "supported.  You must specify the ipc_path".format(sys.platform)
        )

class IPCProvider(JSONBaseProvider):
    def __init__(self, ipc_path=None, testnet=False, *args, **kwargs):
        if ipc_path is None:
            self.ipc_path = get_default_ipc_path(testnet)
        else:
            self.ipc_path = ipc_path

        self._lock = threading.Lock()
        super(IPCProvider, self).__init__(*args, **kwargs)

    def make_request(self, method, params):
        request = self.encode_rpc_request(method, params)

        self._lock.acquire()

        try:
            with get_ipc_socket(self.ipc_path) as sock:
                sock.sendall(request)
                # TODO: use a BytesIO object here
                raw_response = b""

                with Timeout(10) as timeout:
                    while True:
                        try:
                            raw_response += sock.recv(4096)
                        except socket.timeout:
                            timeout.sleep(0)
                            continue

                        if raw_response == b"":
                            timeout.sleep(0)
                        else:
                            try:
                                response = self.decode_rpc_response(raw_response)
                            except JSONDecodeError:
                                timeout.sleep(0)
                                continue
                            else:
                                return response
        finally:
            self._lock.release()


import os

def get_file_name():
    for root, dirs, file_lists in os.walk("../Surge"):
        return file_lists

def main(file_lists):
    for file_name in file_lists:
        with open(f"../Surge/{file_name}", "r", encoding='utf-8') as read:
            note = read.read()
        note = note.replace(", ", ",").replace(",", ", ")
        print(file_name)
        with open(f"../Surge/{file_name}", "w", encoding='utf-8') as write:
            write.write(note)

if __name__ == '__main__':
    main(get_file_name())


''' Code realise par Makhtar SARR. '''

class Pile():
    """
    Classe Pile: voir les definitions ci-dessous
    Dernier arrive premier servi : LIFO
    La classe dispose d'une structure de type list pour ranger les données
    Les consultations, les insertions, les suppressions se font du même cote
    """

    def __init__(self):
        self.elements = []

    '''
    Insere un objet en tete de la pile
    '''

    def push(self, noeud):
        self.elements.append(noeud)

    '''
    Retourne True si un noeud est dans la pile
    '''

    def contains_noeud(self, name):
        for element in self.elements:
            if name == element:
                return True

        return False

    '''
    Retourne true si la pile est vide
    '''

    def empty(self):
        return self.elements == []

    '''
    Retourne et supprime l'element en tete de pile
    Retourne une exception si la pile est vide
    '''

    def remove(self):
        if self.elements:
            self.elements.pop()

    '''
    Affichage de la pile
    '''

    def __str__(self):
        items = ""
        for element in self.elements:
            if self.elements[0] == element:
                items = "\'" + str(element) + "\'" + items
            else:
                items = "\'" + str(element) + "\'" + ", " + items
        items = "[" + items + "]"
        return items

# Test des structures de données Pile et File
f = Pile()
f.push("Mamadou")
f.push("Mansour")
f.push("Dame")
f.push("Khady")
print(f)
f.remove()  # L'élément recemmenet ajouté de la liste sera enlevé
print(f.empty())