import math
import random

import pygame

pygame.font.init()
font = pygame.font.Font(None, 30)

FPS = 30

RED = 0xFF0000
BLUE = 0x0000FF
YELLOW = 0xFFC91F
GREEN = 0x00FF00
MAGENTA = 0xFF03B8
CYAN = 0x00FFCC
BLACK = (20, 20, 20)
WHITE = 0xFFFFFF
GREY = (120, 120, 120)
GAME_COLORS = [RED, BLUE, YELLOW, GREEN, MAGENTA, CYAN]
TANKGREEN = (100, 120, 70)

WIDTH = 800
HEIGHT = 600

pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.SRCALPHA)

#Рисуем поверхность с танком
tanksurf = pygame.Surface((300, 300))
tanksurf.set_colorkey((0, 0, 0))
pygame.draw.circle(tanksurf, GREY, (50, 250), 40)
pygame.draw.circle(tanksurf, GREY, (250, 250), 40)
pygame.draw.rect(tanksurf, GREY, (50, 210, 200, 80))
pygame.draw.circle(tanksurf, BLACK, (50, 250), 30)
pygame.draw.circle(tanksurf, BLACK, (250, 250), 30)
pygame.draw.circle(tanksurf, BLACK, (100, 250), 30)
pygame.draw.circle(tanksurf, BLACK, (150, 250), 30)
pygame.draw.circle(tanksurf, BLACK, (200, 250), 30)
pygame.draw.polygon(tanksurf, TANKGREEN, ((0, 230), (60, 170), (60, 230)))
pygame.draw.polygon(tanksurf, TANKGREEN, ((300, 230), (240, 170), (240, 230)))
pygame.draw.rect(tanksurf, TANKGREEN, (60, 170, 180, 60))
pygame.draw.circle(tanksurf, TANKGREEN, (150, 170), 60)

#Размещаем поверхность с танком на заданной поверхности, в координатах x, y и с масштабом scale
def draw_tank(surface, x , y, scale=1, color = TANKGREEN):
    tanknewsurf = tanksurf
    pygame.draw.polygon(tanknewsurf, color, ((0, 230), (60, 170), (60, 230)))
    pygame.draw.polygon(tanknewsurf, color, ((300, 230), (240, 170), (240, 230)))
    pygame.draw.rect(tanknewsurf, color, (60, 170, 180, 60))
    pygame.draw.circle(tanknewsurf, color, (150, 170), 60)
    if scale != 1:
        tanksurf_tranformed = pygame.transform.scale(tanksurf, (round(300*scale), round(300*scale)))
        surface.blit(tanksurf_tranformed, (x, y))
    else:
        surface.blit(tanksurf, (x, y))

def help():
    clock_help = pygame.time.Clock()
    help_active = True
    help_text = []
    text = []

    help_text.append("Управление у первого игрока: ")
    help_text.append("   A, D - двигать танк; W, S - целиться;")
    help_text.append("   E - зажимать для стрельбы; R - перезарядка;")
    help_text.append("   Q - сменить тип патронов;")

    help_text.append("Управление у второго игрока: ")
    help_text.append("   стрелочки вправо и влево - двигать танк;")
    help_text.append("   стрелочки вверх и вниз - целиться;")
    help_text.append("   RSHIFT - зажимать для стрельбы;")
    help_text.append("   RCTRL - перезарядка;")
    help_text.append("   ENTER - сменить тип патронов;")

    help_text.append("Если патроны закончились - ")
    help_text.append("перезаряжаться нужно вручную.")

    help_text.append("Серый эллипс скидывает новые мишени,")
    help_text.append("только если их становится меньше 10.")

    for i in range(len(help_text)):
        text.append(font.render(help_text[i], True, BLACK))

    size_x = 500
    size_y = 400
    help_x = 150
    help_y = 125

    exitbutton = Button(screen, help_x + size_x/2 - 50, help_y + size_y - 60, 100, 50, "back", 1)

    while help_active:
        clock_help.tick(FPS)
        pygame.draw.rect(screen, WHITE, (0, 0, WIDTH, HEIGHT))

        exitbutton.draw()

        helpsurface2 = pygame.Surface((size_x, size_y))
        helpsurface2.set_colorkey((0, 0, 0))
        pygame.draw.rect(helpsurface2, GREY, (0, 0, size_x, size_y), 7)
        screen.blit(helpsurface2, (help_x + 3, help_y + 3))

        helpsurface1 = pygame.Surface((size_x, size_y))
        helpsurface1.set_colorkey((0, 0, 0))
        pygame.draw.rect(helpsurface1, BLACK, (0, 0, size_x, size_y), 7)
        screen.blit(helpsurface1, (help_x, help_y))

        y = help_y + 10
        for i in range(len(text)):
            screen.blit(text[i], (help_x + 10, y))
            y += text[i].get_height()

        pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
            if exitbutton.check(event):
                help_active = False

#Класс отвечающий за кнопки
class Button:
    def __init__(self, surface, x, y, width, height, buttontext, buttontype = 0):
        """
        :param surface: Поверхность для отрисовки кнопки
        :param x: Координата x левого верхнего угла кнопки
        :param y: Координата y левого верхнего угла кнопки
        :param width: Ширина кнопки
        :param height: Высота кнопки
        :param buttontext: Текст на кнопке
        """
        self.surface = surface
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.buttontype = buttontype

        #Рисуем поверхность с черной кнопкой
        self.buttonsurf = pygame.Surface((self.width, self.height))
        self.buttonsurf.set_colorkey((0, 0, 0))
        pygame.draw.rect(self.buttonsurf, BLACK, (0, 0, self.width, self.height), 7)
        text = font.render(buttontext, True, (10, 10, 10))
        self.buttonsurf.blit(text, ((self.width - text.get_width())/2, (self.height - text.get_height())/2))

        #Рисуем поверхность с серой кнопкой, нужна для создания ээфекта обьема и анимации нажатия
        self.buttonshadow = pygame.Surface((self.width, self.height))
        self.buttonshadow.set_colorkey((0, 0, 0))
        pygame.draw.rect(self.buttonshadow, GREY, (0, 0, self.width, self.height), 7)
        text = font.render(buttontext, False, (150, 150, 150))
        self.buttonshadow.blit(text, ((self.width - text.get_width()) / 2, (self.height - text.get_height()) / 2))

        self.pressed = False
        self.nexttick = False

    def draw(self):
        # Рисуем кнопку по разному в зависимости от того нажата ли она
        if self.pressed and self.nexttick:
            self.pressed = False
            self.nexttick = False

        if not self.pressed:
            self.surface.blit(self.buttonshadow, (self.x + 3, self.y + 3))
            self.surface.blit(self.buttonsurf, (self.x, self.y))
        else:
            self.surface.blit(self.buttonshadow, (self.x + 3, self.y + 3))
            self.surface.blit(self.buttonsurf, (self.x + 2, self.y + 2))

    def check(self, event):
        #Проверка на нажатие кнопки
        if self.buttontype == 0:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if self.x < event.pos[0] < self.x + self.width:
                    if self.y < event.pos[1] < self.y + self.height:
                        self.pressed = True
                        return True
            if event.type == pygame.MOUSEBUTTONUP and self.pressed == True:
                self.nexttick = True
            return False
        if self.buttontype == 1:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if self.x < event.pos[0] < self.x + self.width:
                    if self.y < event.pos[1] < self.y + self.height:
                        self.pressed = True
            if event.type == pygame.MOUSEBUTTONUP and self.pressed == True:
                self.nexttick = True
                return True
            return False

#Класс для эффектов выхлопных газов от танка (создает летающие шарики серого цвета)
class Particle:
    def __init__(self, x, y, alpha, r, screen):
        """
        :param x: Координата x центра кружка
        :param y: Координата y центра кружка
        :param alpha: Начальная прозрачность кружка
        :param r: Начальный радиус кружука
        :param screen: Поверхность для отрисовки
        """
        self.x = x
        self.y = y
        self.r = r
        self.vy = 0
        self.vx = random.randint(-3, 3)
        self.velocity = 1
        self.alpha = alpha
        self.screen = screen
    def update(self):
        #Обновляем позицию на экране, скорость, прозрачность шарика
        self.vy += self.velocity
        self.y -= self.vy
        self.x += self.vx
        self.r += 2
        self.alpha -= 2
        self.partsurface = pygame.Surface((self.r*2, self.r*2))
        pygame.draw.circle(self.partsurface, GREY, (self.r, self.r), self.r)
        self.partsurface.set_colorkey((0,0,0))
        self.partsurface.set_alpha(self.alpha)
        self.screen.blit(self.partsurface, (self.x - self.r, self.y - self.r))

class Ball:
    def __init__(self, _screen, x=40, y=450):
        """
        :param _screen: Поверхность для отрисовки
        :param x: Начальная координата x
        :param y: Начальная координата y
        """
        self.screen = _screen
        self.x = x
        self.y = y
        self.r = 10
        self.vx = 0
        self.vy = 0
        self.color = random.choice(GAME_COLORS)
        self.live = 30
        self.alpha = 255

        self.max_c = 6
        self.c = 0

        self.parent = None

    def update(self):
        """Переместить мяч по прошествии единицы времени. И обработать столкновение со стенками.

        Метод описывает перемещение мяча за один кадр перерисовки. То есть, обновляет значения
        self.x и self.y с учетом скоростей self.vx и self.vy, силы гравитации, действующей на мяч,
        и стен по краям окна (размер окна 800х600).
        """
        self.x += self.vx
        self.y -= self.vy

        if self.x > WIDTH - self.r and self.vx > 0:
            self.vx *= -0.6
            self.vy *= 0.8
            self.x = WIDTH - self.r
            self.c += 1
        if self.y > HEIGHT - self.r and self.vy < 0:
            self.vy *= -0.6
            self.vx *= 0.8
            self.y = HEIGHT - self.r
            self.c += 1
        if self.x < self.r and self.vx < 0:
            self.vx *= -0.6
            self.vy *= 0.8
            self.x = self.r
            self.c += 1
        if self.c > self.max_c:
            if self.alpha > 0:
                self.alpha -= 4
            else:
                self.alpha = 0
        self.vy -= 1

    def draw(self):
        # Отрисовать шарик с учетом его прозрачности(После нескольких столкновений шарик плавно становится прозрачным и исчезает)
        self.surface1 = pygame.Surface((self.r*2, self.r*2))
        self.surface1.set_alpha(self.alpha)
        pygame.draw.circle(self.surface1, self.color, (self.r, self.r), self.r)
        self.surface1.set_colorkey((0, 0, 0))
        screen.blit(self.surface1, (self.x - self.r, self.y - self.r))

    def hittest(self, obj):
        """Функция проверяет сталкивалкивается ли данный обьект с целью, описываемой в обьекте obj.
        Args:
            obj: Обьект, с которым проверяется столкновение.
        Returns:
            Возвращает True в случае столкновения мяча и цели. В противном случае возвращает False.
            Если проверяем столкновение двух обьектов класса Ball, то меняем им скорости после столкновения.
        """
        dist = (self.x - obj.x) ** 2 + (self.y - obj.y) ** 2 - (self.r + obj.r) ** 2
        if dist > 0:
            return False
        else:
            if type(obj) == Ball:
                p1 = complex(self.x, self.y)
                p2 = complex(obj.x, obj.y)
                v1 = complex(self.vx, self.vy)
                v2 = complex(obj.vx, obj.vy)
                p12 = p1 - p2
                d = ((v1 - v2) / p12).real * p12
                self.vx = (v1 - d).real
                self.vy = (v1 - d).imag
                obj.vx = (v2 + d).real
                obj.vy = (v2 + d).imag
            else:
                self.alpha = 0
            return True

#Класс отвечающий за пушку и ее перемещение
class Gun:
    def __init__(self, screen, controltype = 1):
        self.screen = screen
        self.f2_power = 10
        self.f2_on = 0
        self.an = 1
        self.color = GREY

        self.timer = 0

        self.x = 100
        self.y = 540

        self.mousex = 100
        self.mousey = 100

        self.vx = 0
        self.maxspeed = 3
        self.velocity = 0

        self.moving_right = False
        self.moving_left = False

        self.reloadtime = self.defreloadtime = 90
        self.bulletsleft = self.defbulletsleft = 8

        self.fuel = 3000
        self.fuellinecolor = GREEN

        self.controltype = controltype
        self.anup = False
        self.andown = False

        self.k_move_forward = pygame.K_d
        self.k_move_backward = pygame.K_a
        self.k_targeting_up = pygame.K_w
        self.k_targeting_down = pygame.K_s
        self.k_fire = pygame.K_e
        self.k_reload = pygame.K_r
        self.changebullettype = pygame.K_q

        self.statx = 50
        self.staty = 50

        self.name = "Tank"
        self.color = TANKGREEN

        self.score = 0

        self.reloading = False

        self.bullettype = 0

    def setgunstats(self, k_move_forward, k_move_backward, k_targeting_up, k_targeting_down, k_fire, changebullettype, k_reload, statx, staty):
        self.k_move_forward = k_move_forward
        self.k_move_backward = k_move_backward
        self.k_targeting_up = k_targeting_up
        self.k_targeting_down = k_targeting_down
        self.k_fire = k_fire
        self.changebullettype = changebullettype
        self.k_reload = k_reload
        self.statx = statx
        self.staty = staty

    def fire2_start(self):
        #Начать увеличивать мощность пушки (зажать ЛКМ)
        if self.bulletsleft > 0:
            self.f2_on = 1

    def fire2_end(self, bullettype):
        """Выстрел мячом.

        Происходит при отпускании кнопки мыши.
        Начальные значения компонент скорости мяча vx и vy зависят от положения мыши.
        """
        global balls, bullet
        if self.bulletsleft > 0 and bullettype == 0:
            bullet += 1
            new_ball = Ball(self.screen, self.x + self.f2_power * math.cos(self.an), self.y + self.f2_power * math.sin(-self.an))
            new_ball.r += 5
            new_ball.vx = self.f2_power * math.cos(self.an)
            new_ball.vy = - self.f2_power * math.sin(-self.an)
            new_ball.parent = self
            balls.append(new_ball)
            self.f2_on = 0
            self.f2_power = 10
            self.bulletsleft -= 1
        if self.bulletsleft > 0 and bullettype == 1:
            bullet += 3
            for i in range(3):
                new_ball = Ball(self.screen, self.x + math.cos(self.an + (i-1)*0.3) * 30, self.y + math.sin(-self.an - (i-1)*0.3) * 30)
                new_ball.vx = self.f2_power * math.cos(self.an + (i-1)*0.3) / 1.3
                new_ball.vy = - self.f2_power * math.sin(-self.an - (i-1)*0.3) / 1.3
                new_ball.parent = self
                balls.append(new_ball)
            self.f2_on = 0
            self.f2_power = 10
            self.bulletsleft -= 1

    def targetting(self, event):
        """Прицеливание. Зависит от положения мыши."""
        if self.controltype == 0:
            if event.type == pygame.MOUSEMOTION:
                self.mousex = event.pos[0]
                self.mousey = event.pos[1]
            self.an = - math.atan2((self.mousey-self.y), (self.mousex-self.x))
            if self.f2_on:
                self.color = RED
            else:
                self.color = GREY

        if self.controltype == 1:
            if event.type == pygame.KEYDOWN:
                if event.key == self.k_targeting_up:
                    self.anup = True
                if event.key == self.k_targeting_down:
                    self.andown = True
            if event.type == pygame.KEYUP:
                if event.key == self.k_targeting_up:
                    self.anup = False
                if event.key == self.k_targeting_down:
                    self.andown = False

    def drawstats(self):
        text = font.render(self.name, True, (0, 0, 0))
        self.screen.blit(text, (self.statx, self.staty - 20))

        if self.reloading:
            text = font.render("Reloading: ", True, (0, 0, 0))
            self.screen.blit(text, (self.statx, self.staty + 60))
            pygame.draw.line(self.screen, RED, (self.statx + text.get_width(), self.staty + text.get_height()/2 + 60), (self.statx + text.get_width() + self.reloadtime, self.staty + text.get_height()/2 + 60), 10)

        text = font.render("Bullets left: " + str(round(self.bulletsleft)), True, (0, 0, 0))
        self.screen.blit(text, (self.statx, self.staty + 40))

        text = font.render("Fuel left: ", True, (0, 0, 0))
        self.screen.blit(text, (self.statx, self.staty + 20))
        if self.fuel > 0:
            pygame.draw.line(self.screen, self.fuellinecolor, (self.statx + text.get_width(), text.get_height() / 2 + self.staty + 20),
                            (self.statx + text.get_width() + self.fuel / 33.3, text.get_height() / 2 + self.staty + 20), 10)

        text = font.render("Score: " + str(round(self.score)), True, (0, 0, 0))
        self.screen.blit(text, (self.statx, self.staty))

    def update(self):
        """
        Обработка всех остальных событий связанных с танком
        Отрисовка пушки с заданным углом и размером.
        Перезарядка пушки и отрисовка количества оставшихся патронов и таймера перезарядки.
        Создание эффектов выхлопных газов.
        Обновление и отрисовка количества оставшегося топлива.
        Перемещение танка на экране
        """
        self.timer = (self.timer + 1)%1000

        if self.controltype == 1:
            if self.anup:
                self.an += 0.03
            if self.andown:
                self.an -= 0.03

        if 0 > self.an:
            self.an = 0
        if math.pi < self.an:
            self.an = math.pi

        self.sin = math.sin(self.an)
        self.cos = math.cos(self.an)
        self.gunxcoord = self.x + (30 + self.f2_power)*self.cos
        self.gunycoord = self.y - (30 + self.f2_power)*self.sin
        pygame.draw.polygon(self.screen, BLACK, ((self.x - 5*self.sin, self.y-5*self.cos), (self.x + 5*self.sin, self.y + 5*self.cos),
                                                 (self.gunxcoord + 5*self.sin, self.gunycoord + 5*self.cos),
                                                 (self.gunxcoord - 5*self.sin, self.gunycoord - 5*self.cos)))

        draw_tank(self.screen, self.x - 75, self.y - 85, 0.5, self.color)

        if self.reloading:
            self.reloadtime -= 1
        if self.reloadtime == 0:
            self.reloading = False
            self.reloadtime = self.defreloadtime
            self.bulletsleft = self.defbulletsleft

        self.drawstats()

        if self.fuel > 0:
            if self.moving_left:
                self.vx = -self.maxspeed

            if self.moving_right:
                self.vx = self.maxspeed

            if (self.moving_left or self.moving_right) and self.timer % 2 == 0:
                new_particle = Particle(self.x - 60, self.y + 8, 40, 4, self.screen)
                particles.append(new_particle)
                self.fuel -= 5

            elif self.timer % 5 == 0:
                new_particle = Particle(self.x - 60, self.y + 8, 40, 2, self.screen)
                particles.append(new_particle)
                self.fuel -= 2

            self.x += self.vx
            if abs(self.vx) > 1:
                self.fuellinecolor = RED
                self.vx -= 0.5 * self.vx / abs(self.vx)
            else:
                self.fuellinecolor = GREEN
                self.vx = 0
        else:
            self.fuel = 0

        self.power_up()

    def move(self, event):
        """
        Управление танком с клавиатуры, перемещение вправо, влево, перезарядка
        """
        if event.type == pygame.KEYDOWN:
            if event.key == self.k_move_backward:
                self.moving_left = True
            if event.key == self.k_move_forward:
                self.moving_right = True
            if event.key == self.k_reload and self.bulletsleft != self.defbulletsleft:
                self.bulletsleft = 0
                self.reloading = True
            if event.key == self.changebullettype:
                self.bullettype = (self.bullettype + 1)%2
        if event.type == pygame.KEYUP:
            if event.key == self.k_move_backward:
                self.moving_left = False
            if event.key == self.k_move_forward:
                self.moving_right = False

        if self.controltype == 1:
            if event.type == pygame.KEYDOWN:
                if event.key == self.k_fire:
                    self.fire2_start()
            if event.type == pygame.KEYUP:
                if event.key == self.k_fire:
                    self.fire2_end(self.bullettype)

        if self.controltype == 0:
            if event.type == pygame.MOUSEBUTTONDOWN:
                self.fire2_start()
            if event.type == pygame.MOUSEBUTTONUP:
                self.fire2_end()

    def power_up(self):
        # Увеличение мощности пушки при зажатой ЛКМ.
        if self.f2_power < 50 and self.f2_on:
            self.f2_power += 1

# Класс для мишеней
class Target:
    def __init__(self, _screen, _movingtype = 0):
        """
        :param _screen: Поверхность для отрисовки
        :param _movingtype: Тип движения мишени, 0  если не движется, 1 если движется вправо влево, 2 вверх вниз
        """
        self.screen = _screen
        self.movingtype = _movingtype

        self.live = True
        self.defcooldown = self.cooldown = 90

        x = self.x = random.randint(200,HEIGHT - 50)
        y = self.y = random.randint(200, WIDTH - 200)
        r = self.r = random.randint(10, 30)
        color = self.color = RED
        self.reward = 60 - self.r

        if self.movingtype == 1:
            self.startpoint = self.x
            self.endpoint = self.x + random.randint(-200, -50)
            self.speed = random.randint(1, 4)

        if self.movingtype == 2:
            self.startpoint = self.y
            self.endpoint = self.y + random.randint(-200, -50)
            self.speed = random.randint(1, 4)

        if self.movingtype == 3:
            self.vx = 0
            self.vy = 0

    def new_target(self):
        """ Инициализация новой цели. """
        x = self.x = random.randint(200, HEIGHT - 50)
        y = self.y = random.randint(200, WIDTH - 200)
        r = self.r = random.randint(10, 30)
        color = self.color = RED
        self.reward = 60 - self.r

        if self.movingtype == 1:
            self.startpoint = self.x
            self.endpoint = self.x + random.randint(-200, -50)
            self.speed = random.randint(1, 4)

        if self.movingtype == 2:
            self.startpoint = self.y
            self.endpoint = self.y + random.randint(-200, -50)
            self.speed = random.randint(1, 4)

    def hit(self):
        """Попадание шарика в цель. Возвращает количество очков при попадании"""
        if self.live:
            self.new_target()
            self.live = False
            return self.reward
        else:
            return 0

    def draw(self):
        # Отрисовка мишени
        pygame.draw.circle(self.screen, self.color, (self.x, self.y), self.r)

    def update(self):
        # Обновленеие мишени (таймер до возродения и движение мишени)
        if not self.live:
            if self.cooldown > 0:
                self.cooldown -= 1
            else:
                self.cooldown = self.defcooldown
                self.live = True
        else:
            self.draw()
        if self.movingtype == 1:
            self.x += self.speed
            if self.x < self.endpoint or self.x > self.startpoint:
                self.speed *= -1

        if self.movingtype == 2:
            self.y += self.speed
            if self.y < self.endpoint or self.y > self.startpoint:
                self.speed *= -1

        if self.movingtype == 3:
            self.x += self.vx
            self.y -= self.vy

            if self.x > WIDTH - self.r and self.vx > 0:
                self.vx *= -0.8
                self.vy *= 0.8
                self.x = WIDTH - self.r
            if self.y > HEIGHT - self.r and self.vy < 0:
                self.vy *= -0.8
                self.vx *= 0.8
                self.y = HEIGHT - self.r
            if self.x < self.r and self.vx < 0:
                self.vx *= -0.8
                self.vy *= 0.8
                self.x = self.r
            self.vy -= 1

    def collisioncheck(self, obj):
        if self.movingtype == 3:
            dist = (self.x - obj.x) ** 2 + (self.y - obj.y) ** 2 - (self.r + obj.r) ** 2
            if dist < 0:
                if obj.movingtype == 0:
                    objvx = 0
                    objvy = 0
                if obj.movingtype == 1:
                    objvx = obj.speed
                    objvy = 0
                if obj.movingtype == 2:
                    objvx = 0
                    objvy = obj.speed
                if obj.movingtype == 3:
                    objvx = obj.vx
                    objvy = obj.vy
                p1 = complex(self.x, self.y)
                p2 = complex(obj.x, obj.y)
                v1 = complex(self.vx, self.vy)
                v2 = complex(objvx, objvy)
                p12 = p1 - p2
                d = ((v1 - v2) / p12).real * p12
                self.vx = (v1 - d).real
                self.vy = (v1 - d).imag
                if obj.movingtype == 3:
                    obj.vx = (v2 + d).real
                    obj.vy = (v2 + d).imag

class TargetSpawner:
    def __init__(self, _screen):
        self.x = 0
        self.y = 150
        self.vx = 5
        self.screen = _screen
        self.cooldown = self.defcooldown = 60

    def draw(self):
        pygame.draw.ellipse(self.screen, GREY, (self.x - 50, self.y - 20, 100, 40))

    def update(self):
        self.x += self.vx
        self.draw()
        if self.cooldown < 0 and len(targets) < 10:
            self.cooldown = self.defcooldown
            new_target = Target(self.screen, 3)
            new_target.x = self.x
            new_target.y = self.y
            new_target.vx = self.vx
            targets.append(new_target)
        if len(targets) < 10:
            self.cooldown -= 1
        if self.x > WIDTH - 50 and self.vx > 0:
            self.vx *= -1
        if self.x < 50 and self.vx < 0:
            self.vx *= -1

resetbutton = Button(screen, 690, 10, 100, 50, 'reset', 1)
helpbutton = Button(screen, 690, 70, 100, 50, 'help', 1)

# Сброс игры до начального положения
def new_game():
    global bullet
    global balls
    global particles
    global clock
    global gun
    global targets
    global targetspawner
    bullet = 0
    balls = []
    particles = []
    clock = pygame.time.Clock()
    gun = [Gun(screen, 1) for i in range(2)]
    targets = [Target(screen, i % 3) for i in range(6)]
    targetspawner = TargetSpawner(screen)

    gun[0].name = "Player 1"

    gun[1].setgunstats(pygame.K_RIGHT, pygame.K_LEFT, pygame.K_UP, pygame.K_DOWN, pygame.K_RSHIFT, pygame.K_RETURN, pygame.K_RCTRL, 300, 50)
    gun[1].name = "Player 2"
    gun[1].x = 600
    gun[1].an = math.pi - 1
    gun[1].color = (120, 120, 30)

new_game()
finished = False
while not finished:
    clock.tick(FPS)
    pygame.draw.rect(screen, WHITE, (0, 0, WIDTH, HEIGHT))
    for g in gun:
        g.update()

    resetbutton.draw()
    helpbutton.draw()
    targetspawner.update()

    for p in particles:
        p.update()
        if p.alpha < 0:
            particles.remove(p)
    for t in targets:
        t.update()
        #for t2 in targets:
        #   if t != t2:
        #      t.collisioncheck(t2)
        if t.movingtype == 3 and not t.live:
            targets.remove(t)
    for b in balls:
        b.update()
        for t in targets:
            if t.live:
                if b.hittest(t):
                    b.parent.score += t.hit()
        for b2 in balls:
            if b2 != b:
                b.hittest(b2)
        if b.alpha == 0:
            balls.remove(b)
        b.draw()

    pygame.display.update()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            finished = True
        elif resetbutton.check(event):
            new_game()
        elif helpbutton.check(event):
            help()
        elif not resetbutton.pressed:
            for g in gun:
                g.targetting(event)
                g.move(event)

pygame.quit()


from typing import List

# 1
# 2 1
# 1 3 3
# 1 3 4 5
# 1 1 1 7 6
# dp[i] 到第i层最短路径之和
# dp[i] = dp[i-1] + min(triangle[i],triangle[i+1])
# class Solution:
#     def minimumTotal(self, triangle: List[List[int]]) -> int:
#         n = len(triangle)
#         dp = [0]*n
#         dp[0] = triangle[0][0]
#         j = 0
#         for i in range(1,n):
#             if triangle[i][j] > triangle[i][j+1]:
#                 j += 1
#             dp[i] = dp[i - 1] + triangle[i][j]
#         print(dp)
#         return dp[-1]

# dp[i][j] = min(dp[i-1][j],dp[i-1][j+1]) + triangle[i][j]

class Solution:
    def minimumTotal(self, triangle: List[List[int]]) -> int:
        n = len(triangle)
        dp = [[0]*x for x in range(1,n+1)]
        dp[0][0] = triangle[0][0]
        for i in range(1,n):
            for j in range(i+1):
                if j == 0:
                    dp[i][j] = dp[i-1][j] + triangle[i][j]
                elif j == i:
                    dp[i][j] = dp[i-1][j-1] + triangle[i][j]
                else:
                    dp[i][j] = min(dp[i - 1][j-1], dp[i - 1][j]) + triangle[i][j]
        #print(dp)
        return min(dp[-1])

if __name__ == '__main__':
    triangle = [[1],[2,1],[1,3,3],[1,3,4,5],[1,1,1,7,6]]
    print(Solution().minimumTotal(triangle))

120. 三角形最小路径和.py


import random
import json
import datetime

secret = random.randint(1, 10)

intentos = 0
nombre = str(input("Escriba su nombre: "))
print("Bienvenid@ " + nombre)
with open("score2.txt", "r") as score:
    score_lista = json.loads(score.read())
    print("La lista es " + str(score_lista))

while True:

    guess = int(input("Guess the secret number (between 1 and 30): "))
    intentos = intentos + 1
    wrong_guesses = intentos -1

    if guess == secret:

        score_lista.append({"Nombre": nombre, "Numero Secreto": secret, "Numero de intentos": intentos,  "Intentos falldios":  wrong_guesses, "Fecha": str(datetime.datetime.now())})
        with open("score2.txt", "w") as score_file:
            score_file.write(json.dumps(score_lista))

            print("You've guessed it - congratulations! It's number " + str(secret))

            print ("Number of attempts: " + str(intentos))

            break

    elif guess > secret:

        print("Your guess is not correct... try something smaller")

    elif guess < secret:

        print("Your guess is not correct... try something bigger")


"""
Contains unit tests for relative topologies
"""
import unittest
from fom.interfaces import Topology
from fom.topologies import RelativeTopology, CustomTopology
from hypothesis import given, assume
from test.unit.generators import topologies

class TestRelativeTopology(unittest.TestCase):
    """
    Base class for testing relative topologies
    """
    def setUp(self):
        self.elements = frozenset({'item 1', 'item 2'})
        self.open_sets = frozenset({frozenset(), self.elements})
        self.custom_topology = CustomTopology(self.elements, self.open_sets)

class TestConstructor(TestRelativeTopology):
    """
    Tests the constructor
    """
    @given(topologies())
    def test_valid_subset(self, topology: Topology):
        """
        Tests that an isolated topology containing just the first element of
        a larger topology is a valid relative topology

        :param topology: The topology for which a relative topology is to be
            constructed
        :return:
        """
        assume(len(list(topology.elements)) >= 2)
        first_element = next(iter(topology.elements))
        subset = frozenset({first_element})

        relative_topology = RelativeTopology(subset, topology)
        self.assertIn(first_element, relative_topology.elements)

    def test_invalid_subset(self) -> None:
        """
        Tests that attempting to make an invalid relative topology throws an
        error
        """
        with self.assertRaises(ValueError):
            RelativeTopology(frozenset({'item 3'}), self.custom_topology)


from typing import Sequence, Union

import torch
from torch import Tensor

from ..neko_module import NekoModule
from ..util import F

class Aggregation(NekoModule):
    """
    The torch module for aggregation.

    Args:
        mode (``str``, optional): The mode of aggregation. Default "mean".
        dim (``int`` | ``Sequence[int]``, optional): The dimension chosen to apply aggregate function. Default None.

    Examples::

        x = torch.rand(1, 16, 32, 32)
        global_avg_pooling = Aggregation("avg", dim=(1, 2, 3))
        x_pooled = max_pooling(x)

    """
    def __init__(self, mode: str = "mean", dim: Union[int, Sequence[int]] = None):
        super().__init__()
        if mode == "mean":
            self.agg_func = F(torch.mean, dim=dim)
        elif mode == "sum":
            self.agg_func = F(torch.sum, dim=dim)
        elif mode == "max":
            self.agg_func = F(torch.max, dim=dim)
        elif mode == "min":
            self.agg_func = F(torch.min, dim=dim)
        else:
            raise ValueError("Wrong mode value. It should be in [mean, sum, max, min]")

    def forward(self, x: Tensor) -> Tensor:
        return self.agg_func(x)


# 1. Revise the racquetball simulation so that it computes the results for best
# of n game matches. First service alternates, so player A serves first in the
# odd games of the match, and player B serves first in the even games.

# rball2.py

# my implementation is a bit different because I didn't understood the ask

from random import *

def main():
    printlntro()
    probA, probB, n = getlnputs()
    winsA, winsB = simNGames(n, probA, probB)
    printSummary(winsA, winsB)

def printlntro():
    print("This program simulates a game of racquetball between two")
    print('players called "A" and "B". The ability of each player is')
    print("indicated by a probability (a number between 0 and 1) that")
    print("the player wins the point when serving. Player A always")
    print("has the first serve.")

def getlnputs():
    # Returns the three simulation parameters
    a = float(input("What is the prob. player A wins a serve? "))
    b = float(input("What is the prob. player B wins a serve? "))
    n = int(input("How many games to simulate? "))
    return a, b, n

def simNGames(n, probA, probB):
    # Simulates n games of racquetball between players whose
    # abilities are represented by the probability of winning a serve.
    # Returns number of wins for A and B
    winsA = winsB = 0
    for i in range(n):
        scoreA, scoreB = simOneGame(probA, probB)
        if scoreA > scoreB:
            winsA = winsA + 1
        else:
            winsB = winsB + 1
    return winsA, winsB

def simOneGame(probA, probB):
    # Simulates a single game or racquetball between players whose
    # abilities are represented by the probability of winning a serve.
    # Returns final scores for A and B
    serving = servings()
    scoreA = 0
    scoreB = 0
    while not gameOver(scoreA, scoreB):
        if serving == "A":
            if random() < probA:
                scoreA = scoreA + 1
            else:
                serving = "B"
        else:
            if random() < probB:
                scoreB = scoreB + 1
            else:
                serving = "A"
    return scoreA, scoreB

def gameOver(a, b):
    # a and b represent scores for a racquetball game
    # Returns True if the game is over, False otherwise.
    return a == 15 or b == 15

def servings():
    # this function generates a random number in the range from 1 to 10 inclusively. If the number is even serves player B,
    # otherwise serves player A
    order = randrange(1, 11)
    if (order % 2 != 0):
        serving = 'A'
    else:
        serving = 'B'
    return serving

def printSummary(winsA, winsB):
    # Prints a summary of wins for each player.
    n = winsA + winsB
    print("\nGames simulated: ", n)
    print("Wins for A: {0} ({1: 0.1%})".format(winsA, winsA / n))
    print("Wins for B: {0} ({1: 0.1%})".format(winsB, winsB / n))

if __name__ == '__main__':
    main()


from rest_framework import serializers
from .models import Movie

class MovieSerializer(serializers.ModelSerializer):

    title = serializers.CharField(max_length=128, min_length=8, required=True)
    description = serializers.CharField(max_length=500, min_length=8, required=True)

    class Meta:

        model = Movie
        fields = '__all__'

    def create(self, validated_data):
        movie = Movie.objects.create(
            title=validated_data['title'],
            description=validated_data['description'],
            coverImage=validated_data['coverImage'],
            genre=validated_data['genre']
        )
        movie.save()

        return movie


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    # Solution 1: O(n) space, O(nlogn) time
    def sortList1(self, head: Optional[ListNode]) -> Optional[ListNode]:
        # loop though the linked list to get all the values,
        # sort the values and reconstruct a linked list
        if not head:
            return None
        vals = []
        while head:
            vals.append(head.val)
            head = head.next
        vals.sort()  # O(nlogn)
        head = ListNode(vals[0])
        tail = head
        for i in range(1, len(vals)):
            tail.next = ListNode(vals[i])
            tail = tail.next
        return head

    # Solution 2: O(n) space, O(nlogn) time
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if not head or not head.next:
            return head

        # count number of nodes
        size, cur = 0, head
        while cur:
            cur = cur.next
            size += 1

        # split the linked list
        size = size // 2
        prev, cur = None, head
        while size:
            prev = cur
            cur = cur.next
            size -= 1
        prev.next = None

        # sort sublists
        n1, n2 = self.sortList(head), self.sortList(cur)

        # merge two sublists
        dummy_head = ListNode()
        cur = dummy_head
        while n1 and n2:
            if n1.val < n2.val:
                cur.next = n1
                n1 = n1.next
            else:
                cur.next = n2
                n2 = n2.next
            cur = cur.next
        cur.next = n1 or n2

        return new_head.next


#!/usr/bin/python
#coding: utf-8
#-----------------------------
# 宝塔Linux面板内测插件
#-----------------------------
import sys,os
reload(sys)
sys.setdefaultencoding('utf-8')
os.chdir('/www/server/panel');
sys.path.append("class/")
import public,db,time

class beta_main:
    __setupPath = '/www/server/panel/plugin/beta';
    #设置内测
    def SetConfig(self,get):
        data = {}
        data['username'] = get.bbs_name
        data['qq'] = get.qq
        data['email'] = get.email
        result = public.httpPost('https://www.bt.cn/Api/LinuxBeta',data);
        import json;
        data = json.loads(result);
        if data['status']:
            public.writeFile(self.__setupPath + '/config.conf',get.bbs_name + '|' + get.qq + '|' + get.email);
        return data;
    #取内测资格状态
    def GetConfig(self,get):
        try:
            cfile = self.__setupPath + '/config.conf'
            if not os.path.exists(cfile): cfile = 'data/beta.pl'
            return public.readFile(cfile).strip();
        except:
            return 'False';


# a = [30,40,50,60,70]                        #每一個元素必須視同一個資料型別

# a.append(90)                                #append在串列後方加入資料
# a.append(100)

# a.insert(4,8)                               #insert在指定位置加入資料

# a.remove(30)                                #刪除指定數值的資料,相同資料只會刪除一筆

# del a[1]                                    #del刪除指定位置的資料

# for i in range(len(a)):                     #逐一顯示串列數字
#     print(a[i])

# b = list("2358")                              #list()輸入字串會逐一分割,如列子會為"2","3","5","8"
# c = list(input("please your number: "))       #猜數字遊戲
# A=0
# B=0
# for i in range(len(b)):
#     for j in range(len(c)) :
#         if j == i and b[i] == c[j]:
#             A+=1
#             break
#         elif b[i] == c[j] :
#             B+=1
#             break
# print(A,"A",B,"b")

# b = int(input("year:"))                          #十二生肖
# y = b % 12-4
# a = ["rat","ox","tiger","rabbit","dragon","snake","horse","sheep","moneky","rooster","dog","pig"]
# print(a[y])

# a = [6,8,3,4,2,9,1,7]
# a.sort()                                           #順序排列資料
# for i in range(len(a)):
#     print(a[i])

# a = [6,8,3,4,2,9,1,7]                                #泡沫排序法(Bubble sort)
# i=0
# for j in range(len(a)-2):
#     for i in range(len(a)-1):
#         if a[i]>a[i+1]:
#             b = a[i]
#             a[i] = a[i+1]
#             a[i+1] = b

# print(a)

a=list(input("輸入4個數字:"))
z=a
for j in range(len(a)-2):
    for i in range(len(a)-1):
        if a[i]>a[i+1]:
            b = a[i]
            a[i] = a[i+1]
            a[i+1] = b
d=""
for c in range(len(a)):
    d = str(d) + str(a[c])
print(d)
for x in range(len(z)-1):
    for y in range(len(z)-1):
        if z[y]<z[y+1]:
            b = z[y]
            z[y] = z[y+1]
            z[y+1] = b

f=""
for e in range(len(z)):
    f = str(f) + str(z[e])
print(f)
print(int(d)-int(f))


for _ in range(int(input())):
	arr=list(map(int,input().split()))
	f,flag=0,-1
	for i in range(4):
		if(arr[i]%2!=0):
			f+=1

	if(f==0 or f==1):
		print('YES')
	elif(f==2):
		print('NO')
	else:
		if 0 in arr[:3]:
			print('NO')
		else:
			print('YES')


row1 = [' ', ' ', ' ']
row2 = [' ', ' ', ' ']
row3 = [' ', ' ', ' ']
treasure_map = [row1, row2, row3]

print(f"{row1}\n{row2}\n{row3}")
choice = input("Where do you want to put the treasure? (separate by a ','): ")
location = choice.split(',')
vertical = int(location[0]) - 1
horizontal = int(location[1]) - 1

treasure_map[horizontal][vertical] = 'X'
print(f"{row1}\n{row2}\n{row3}")


# -*- coding: utf-8 -*-
"""
Document classifier using Linear Support Vector Machine Classifier
preprocessed with TD-IDF vectorizer
Created on Mon Mar 22 20:26:18 2021

@author: jgharris
"""
# Preprocessing parameters
minLength=5             #Mininmun number of words for running classifer
MAXFEATURES=2000
mindf=1
maxdf=1.0
mindf=1
alphasmooth=1
ngramrange=(1,3)
MAXSTRINGLENGH=7060
FIRSTSTRINGLENGTH=80
CREG=1.

# SVC options
PENALTY='l2'
LOSS='squared_hinge'
DUAL=False
DEBUG=1

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import cross_val_score
#from sklearn.model_selection import train_test_split

from sklearn.svm import LinearSVC
#from sklearn.metrics import accuracy_score
from sklearn.metrics import confusion_matrix
import unittest
import pickle
import time

#import matplotlib
#import matplotlib.pyplot as plt
#import numpy as np

# path is './' for final build, but may be '../' for testing in IDE

unit_temp_file_path='./'
unit_model_name='linSVCv0'
start_time=time.time()
class DocClfTLinSVC():
    def __init__(self,maxStringLength=MAXSTRINGLENGH, \
                 firstStringLength=FIRSTSTRINGLENGTH,
                 penalty=PENALTY,loss=LOSS,dual=DUAL,
                 creg=CREG,
                 maxFeatures=MAXFEATURES
                 ):
        self.maxStringLength=maxStringLength
        self.firstStringLength=firstStringLength
        self.loss=loss
        self.penalty=penalty
        self.creg=creg
        self.dual=dual
        self.maxFeatures=maxFeatures
        self.message="LinearSVC using TF-IDF with "+"%5d" % maxFeatures + " features " + \
        " ngram-range "+"%2d" % ngramrange[0]+" to "+"%2d" % ngramrange[1] + \
        " maxString Length "+ "%6d" % self.maxStringLength +"Creg="+"%4.2f" % self.creg

        return

# Truncate string. Not implemented--possibility of combining counts from
#  begining of document with counts from most of document
# Documents must be truncated due to apparent length limit to GET URL

    def preprocess(self,x):
        xprocessed=[]
        xbegin=[]
        for item in x:
            xprocessed.append(item[0:self.maxStringLength])
            xbegin.append(item[0:self.firstStringLength])
        return xprocessed,xbegin
    def fit(self,x,y):
            # generate dictionary of words and numb of word occurences
            # in each document
        xprocessed,xbegin=self.preprocess(x)
        self.vectorizer=\
        TfidfVectorizer(max_df=maxdf,min_df=mindf,max_features=self.maxFeatures,
                               ngram_range=ngramrange)
        xv=self.vectorizer.fit_transform(xprocessed)
        self.nbclf=LinearSVC(penalty=self.penalty,loss=self.loss,dual=self.dual,
                C=self.creg)
        self.nbclf.fit(xv,y)
        ytrain=self.nbclf.predict(xv)
        return ytrain

    #predict for a group of x value

    def predict(self,x):
        if (len(x[0])<minLength):
            y=["No input"]
            return y
        try:
            xprocessed,xbegin=self.preprocess(x)
            xv=self.vectorizer.transform(xprocessed)
            y=self.nbclf.predict(xv)
        except:
            raise
        return y
    def crossVal(self,cvec,xtrain,ytrain):
        scorelist=[]
        global start_time
        for item in cvec:
           modelt=make_pipeline(
            TfidfVectorizer(max_df=maxdf,min_df=mindf,max_features=self.maxFeatures,
                               ngram_range=ngramrange),
            LinearSVC(penalty=self.penalty,loss=self.loss,dual=self.dual,
                C=item)
            )
           if(DEBUG>=1):
               print(modelt.named_steps)
           scores=cross_val_score(modelt,xtrain,ytrain)
           print("time=%7.1f " % (time.time()-start_time),end="")
           print("%5.2f " % item, end=' ')
           [print("%10.5f " % xval,end='') for xval in scores]
           print("")
           scorelist.append(scores)
        return scorelist

    # Compute confidence given predicted values & return confusion matrix

    def confidence(self,ytest,ytestpred):
        conf_mat = confusion_matrix(ytest, ytestpred)
    # compute accuracy given predicted value
        labels = sorted(set(ytest))
        self.confidence=dict(zip(labels, conf_mat.diagonal()/
                                 (.1+conf_mat.sum(axis=0))))
        return conf_mat
    #
    # get the Confidence score for a single item:
    # "x" is stuck in here, but not used because it may be possible
    # to improve the Confidence estimate by metrics like
    # distance from separating boundary or a relative score
    #
    def getConfidence(self,x,y):
        try:
            return self.confidence[y]
        except:
            return -1.0;

# Note that directory at top may need to be changed depending on
# whether this is run from the ./app or home directory
#  This tries to catch that error

class TestDocLinSVC(unittest.TestCase):
    def setUp(self):
       modelFile=unit_temp_file_path+unit_model_name+".pckmdl"
       try:
          with open(modelFile,"rb") as myFile:
             self.myModel=pickle.load(myFile)
          testF=open(unit_temp_file_path+unit_model_name+"testdata.txt","rt")
       except:
           with open('../'+modelFile,"rb") as myFile:
             self.myModel=pickle.load(myFile)
           testF=open('../'+unit_temp_file_path+unit_model_name+"testdata.txt","rt")

       self.cases=[]

       for line in testF:
           y,x=line.strip().split(',')
           self.cases.append((x,y))
       testF.close()
    def testpredict(self):
        print("")
        for case in self.cases:
            result=self.myModel.predict([case[0]])
            print((result,case[1]))
            self.assertEqual(result,case[1])

if __name__=='__main__':
    unittest.main()


from portfolio import get_most_profitable_stock as gmps, calculate_portfolio_return as cpr, \
    calkulate_portfolio_value as cpv

stoks = {
    "aple": 10,
    "google": 5,
    "MSFT": 8
}
prices = {
    "aple": 155.25,
    "google": 260.75,
    "MSFT": 800.50
}
if __name__ == '__main__':
    print(cpv(stoks, prices))
    print(cpr(100, 150))
    print(gmps(stoks, prices))


"""
344. Reverse String

"""

class Solution:
    def reverseString(self, s) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        for i in range(len(s)//2):
            s[i],s[-i-1]=s[-i-1],s[i]
        return s

s=Solution()
print(s.reverseString(["h","e","l","l","o"]))


import unittest
import sys
import collections
sys.path.insert(0, '../pyengine')
sys.path.insert(1, 'pyengine')
import dfix as dfix
import pathfinder as pf
import json

testroutes_map = {}

def test_parse_routes():
    # we will have one json file which will contain all routes for these tests.
    # this function is required to split them into individual jsons which we will store in a python dict
    test_file = open('tests/resources/routing_tests.json')
    routes = test_file.read()
    routesparse = json.loads(routes)

    for route in routesparse['testroutes']:
        testroutes_map[route['routeid']] = json.dumps(route,indent=2)

    print(testroutes_map)

    test_file.close()

class pathfindertest(unittest.TestCase):
    def setUp(self):
        test_parse_routes()
        pass

    def test_single_destination(self):
        test_route = testroutes_map['single_destination_test']
        destination = pf.pathfinder(test_route)
        self.assertEqual(destination,'maspeth:exch1')

    def test_single_destination_unavailable(self):
        test_route = testroutes_map['single_destination_test_unavailable']
        destination = pf.pathfinder(test_route)
        self.assertFalse(destination)

    def test_bad_routetype(self):
        test_route = testroutes_map['bad_routetype_test']
        destination = pf.pathfinder(test_route)
        self.assertFalse(destination)

    def test_priority_dest1(self):
        test_route = testroutes_map['priority_test_dest1']
        destination = pf.pathfinder(test_route)
        self.assertEqual(destination,'maspeth:exch1')

    def test_priority_dest3(self):
        test_route = testroutes_map['priority_test_dest3']
        destination = pf.pathfinder(test_route)
        self.assertEqual(destination,'bushwick:exch1')

if __name__ == '__main__':
    unittest.main()


import subprocess
import json

class CodeTester:
	def __init__(self):
		pass

	def submitTestCode(self, before_code, test_code, submited_code):
		assert len(test_code) % 2 == 0, "Wrong test code"
		testResults = []

		for k in range(int(len(test_code) / 2)):
			# imports - submited code - custom tests
			print(before_code + "\n\n")
			testResults.append(self.runSubprocess(before_code + "\n\n" + submited_code + "\n\n" + test_code[2 * k], test_code[2 * k + 1]))

		return json.dumps(testResults)

	# Run a single python test
	def runSubprocess(self, full_code, expected_output):
		proc = subprocess.Popen(["python", "-c", full_code,], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

		std = proc.communicate()
		stdout_value = std[0]
		stderr_value = std[1]

		stdout_value = stdout_value.replace("'", "");
		stderr_value = stderr_value.replace("'", "");
		stdout_value = stdout_value.replace('"', '');
		stderr_value = stderr_value.replace('"', '');
		stdout_value = stdout_value.replace("\n", "\\n");
		stderr_value = stderr_value.replace("\n", "\\n");

		is_success = (stderr_value == '')

		if is_success:
			# Test the output
			is_success = (stdout_value == str(expected_output)+'\\n')

			if not is_success:
				stderr_value = "The program returned " + stdout_value + "it should have been " + str(expected_output)

		return {"is_success" : is_success, "stdout" : stdout_value, "stderr" : stderr_value}


'''User input = “aaaabbbbbcccd”
Dictionary = {“a”:4,”b”:5,”c”:3,”d”:1}
You could store the dictionary in file like this:
a,4 b,5 c,3 d,1
So that when you read it back in to create the dictionary, you can use the letters as keys and the numbers as values again.'''

userInput = input("Please give me a string ")
userDict = {}
for i in userInput:
    if i in userDict:
        userDict[i]+=1
    else:
        userDict[i]=1
print(userDict)

def dict2file(dict, myfile):
    xFile = open(myfile, "w")
    for i,j in dict.items():
        print(i,",",j,sep="",file=xFile)
    xFile.close()

dict2file(userDict,"hello.txt")

def file2dict(myfile):
    xFile = open(myfile,"r")
    dict={}
    for i in xFile:
        line=i.split(",")
        key=line[0]
        value=int(line[1])
        dict[key]=value
    xFile.close()
    print(dict)

file2dict("hello.txt")


import telebot
from loguru import logger
from pprint import pprint
import math

@logger.catch
def create_inline_keyboard(deals: list, pageCountCallback: int=1 ):
    """_summary_

    Args:
        deals (list): сделки
        pageCountCallback (int, optional): Defaults to 1. Какую страницу мы хотим потулчить

    Returns:
        _types.InlineKeyboardMark_p(): inline клавиатура
    """
    # Создаем объект клавиатуры и списка кнопок
    keyboard = telebot.types.InlineKeyboardMarkup()
    buttons = []
    # Переменная для отслеживания количества кнопок
    buttonCount = 0
    # Переменная для отслеживания числа страниц
    pageCount = 1
    # Проходим по всем элементам deals для создания кнопок
    keyboardDict={}
    for deal in deals:
        # Создаем кнопку и добавляем ее в список кнопок
        button = telebot.types.InlineKeyboardButton(text=deal['ID'], callback_data=f"btnDeal_{deal['ID']}")
        buttons.append(button)
        # Увеличиваем счетчик кнопок
        buttonCount += 1
        # Если мы дошли до конца строки 3 (т.е. у нас уже 3 кнопки в строке), то добавляем эту
        # строку в объект клавиатуры и обнуляем список кнопок
        if buttonCount % 3 == 0:
            keyboard.row(*buttons)
            buttons = []
        # Проверяем, достигли ли мы 20 кнопок (т.е. достигли лимита количества кнопок на одной странице)
        # Если да, то добавляем кнопку для перехода на следующую страницу и сбрасываем счетчик кнопок
        if buttonCount == 20:
            keyboard.row(*buttons)

            if pageCount == 1:
                next_button = telebot.types.InlineKeyboardButton(text=">>", callback_data=f"next_page_{pageCount}")
                keyboard.row(next_button)
            elif pageCount >= math.ceil((len(deals)/20)): #last
                prevButton = telebot.types.InlineKeyboardButton(text="<<", callback_data=f"prev_page_{pageCount}")
                keyboard.row(prevButton)
                #keyboardDict.setdefault(pageCount, keyboard)
                # pprint(keyboardDict)
                #return keyboardDict[pageCountCallback]
            else:
                prevButton = telebot.types.InlineKeyboardButton(text="<<", callback_data=f"prev_page_{pageCount}")
                nextButton = telebot.types.InlineKeyboardButton(text=">>", callback_data=f"next_page_{pageCount}")
                keyboard.row(prevButton, nextButton)

            buttonCount = 0
            buttons = []
            keyboardDict.setdefault(pageCount, keyboard)
            keyboard = telebot.types.InlineKeyboardMarkup()
            pageCount += 1
            print(f'{pageCount}')

    # Добавляем остаток списка кнопок в объект клавиатуры
    if buttonCount !=0:
        print('Добавляем остаток списка кнопок в объект клавиатуры')
        keyboard.row(*buttons)
        prevButton = telebot.types.InlineKeyboardButton(text="<<", callback_data=f"prev_page_{pageCount}")
        keyboard.row(prevButton)
        keyboardDict.setdefault(pageCount, keyboard)

    # Если страниц больше, чем 1 (т.е. мы создали более 20 кнопок), то добавляем кнопки навигации
    # if pageCount > 1:
    #     prevButton = telebot.types.InlineKeyboardButton(text="<<", callback_data=f"prev_page_{pageCount}")
    #     nextButton = telebot.types.InlineKeyboardButton(text=">>", callback_data=f"next_page_{pageCount}")
    #     keyboard.row(prevButton, nextButton)
    pprint(keyboardDict)
    return keyboardDict[pageCountCallback]

def create_menu_keyboard():
    keyboard = telebot.types.ReplyKeyboardMarkup(True)
    keyboard.row('Соседи шумят')
    keyboard.row('Мои занятия')

    return keyboard


import psycopg2
from config import config

class DataAccess():

    @classmethod
    def connexion(cls):

     #""" Connect to the PostgreSQL database server """
        conn = None

        try:
            # read connection parameters
            params = config()

            # connect to the PostgreSQL server
            print('Connecting to the PostgreSQL database...')
            conn = psycopg2.connect(**params)

        except (Exception, psycopg2.DatabaseError) as error:
            print(error)

        return conn

    @classmethod
    def close_connexion(cls):

        cls.conn = cls.connexion()
        if cls.conn is not None:
            cls.conn.close()
            print('Database connection closed.')

    @classmethod
    def get_facilities(cls):
        cls.cur = cls.connexion().cursor()
        cls.cur.execute('SELECT * FROM cd.facilities')
        data = cls.cur.fetchall()
        #data = cls.cur.fetchone()
        print(data)
        cls.close_connexion()
        return (data)

DataAccess.get_facilities()


import uuid
from .cache import local, init_local
from django.conf import settings

class RequestCacheMiddleware(object):
    """使用线程 ID 缓存 request 实例"""
    def process_request(self, request):
        # 生成 request_id
        request.id = uuid.uuid4().hex
        local.request_id = request.id

        # 获取真实ip
        x_forwarded_for = request.META.GET('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get("REMOTE_ADDR", '')
        local.ip = ip
        # 获取 token 优先级：GET param > http header > http Cookie
        token = request.GET.get('token',
                                request.META.GET('HTTP_ACCESS_TOKEN',
                                                 request.COOKIES.get('cds_token','')))
        local.token = token

        # 获取 代理商标志
        is_agent = int(request.COOKIES.get('is_agent', 0))
        local.is_agent = is_agent

        # 获取语言
        language = request.COOKIES.get("django_language")
        if language != 'en':
            language = 'zh-hans'
        request.LANGUAGE_CODE = language
        local.language = language

    def process_response(self, request, response):
        token = local.token
        if token:
            response.set_cookie(settings.TOKEN_NAME, token)
        init_local()
        return response


import matplotlib.pyplot as plt
import numpy as np

import torch
import torchvision
#from torch import nn
import torch.nn as nn
from torch import optim
import torch.nn.functional as F
from torchvision import datasets, transforms, models

from os import listdir
from os.path import isfile, join

mypathTrain=r"C:\data\DataNumTr"
trainlabel = [f for f in listdir(mypathTrain) if isfile(join(mypathTrain, f))]

#transforma = transforms.Compose(
 #   [transforms.ToTensor(),
  #   transforms.Normalize((0.1307), (0.3081))]) #transform (mean) (std)
transforma = transforms.ToTensor()

train_dataset=datasets.MNIST(root=mypathTrain,train= True,download=False,transform=transforma)
test_dataset=datasets.MNIST(root=mypathTrain,train=False,download=False,transform=transforma)

train_loader=torch.utils.data.DataLoader(train_dataset,batch_size=64, shuffle= True)
test_loader=torch.utils.data.DataLoader(test_dataset,batch_size=64, shuffle= True)

print((test_dataset.classes))

##### load and show some images for fun #####
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

# get some random training images
dattaiter = iter(test_loader)
images, labels = dattaiter.next() #******

# show images
imshow(torchvision.utils.make_grid(images))
# print labels
print(' '.join('%5s' % train_dataset.classes[labels[j]] for j in range(64)))  #range(batch_size)
####End test loading images ### note the number of image showed = batch size ###########

print(torch.tensor(images.shape))
BigT=images
BigTen=BigT.reshape(64,28*28)
print(BigTen.shape)

class classifierv1 (nn.Module):
    def __init__(self):
        super().__init__()
        #hidden NN
        self.hidden1= nn.Linear(28*28,128) #
        self.hidden2= nn.Linear(128,64)
        #output layer
        self.output= nn.Linear(64,10)#

    def forward(self,x):
        # flatten image
        x = x.view(-1, 28 * 28)
        x = F.relu(self.hidden1(x))
        x = F.relu(self.hidden2(x))
        x = F.softmax(self.output(x),dim=1)
        return x

classifierv2= nn.Sequential(nn.Linear(28*28,128),
                            nn.ReLU(),
                            nn.Linear(128,64),
                            nn.ReLU(),
                            nn.Linear(64,10),
                            nn.LogSoftmax())
#####################################"
#net = classifierv1()#if you use this remove line 69 or remove resahping of input tensor each time
net = classifierv2 #same as v1 just cleaner code

####### loss fucntion and optimizer ###
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.01, momentum=0.9)

for epoch in range(15):  # loop over the dataset multiple times #2 -> 14% accuracy; 10->64%; 25->100%

    running_loss = 0.0
    for i, data in enumerate(train_loader, 0):
        # get the inputs
        inputs, labels = data
        #print(torch.Tensor.size(inputs))
        inputss=inputs.reshape(-1,28*28)
        #print(torch.Tensor.size(inputss))
        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputss)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

print('Finished Training')

##########accuracy for the whole dataset ##########
correct = 0
total = 0
with torch.no_grad():
    for data in test_loader:
        images, labels = data
        imagess = images.reshape(-1, 28 * 28)
        outputs = net(imagess)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print('Accuracy of the network on the 10000 test images: %d %%' % (
    100 * correct / total))

############ performance evaluation of every class #########
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in test_loader:
        images, labels = data
        imagess = images.reshape(-1, 28 * 28)
        outputs = net(imagess)
        _, predicted = torch.max(outputs, 1)
        c = (predicted == labels).squeeze()
        for i in range(4):
            label = labels[i]
            class_correct[label] += c[i].item()
            class_total[label] += 1

for i in range(10):
    print('Accuracy of %5s : %2d %%' % (
        train_dataset.classes[i], 100 * class_correct[i] / class_total[i]))


# Import libraries
from time import sleep
from labs.module02 import TempSensorEmulator

# Initialize the object of TempSensorEmulator.
sysPerfAdaptor = TempSensorEmulator.module02()

sysPerfAdaptor.daemon = True
print("Starting system performance app daemon thread...")

# Call the start method as to call the run method in TemSensorEmulator thread class.
sysPerfAdaptor.start()
while (True):
    sleep(10)


seq="TAGTGTGCTGTGTGCGCTGACGACATCTAGCTATCGTGATGCTGATGCTGATCGATGCGATCGTAGTCGATCGATCGTAGCTTAGTCGTGCTGATCGATGCTGATGCTGACTGCTAGCTACGTAGCTGCGACTGATCGTACGTAGCTACGTCTGTAGTGCA"

#ATGC
seq=seq.replace("A","a")	#aTGC
seq=seq.replace("T","A")	#aAGC
seq=seq.replace("a","T")	#TAGC
seq=seq.replace("C","c")	#TAGc
seq=seq.replace("G","C")	#TACc
seq=seq.replace("c","G")	#TACG

print(seq)

Seq_comp="ATGCGATACGATGACTACGATGCTGAGTTAAGCCGTAGTTGACAGTCGTAGCTGATCTTGACTGATCGTAGCTCCAATTGATGTACCACACA"

#ATGC

Seq_comp=Seq_comp.replace("A","a")	#aTGC
Seq_comp=Seq_comp.replace("T","A")	#aAGC
Seq_comp=Seq_comp.replace("a","T")	#TAGC
Seq_comp=Seq_comp.replace("C","c")	#TAGc
Seq_comp=Seq_comp.replace("G","C")	#TACc
Seq_comp=Seq_comp.replace("c","G")	#TACG

print(Seq_comp)


import os

import discord
import json
import urllib.request as request
from random  import randint
from discord.ext import commands
from dotenv import load_dotenv

load_dotenv()
TOKEN = os.getenv('DISCORD_TOKEN')
MERRIAM_TOKEN = os.getenv('MERRIAM_DICTIONARY_API')
MERRIAM_THESAURUS_TOKEN = os.getenv('MERRIAM_THESAURUS_API')
OPEN_WEATHER_TOKEN = os.getenv('OPEN_WEATHER_API')

bot = commands.Bot(command_prefix='!')

#!def command: used to find the first 4 definitions of a word
@bot.command(name='def', help='Defines a single word given as input. Ex: !define {input}')
async def definitionOf(ctx, word):
    jsonDef = await grab_json_definition(word, "collegiate", MERRIAM_TOKEN)
    for i in jsonDef[0]:
        if(i == 'shortdef'):
            for j in jsonDef[0][i]:
                await ctx.send(j)

#!syn command: used to find the first 4 synonyms of a word
@bot.command(name='syn', help='Gives synonyms for a single word. Ex: !syn {input}')
async def synonymOf(ctx, word):
	limiter = 0
	jsonSyn = await grab_json_definition(word,"thesaurus", MERRIAM_THESAURUS_TOKEN)
	for i in jsonSyn[0]['meta']['syns'][0]:
		await ctx.send(i)
		limiter = limiter + 1
		if (limiter == 4):
			break

#!roll command: given the number (inclusive), it will return a random number from 1 to {input}
@bot.command(name='roll', help='Rolls a dice, given the number of sides that you input. Ex: !roll {# of sides}')
async def diceRoller(ctx,side):
	try:
		if (side == '1'):
			await ctx.send(side)
		elif (int(side)  <= 0):
			await ctx.send('Sorry, no can do jimbo!')
		else:
			value = str(randint(1,int(side)+1))
			await ctx.send(value)
	except ValueError:
		await ctx.send('Sorry, you\'ve entered invalid inputs')

#!weather command: Used to grab the weather (in progress)
@bot.command(name='weather', help='Grabs CURRENT weather info with a zip code')
async def weatherInfo(ctx, zip):
	jsonWeather = await grab_json_weather(zip, OPEN_WEATHER_TOKEN)
	await ctx.send('The current weather for ' + zip + ' looks like ' + jsonWeather['weather'][0]['description'] + '\nThe temperature is ' + str(jsonWeather['main']['temp']) + ' degrees but will feel like ' + str(jsonWeather['main']['feels_like']) + '\n The max today will be ' + str(jsonWeather['main']['temp_max']))

#-------------------------------------------------------------------Helper functions--------------------------------------------------------------

#Used to grab json data from open weather API
async def grab_json_weather(zip, key):
	uri = "https://api.openweathermap.org/data/2.5/weather?zip=" + zip + "&appid=" + key +"&units=imperial"
	jsonURL = request.urlopen(uri)
	source = jsonURL.read()
	jsonData = json.loads(source)
	return jsonData

#used to grab json data from Mirriam webster API
async def grab_json_definition(word, ref, key):
	uri = "https://dictionaryapi.com/api/v3/references/" + ref + "/json/" + word + "?key=" + key
	jsonURL = request.urlopen(uri)
	source = jsonURL.read()
	jsonData = json.loads(source)
	return jsonData

bot.run(TOKEN)


#! python3
import numpy as np

def read_indexes(file_name):
    indexes = []
    # read without new line
    for line_text in open(file_name, 'r').read().splitlines():
        indexes.append(line_text.split(',')[-1])
    return indexes

def extract_ids(line_txt):
    ids = []
    numbers = line_txt.split('\t')
    for i in range(100):
        ids.append(int(numbers[2 * i + 1]))
    return ids

def read_nn(file_name):
    nn = None
    for line_txt in open(file_name):
        if nn is None:
            nn = []
        else:
            nn.append(extract_ids(line_txt))
    return nn

def submission_map(nn, query_indexes, train_indexes):
    nn_map = {}
    train_indexes = np.array(train_indexes)

    for i, top_k in enumerate(nn):
        nn_map[query_indexes[i]] = ' '.join(train_indexes[top_k])

    return nn_map

def replace_submission(sample_sub_file, nn_array, submission_file, query_indexes, train_indexes):
    submission = open(submission_file, 'w')
    sample_sub = open(sample_sub_file)
    sub_map = submission_map(nn_array, query_indexes, train_indexes)
    for line_txt in sample_sub:
        line_array = line_txt.split(',')
        if line_array[0] in sub_map:
            submission.write('%s,%s\n' % (line_array[0], sub_map[line_array[0]]))
        else:
            submission.write(line_txt)

    submission.close()
    sample_sub.close()

if __name__ == '__main__':
    sample_submission = './data/sample_submission.csv'

    features_name = 'landmark_cnn'
    submission_file = './data/sub.csv'

    import sys
    if len(sys.argv) > 2:
        features_name = sys.argv[1]
        submission_file = sys.argv[2]
    else:
        print('\033[93m', 'use default features_name submission_file metric')
        print('\033[93m', 'usage: python3 submit.py <features_name> <submission_file> [euclidean/product/angular]')

    query_indexes_file = './data/%s/%s_query_index.txt' % (features_name, features_name)
    train_indexes_file = './data/%s/%s_base_index.txt' % (features_name, features_name)

    metric = 'euclidean'
    if len(sys.argv) > 3 :
        metric = sys.argv[3]

    nn_result = './data/%s/%s_%s_groundtruth.lshbox' % (features_name, features_name, metric)

    replace_submission(
        sample_submission,
        read_nn(nn_result),
        submission_file,
        read_indexes(query_indexes_file),
        read_indexes(train_indexes_file))


#Developed by Zachary Williams

from tkinter import *
from functools import partial
from PIL import Image
import sys
from sys import platform

class mainclass(object):
    colorfillvar = 0
    gridwidth = 8
    gridheight = 8
    griddim = gridwidth * gridheight
    colors = []
    basecolor = "red"
    picname = []
    if platform == "linux" or platform == "linux2":
        buttonw = 2
        buttonh = 2
        toolbarw = 370
        toolbarh= 10
    elif platform == "darwin":
        buttonw = 2
        buttonh = 2
    elif platform == "win32" or "win64":
        buttonw = 2
        buttonh = 1
        toolbarw = 260
        toolbarh = 10
    COLORS = ['snow', 'ghost white', 'white smoke', 'gainsboro', 'floral white', 'old lace', 'linen', 'antique white',
              'papaya whip', 'blanched almond', 'bisque', 'peach puff', 'navajo white', 'lemon chiffon', 'mint cream',
              'azure', 'alice blue', 'lavender', 'lavender blush', 'misty rose', 'dark slate gray', 'dim gray',
              'slate gray', 'light slate gray', 'gray', 'light grey', 'midnight blue', 'navy', 'cornflower blue',
              'dark slate blue', 'slate blue', 'medium slate blue', 'light slate blue', 'medium blue', 'royal blue',
              'blue', 'dodger blue', 'deep sky blue', 'sky blue', 'light sky blue', 'steel blue', 'light steel blue',
              'light blue', 'powder blue', 'pale turquoise', 'dark turquoise', 'medium turquoise', 'turquoise', 'cyan',
              'light cyan', 'cadet blue', 'medium aquamarine', 'aquamarine', 'dark green', 'dark olive green',
              'dark sea green', 'sea green', 'medium sea green', 'light sea green', 'pale green', 'spring green',
              'lawn green', 'medium spring green', 'green yellow', 'lime green', 'yellow green', 'forest green',
              'olive drab', 'dark khaki', 'khaki', 'pale goldenrod', 'light goldenrod yellow', 'light yellow', 'yellow',
              'gold', 'light goldenrod', 'goldenrod', 'dark goldenrod', 'rosy brown', 'indian red', 'saddle brown',
              'sandy brown', 'dark salmon', 'salmon', 'light salmon', 'orange', 'dark orange', 'coral', 'light coral',
              'tomato', 'orange red', 'red', 'hot pink', 'deep pink', 'pink', 'light pink', 'pale violet red', 'maroon',
              'medium violet red', 'violet red', 'medium orchid', 'dark orchid', 'dark violet', 'blue violet', 'purple',
              'medium purple', 'thistle', 'snow2', 'snow3', 'snow4', 'seashell2', 'seashell3', 'seashell4',
              'AntiqueWhite1', 'AntiqueWhite2', 'AntiqueWhite3', 'AntiqueWhite4', 'bisque2', 'bisque3', 'bisque4',
              'PeachPuff2', 'PeachPuff3', 'PeachPuff4', 'NavajoWhite2', 'NavajoWhite3', 'NavajoWhite4', 'LemonChiffon2',
              'LemonChiffon3', 'LemonChiffon4', 'cornsilk2', 'cornsilk3', 'cornsilk4', 'ivory2', 'ivory3', 'ivory4',
              'honeydew2', 'honeydew3', 'honeydew4', 'LavenderBlush2', 'LavenderBlush3', 'LavenderBlush4', 'MistyRose2',
              'MistyRose3', 'MistyRose4', 'azure2', 'azure3', 'azure4', 'SlateBlue1', 'SlateBlue2', 'SlateBlue3',
              'SlateBlue4', 'RoyalBlue1', 'RoyalBlue2', 'RoyalBlue3', 'RoyalBlue4', 'blue2', 'blue4', 'DodgerBlue2',
              'DodgerBlue3', 'DodgerBlue4', 'SteelBlue1', 'SteelBlue2', 'SteelBlue3', 'SteelBlue4', 'DeepSkyBlue2',
              'DeepSkyBlue3', 'DeepSkyBlue4', 'SkyBlue1', 'SkyBlue2', 'SkyBlue3', 'SkyBlue4', 'LightSkyBlue1',
              'LightSkyBlue2', 'LightSkyBlue3', 'LightSkyBlue4', 'SlateGray1', 'SlateGray2', 'SlateGray3', 'SlateGray4',
              'LightSteelBlue1', 'LightSteelBlue2', 'LightSteelBlue3', 'LightSteelBlue4', 'LightBlue1', 'LightBlue2',
              'LightBlue3', 'LightBlue4', 'LightCyan2', 'LightCyan3', 'LightCyan4', 'PaleTurquoise1', 'PaleTurquoise2',
              'PaleTurquoise3', 'PaleTurquoise4', 'CadetBlue1', 'CadetBlue2', 'CadetBlue3', 'CadetBlue4', 'turquoise1',
              'turquoise2', 'turquoise3', 'turquoise4', 'cyan2', 'cyan3', 'cyan4', 'DarkSlateGray1', 'DarkSlateGray2',
              'DarkSlateGray3', 'DarkSlateGray4', 'aquamarine2', 'aquamarine4', 'DarkSeaGreen1', 'DarkSeaGreen2',
              'DarkSeaGreen3', 'DarkSeaGreen4', 'SeaGreen1', 'SeaGreen2', 'SeaGreen3', 'PaleGreen1', 'PaleGreen2',
              'PaleGreen3', 'PaleGreen4', 'SpringGreen2', 'SpringGreen3', 'SpringGreen4', 'green2', 'green3', 'green4',
              'chartreuse2', 'chartreuse3', 'chartreuse4', 'OliveDrab1', 'OliveDrab2', 'OliveDrab4', 'DarkOliveGreen1',
              'DarkOliveGreen2', 'DarkOliveGreen3', 'DarkOliveGreen4', 'khaki1', 'khaki2', 'khaki3', 'khaki4',
              'LightGoldenrod1', 'LightGoldenrod2', 'LightGoldenrod3', 'LightGoldenrod4', 'LightYellow2',
              'LightYellow3', 'LightYellow4', 'yellow2', 'yellow3', 'yellow4', 'gold2', 'gold3', 'gold4', 'goldenrod1',
              'goldenrod2', 'goldenrod3', 'goldenrod4', 'DarkGoldenrod1', 'DarkGoldenrod2', 'DarkGoldenrod3',
              'DarkGoldenrod4', 'RosyBrown1', 'RosyBrown2', 'RosyBrown3', 'RosyBrown4', 'IndianRed1', 'IndianRed2',
              'IndianRed3', 'IndianRed4', 'sienna1', 'sienna2', 'sienna3', 'sienna4', 'burlywood1', 'burlywood2',
              'burlywood3', 'burlywood4', 'wheat1', 'wheat2', 'wheat3', 'wheat4', 'tan1', 'tan2', 'tan4', 'chocolate1',
              'chocolate2', 'chocolate3', 'firebrick1', 'firebrick2', 'firebrick3', 'firebrick4', 'brown1', 'brown2',
              'brown3', 'brown4', 'salmon1', 'salmon2', 'salmon3', 'salmon4', 'LightSalmon2', 'LightSalmon3',
              'LightSalmon4', 'orange2', 'orange3', 'orange4', 'DarkOrange1', 'DarkOrange2', 'DarkOrange3',
              'DarkOrange4', 'coral1', 'coral2', 'coral3', 'coral4', 'tomato2', 'tomato3', 'tomato4', 'OrangeRed2',
              'OrangeRed3', 'OrangeRed4', 'red2', 'red3', 'red4', 'DeepPink2', 'DeepPink3', 'DeepPink4', 'HotPink1',
              'HotPink2', 'HotPink3', 'HotPink4', 'pink1', 'pink2', 'pink3', 'pink4', 'LightPink1', 'LightPink2',
              'LightPink3', 'LightPink4', 'PaleVioletRed1', 'PaleVioletRed2', 'PaleVioletRed3', 'PaleVioletRed4',
              'maroon1', 'maroon2', 'maroon3', 'maroon4', 'VioletRed1', 'VioletRed2', 'VioletRed3', 'VioletRed4',
              'magenta2', 'magenta3', 'magenta4', 'orchid1', 'orchid2', 'orchid3', 'orchid4', 'plum1', 'plum2', 'plum3',
              'plum4', 'MediumOrchid1', 'MediumOrchid2', 'MediumOrchid3', 'MediumOrchid4', 'DarkOrchid1', 'DarkOrchid2',
              'DarkOrchid3', 'DarkOrchid4', 'purple1', 'purple2', 'purple3', 'purple4', 'MediumPurple1',
              'MediumPurple2', 'MediumPurple3', 'MediumPurple4', 'thistle1', 'thistle2', 'thistle3', 'thistle4',
              'gray1', 'gray2', 'gray3', 'gray4', 'gray5', 'gray6', 'gray7', 'gray8', 'gray9', 'gray10', 'gray11',
              'gray12', 'gray13', 'gray14', 'gray15', 'gray16', 'gray17', 'gray18', 'gray19', 'gray20', 'gray21',
              'gray22', 'gray23', 'gray24', 'gray25', 'gray26', 'gray27', 'gray28', 'gray29', 'gray30', 'gray31',
              'gray32', 'gray33', 'gray34', 'gray35', 'gray36', 'gray37', 'gray38', 'gray39', 'gray40', 'gray42',
              'gray43', 'gray44', 'gray45', 'gray46', 'gray47', 'gray48', 'gray49', 'gray50', 'gray51', 'gray52',
              'gray53', 'gray54', 'gray55', 'gray56', 'gray57', 'gray58', 'gray59', 'gray60', 'gray61', 'gray62',
              'gray63', 'gray64', 'gray65', 'gray66', 'gray67', 'gray68', 'gray69', 'gray70', 'gray71', 'gray72',
              'gray73', 'gray74', 'gray75', 'gray76', 'gray77', 'gray78', 'gray79', 'gray80', 'gray81', 'gray82',
              'gray83', 'gray84', 'gray85', 'gray86', 'gray87', 'gray88', 'gray89', 'gray90', 'gray91', 'gray92',
              'gray93', 'gray94', 'gray95', 'gray97', 'gray98', 'gray99']

    def __init__(self, master):

        self.fillbutton = "0"
        menu = Menu(master)
        master.config(menu=menu)
        bFrame = Frame(master)
        subMenu = Menu(menu, tearoff=0)
        menu.add_cascade(label="File", menu=subMenu)
        topPadding = Frame(master, width=self.toolbarw, height=self.toolbarh)
        subMenu.add_command(label="New File", command=partial(self.importpic, bFrame, topPadding))
        subMenu.add_command(label="Placeholder", command=self.doNothing)
        subMenu.add_separator()
        subMenu.add_command(label="Placeholder", command=self.doNothing)

        editMenu = Menu(menu, tearoff=0)
        menu.add_cascade(label="Edit", menu=editMenu)
        editMenu.add_command(label="Remove Row", command=partial(self.removeRow, bFrame, topPadding))
        editMenu.add_command(label="Remove Col", command=partial(self.removeCol, bFrame, topPadding))
        viewMenu = Menu(menu, tearoff=0)
        menu.add_cascade(label="View", menu=viewMenu)
        viewMenu.add_command(label="Color Chart", command=self.viewColorChart)

        toolbar = Frame(master, width=self.toolbarw, height=20, bg="grey")
        frameSep = Frame(master, width=self.toolbarw, height=3, bg="black")
        bottomPadding = Frame(master, width=self.toolbarw, height=40)
        self.setfillbutton = Checkbutton(bottomPadding, text="Fill")
        self.setfillbutton.config(state=DISABLED)
        self.setfillbutton.pack(side=LEFT)
        colorselect = Button(toolbar, text="Set Color", command=partial(self.colorfillask, bFrame, topPadding))
        colorselect.pack(side=LEFT)
        gridSelect = Button(toolbar, text="Grid Select", command=partial(self.changeGrid, bFrame, topPadding))
        gridSelect.pack(side=LEFT)
        View = Button(toolbar, text="View", command=partial(self.viewImage, 40))
        View.pack(side=LEFT)
        baseCol = Button(toolbar, text="Color Fill", command=partial(self.fillColor, bFrame, topPadding))
        baseCol.pack(side=LEFT)
        exportbut = Button(toolbar, text="Export", command=self.expFunc)
        exportbut.pack(side=LEFT)
        self.buttons = []

        for i in range(self.griddim):
            self.buttons.append(Button(bFrame, width=self.buttonw, height=self.buttonh, bg=self.basecolor,
                                       command=partial(self.buttonColor, i, bFrame, topPadding)))
            self.buttons[i].grid(row=int((i / self.gridwidth)), column=int((i % self.gridwidth)))
            self.colors.append(self.basecolor)
        toolbar.pack_propagate(0)
        toolbar.pack(side=TOP)
        frameSep.pack(side=TOP)
        topPadding.pack(side=TOP)
        bFrame.pack()
        bottomPadding.pack(side=BOTTOM)

    def doNothing(self):
        print("Nope")

    def buttonColor(self, position, frame, padding):

        if self.colorfillvar == 0:
            colorask = Frame(padding)
            label_1 = Label(colorask, text="What Color?")
            entry_1 = Entry(colorask)
            label_2 = Label(colorask, text="Input takes lower case standard color, \nor #xxxxxxxxx hexadecimal number ")
            buttonOK = Button(colorask, text="OK",
                              command=partial(self.getEntry, entry_1, position, frame, colorask, padding))
            label_1.grid(row=0, sticky=E)
            entry_1.grid(row=0, column=1)
            label_2.grid(row=1, columnspan=2)
            buttonOK.grid(row=2, columnspan=2)
            colorask.pack()
        else:
            self.buttons[position].grid_forget()
            try:
                temp = Button(frame, width=self.buttonw, height=self.buttonh, bg=self.fillbutton,
                              command=partial(self.buttonColor, position, frame, padding))
            except:
                self.buttons[position] = Button(frame, width=self.buttonw, height=self.buttonh, bg='red',
                                                command=partial(self.buttonColor, position, frame, padding))
                self.buttons[position].grid(row=int(position / self.gridwidth), column=int(position % self.gridwidth))
                self.colors[position] = "red"
                print("Color entered is not recognized by tkinter. Please format the color as either a recognized tkinter string or #RGB or #RRGGBB or #RRRGGGBBB or #RRRRGGGGBBBB")
                return
            self.buttons[position] = Button(frame, width=self.buttonw, height=self.buttonh, bg=self.fillbutton,
                                            command=partial(self.buttonColor, position, frame, padding))
            self.buttons[position].grid(row=int(position / self.gridwidth), column=int(position % self.gridwidth))
            self.colors[position] = self.fillbutton

    def getEntry(self, entry, position, frame, colorask, padding):
        self.colorentry = entry.get()
        padding.config(width=self.toolbarw, height=self.toolbarh)
        colorask.destroy()
        if self.colorfillvar == 0:
            self.buttons[position].grid_forget()
            try:
                temp = Button(frame, width=self.buttonw, height=self.buttonh, bg=self.colorentry,
                              command=partial(self.buttonColor, position, frame, padding))
            except:
                self.buttons[position] = Button(frame, width=self.buttonw, height=self.buttonh, bg='red',
                                                command=partial(self.buttonColor, position, frame, padding))
                self.buttons[position].grid(row=int(position / self.gridwidth), column=int(position % self.gridwidth))
                self.colors[position] = "red"
                print("Something went wrong")
                return
            self.buttons[position] = Button(frame, width=self.buttonw, height=self.buttonh, bg=self.colorentry,
                                            command=partial(self.buttonColor, position, frame, padding))
            self.buttons[position].grid(row=int(position / self.gridwidth), column=int(position % self.gridwidth))
            self.colors[position] = self.colorentry
        else:
            self.fillbutton = self.colorentry

    def getButtonColor(self, button):
        rgb = button.winfo_rgb(button.cget('bg'))
        r = (rgb[0] >> 11)
        g = (rgb[1] >> 10)
        g = g << 5
        b = rgb[2] >> 11
        b = b << 11
        rgb = b + g + r
        return '0x%04x' % (rgb)

    def colorfillask(self, frame, padding):

        colorask = Frame(padding)

        label_1 = Label(colorask, text="What Color?")
        entry_1 = Entry(colorask)
        label_2 = Label(colorask, text="Input takes lower case standard color, \nor #xxxxxxxxx hexadecimal number ")
        container = Frame(colorask)
        buttonOK = Button(container, text="OK", command=partial(self.getEntry, entry_1, 1, frame, colorask, padding))
        buttonSet = Button(container, text="Set", command=self.setfillvar)
        buttonClear = Button(container, text="Clear", command=self.clearfillvar)

        label_1.grid(row=0, sticky=E)
        entry_1.grid(row=0, column=1)
        label_2.grid(row=1, columnspan=2)
        buttonOK.grid(row=1, column=1)
        buttonSet.grid(row=1, column=2)
        buttonClear.grid(row=1, column=3)
        container.grid(row=2, columnspan=2)
        colorask.pack()

    def setfillvar(self):
        self.setfillbutton.select()
        self.colorfillvar = 1

    def clearfillvar(self):
        self.setfillbutton.deselect()
        self.colorfillvar = 0

    def changeGrid(self, frame, padding):
        gridask = Frame(padding)
        label_1 = Label(gridask, text="Grid Width:")
        entry_1 = Entry(gridask)
        label_2 = Label(gridask, text="Grid Height")
        entry_2 = Entry(gridask)
        buttonOK = Button(gridask, text="OK",
                          command=partial(self.getgridEntries, entry_1, entry_2, gridask, frame, padding))
        label_1.grid(row=0, sticky=E)
        entry_1.grid(row=0, column=1)
        label_2.grid(row=1, column=0)
        entry_2.grid(row=1, column=1)
        buttonOK.grid(row=2, columnspan=2)
        gridask.pack()

    def getgridEntries(self, entry1, entry2, kill, frame, padding):
        if entry1.get() == "":
            kill.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        if entry2 != 1:
            try:
                temp1 = int(entry1.get())
                temp2 = int(entry2.get())
            except:
                kill.destroy()
                padding.config(width=self.toolbarw, height=self.toolbarh)
                return
            if int(entry1.get()) >30 or int(entry2.get()) >30:
                kill.destroy()
                padding.config(width=self.toolbarw, height=self.toolbarh)
                return
            self.gridwidth = int(entry1.get())
            self.gridheight = int(entry2.get())
        else:
            if entry1.get() in self.COLORS:
                self.basecolor = entry1.get()
            else:
                kill.destroy()
                padding.config(width=self.toolbarw, height=self.toolbarh)
                return
        for i in range(self.griddim):
            self.buttons[i].grid_forget()
        self.griddim = self.gridwidth * self.gridheight
        self.colors = []
        self.buttons = []
        for i in range(self.griddim):
            self.buttons.append(Button(frame, width=self.buttonw, height=self.buttonh, bg=self.basecolor,
                                       command=partial(self.buttonColor, i, frame, padding)))
            self.buttons[i].grid(row=int((i / self.gridwidth)), column=int((i % self.gridwidth)))
            self.colors.append(self.basecolor)
        frame.pack()
        kill.destroy()
        padding.config(width=self.toolbarw, height=self.toolbarh)

    def viewImage(self, size):
        pixelI = Tk()
        canvas = Canvas(pixelI, width=self.gridwidth * size, height=self.gridheight * size)
        canvas.pack()
        for i in range(self.gridheight):
            for j in range(self.gridwidth):
                canvas.create_rectangle(j * size, i * size, j * size + size, i * size + size,
                                        fill=self.colors[i * self.gridwidth + j], width=0)

    def fillColor(self, frame, padding):
        fillAsk = Frame(padding)
        label_1 = Label(fillAsk, text="What Color?")
        entry_1 = Entry(fillAsk)
        label_2 = Label(fillAsk, text="Input takes lower case standard color, \nor #xxxxxxxxx hexadecimal number ")
        buttonOK = Button(fillAsk, text="OK", command=partial(self.getgridEntries, entry_1, 1, fillAsk, frame, padding))
        label_1.grid(row=0, sticky=E)
        entry_1.grid(row=0, column=1)
        label_2.grid(row=1, columnspan=2)
        buttonOK.grid(row=2, columnspan=2)
        fillAsk.pack()

    def expFunc(self):
        print('writing file')
        file = open("bitmap.txt", "w")
        file.write(
            "uint16_t bitmap[] = {" + ','.join([self.getButtonColor(button) for button in self.buttons]) + "};\n\n")
        file.write("int idx = 0;\nfor (int i=0; i< " + str(self.gridheight) + "; i++){\n" + "\tfor (int j=0; j< " + str(
            self.gridwidth) +
                   "; j++){\n\t\tST7735_DrawPixel(j,i,bitmap[idx]);\n\t\tidx++;\n\t}\n}")
        file.close()

    def importpic(self, frame, padding):
        resizeask = Frame(padding)
        label_1 = Label(resizeask, text="Picture Name:")
        entry_1 = Entry(resizeask)
        label_2 = Label(resizeask, text="Resize Width")
        entry_2 = Entry(resizeask)
        label_3 = Label(resizeask, text="Resize Height")
        entry_3 = Entry(resizeask)
        buttonOK = Button(resizeask, text="OK",
                          command=partial(self.resizeandplace, entry_1, entry_2, entry_3, resizeask, frame, padding))
        label_1.grid(row=0, sticky=E)
        entry_1.grid(row=0, column=1)
        label_2.grid(row=1, column=0)
        entry_2.grid(row=1, column=1)
        label_3.grid(row=2, column=0)
        entry_3.grid(row=2, column=1)
        buttonOK.grid(row=3, columnspan=2)
        resizeask.pack()

    def resizeandplace(self, entry1, entry2, entry3, kill, frame, padding):
        if entry1.get() == "" or entry2.get() == "" or entry3.get() == "":
            kill.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        self.picname = entry1.get()
        print(self.picname)
        try:
            im = Image.open(self.picname)
        except:
            kill.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        for i in range(self.griddim):
            self.buttons[i].grid_forget()
        temp1 = self.griddim
        temp2 = self.gridwidth
        temp3 = self.griddim
        self.gridwidth = int(entry2.get())
        self.gridheight = int(entry3.get())
        self.griddim = self.gridheight * self.gridwidth
        im = Image.open(self.picname)
        im = im.resize((self.gridwidth, self.gridheight), Image.NEAREST)
        pix = im.convert('RGB')
        self.colors = []
        self.buttons = []
        for i in range(self.griddim):
            r, g, b = pix.getpixel((int(i % self.gridwidth), int(i / self.gridwidth)))
            # print(int(i%self.gridheight), int(i/self.gridheight))
            # print(r,g,b)
            rgb = (r << 16) + (g << 8) + b
            rgb = "#%0.6x" % rgb
            # print(rgb)
            self.buttons.append(Button(frame, width=self.buttonw, height=self.buttonh, bg=rgb,
                                       command=partial(self.buttonColor, i, frame, padding)))
            if self.gridwidth < 55 or self.gridheight < 30:
                self.buttons[i].grid(row=int((i / self.gridwidth)), column=int((i % self.gridwidth)))
            self.colors.append(rgb)
        print("Check")
        if self.gridwidth > 55 or self.gridheight > 30:
            print("did it work?")
            self.expFunc()
            self.viewImage(4)
            self.griddim = temp1
            self.gridwidth = temp2
            self.gridheight = temp3
            buttons = []
            for i in range(self.griddim):
                self.buttons.append(Button(frame, width=self.buttonw, height=self.buttonh, bg=self.basecolor,
                                           command=partial(self.buttonColor, i, frame, padding)))
                self.buttons[i].grid(row=int((i / self.gridwidth)), column=int((i % self.gridwidth)))
                self.colors.append(self.basecolor)
            frame.pack()
        else:
            frame.pack()
        kill.destroy()
        im.save('resized_image.png')
        padding.config(width=self.toolbarw, height=self.toolbarh)

    def viewColorChart(self):
        MAX_ROWS = 36
        FONT_SIZE = 10  # (pixels)
        ColorChart = Tk()
        ColorChart.title("Named colour chart")
        row = 0
        col = 0
        for color in self.COLORS:
            e = Label(ColorChart, text=color, background=color,
                      font=(None, -FONT_SIZE))
            e.grid(row=row, column=col, sticky=E + W)
            row += 1
            if (row > 36):
                row = 0
                col += 1

    def removeRow(self, frame, padding):
        gridask = Frame(padding)
        label_1 = Label(gridask, text="Row: ")
        entry_1 = Entry(gridask)
        buttonOK = Button(gridask, text="OK",
                          command=partial(self.manMatRow, entry_1, gridask, frame, padding))
        label_1.grid(row=0, sticky=E)
        entry_1.grid(row=0, column=1)
        buttonOK.grid(row=1, columnspan=2)
        gridask.pack()

    def removeCol(self, frame, padding):
        gridask = Frame(padding)
        label_1 = Label(gridask, text="Column: ")
        entry_1 = Entry(gridask)
        buttonOK = Button(gridask, text="OK",
                          command=partial(self.manMatCol, entry_1, gridask, frame, padding))
        label_1.grid(row=0, sticky=E)
        entry_1.grid(row=0, column=1)
        buttonOK.grid(row=1, columnspan=2)
        gridask.pack()

    def manMatRow(self, entry_1, gridask, frame, padding):
        try:
            temp1 = int(entry_1.get())
        except:
            print("Value given failed integer conversion")
            gridask.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        if int(entry_1.get()) <=0 or int(entry_1.get()) >self.gridheight:
            print("Integer given is out of bounds")
            gridask.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        rowID = int(entry_1.get())-1
        for i in range(self.griddim):
            self.buttons[i].grid_forget()
        self.buttons = []
        for i in range(self.gridwidth):
            del self.colors[self.gridwidth*rowID]
            print(i)
        self.gridheight = self.gridheight - 1
        self.griddim = self.gridheight*self.gridwidth
        for i in range(self.griddim):
            self.buttons.append(Button(frame, width=self.buttonw, height=self.buttonh, bg=self.colors[i],
                                       command=partial(self.buttonColor, i, frame, padding)))
            self.buttons[i].grid(row=int((i / self.gridwidth)), column=int((i % self.gridwidth)))
        gridask.destroy()
        padding.config(width=self.toolbarw, height=self.toolbarh)
        frame.pack()

    def manMatCol(self, entry_1, gridask, frame, padding):
        try:
            temp1 = int(entry_1.get())
        except:
            print("Value given failed integer conversion")
            gridask.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        if int(entry_1.get()) <=0 or int(entry_1.get()) >self.gridwidth:
            print("Integer given is out of bounds")
            gridask.destroy()
            padding.config(width=self.toolbarw, height=self.toolbarh)
            return
        colID = int(entry_1.get())-1
        for i in range(self.griddim):
            self.buttons[i].grid_forget()
        self.buttons = []
        temp = []
        j=0
        for i in range(self.griddim):
            if (i%self.gridwidth == colID):
                continue
            else:
                temp.append(self.colors[i])
                j=j+1
        self.colors = temp
        self.gridwidth = self.gridwidth - 1
        self.griddim = self.gridheight*self.gridwidth
        for i in range(self.griddim):
            self.buttons.append(Button(frame, width=self.buttonw, height=self.buttonh, bg=self.colors[i],
                                       command=partial(self.buttonColor, i, frame, padding)))
            self.buttons[i].grid(row=int((i / self.gridwidth)), column=int((i % self.gridwidth)))
        gridask.destroy()
        padding.config(width=self.toolbarw, height=self.toolbarh)
        frame.pack()

root = Tk()
z = mainclass(root)
root.mainloop()
sys.exit()