import pygame
import random

from typing import Callable
from pygame import Vector2, Rect, Color, Surface

pygame.init()

class Signal:

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

    def connect(self, handler: callable) -> None:
        self.handlers.append(handler)

    def disconnect(self, handler: callable) -> None:
        self.handlers.remove(handler)

    def disconnect_all(self) -> None:
        self.handlers.clear()

    def emit(self, *args, **kwargs) -> None:
        for handler in self.handlers:
            handler(*args, **kwargs)

class Buff:

    def __init__(self):
        self.name = "Buff"
        self.desc = ""

    def __str__(self) -> str:
        return f"{self.name}({self.desc})"

    def use(self, player: "Player") -> None:
        pass

class HealthBuff(Buff):

    def __init__(self, value: int):
        super().__init__()
        self.name = "勇往直前"
        self.desc = f"恢复{value}点生命值."
        self.value = value

    def use(self, player: "Player") -> None:
        player.health += self.value

class BulletDamage(Buff):

    def __init__(self, value: int):
        super().__init__()
        self.name = "血脉觉醒"
        self.desc = f"每颗子弹增加{value}点伤害."
        self.value = value

    def use(self, player: "Player") -> None:
        player.gun.bullet_damage += self.value

class BulletSpeed(Buff):

    def __init__(self, value: int):
        super().__init__()
        self.name = "速战速决"
        self.desc = f"子弹速度增加{value}点."
        self.value = value

    def use(self, player: "Player") -> None:
        player.gun.bullet_speed += self.value

class FireRateBuff(Buff):

    def __init__(self, value: int):
        super().__init__()
        self.name = "唯快不破"
        self.desc = f"枪的射速增加{value}点."
        self.value = value

    def use(self, player: "Player") -> None:
        player.gun.firing_rate += self.value

class FireBulletCountBuff(Buff):

    def __init__(self, value: int):
        super().__init__()
        self.name = "火力覆盖"
        self.desc = f"发射子弹的颗数增加{value}颗."
        self.value = value

    def use(self, player: "Player") -> None:
        player.gun.fire_bullet_count += self.value

class BulletKnockbackForce(Buff):

    def __init__(self, value: int):
        super().__init__()
        self.name = "大力出奇迹"
        self.desc = f"击退力度增加{value}点."
        self.value = value

    def use(self, player: "Player") -> None:
        player.gun.bullet_knockback_force += self.value

Buffs = [
    (HealthBuff, 5, 15),
    (BulletDamage, 1, 30),
    (BulletSpeed, 20, 100),
    (FireRateBuff, 1, 2),
    (FireBulletCountBuff, 1, 2),
    (BulletKnockbackForce, 1, 5)
]

class Node2D:

    def __init__(self, parent: "Node2D", pos: Vector2, size: Vector2, z_index: int = 0):
        self.parent = parent
        self.pos = pos
        self.size = size
        self.collision_rect = Rect(pos, size)
        self.z_index = z_index
        self.visible = True
        self.can_paused = True
        self.children = []
        self.can_collide = False
        self.has_collided_signal = Signal()

        self.set_parent(parent)

    def update(self, delta: float) -> None:
        pass

    def draw(self, surface: Surface) -> None:
        if not self.visible: return

    def set_parent(self, parent: "Node2D") -> None:
        self.parent = parent
        if parent is None:
            return
        if not self in parent.children:
            parent.children.append(self)

    def add_child(self, child: "Node2D") -> None:
        self.children.append(child)
        child.set_parent(self)

    def remove_child(self, child: "Node2D") -> None:
        if child not in self.children:
            return
        self.children.remove(child)
        child.set_parent(None)

    def remove_all_children(self) -> None:
        for child in self.children[:]:
            self.children.remove(child)
            child.set_parent(None)

    def remove(self) -> None:
        if self.parent is None:
            return
        self.parent.remove_child(self)
        self.parent = None

    def get_all_children(self) -> list:
        all_children = []
        for child in self.children:
            all_children.append(child)
            all_children.extend(child.get_all_children())
        return all_children

    def get_root(self) -> "Root":
        if isinstance(self, Root):
            return self

        if isinstance(self.parent, Root):
            return self.parent

        return self.parent.get_root()

    def get_rect(self) -> Rect:
        return Rect(self.pos, self.size)

    def add_in_group(self, name: str) -> None:
        root = self.get_root()
        if root is None: return
        group = root.groups.get(name)
        if group is None:
            group = []
            root.groups[name] = group
        group.append(self)

class Root(Node2D):

    instance = None

    def __new__(cls, *args, **kwargs):
        if cls.instance is None:
            cls.instance = super().__new__(cls)
        return cls.instance

    def __init__(self):
        super().__init__(None, Vector2(0, 0), Vector2(pygame.display.get_surface().get_size()))
        self.groups = {}
        self.delta = 0.0
        self.clear_color = Color(0, 0, 0)
        self.mouse_pos = Vector2(0, 0)

        self.__pause_time = 0
        self.__pause_duration = 0
        self.__is_paused = False

    def update(self, delta: float) -> None:
        self.delta = delta
        self.mouse_pos = pygame.mouse.get_pos()

    def get_nodes_in_group(self, name: str) -> list:
        group = self.groups.get(name)
        if group is None:
            return []
        return group

    def get_first_node_in_group(self, name: str) -> Node2D:
        group = self.groups.get(name)
        if group is None:
            return None
        return group[0]

    def pause(self, value: bool) -> None:
        self.__is_paused = value
        if value:
            self.__pause_time = pygame.time.get_ticks()
        else:
            self.__pause_duration += pygame.time.get_ticks() - self.__pause_time

    def is_paused(self) -> bool:
        return self.__is_paused

    def get_ticks(self, offset: int = 0) -> int:
        return pygame.time.get_ticks() - self.__pause_duration + offset

class Sprite2D(Node2D):

    def __init__(self, parent: Node2D, pos: Vector2, image: Surface):
        super().__init__(parent, pos, Vector2(image.get_size()))
        self.image = image
        self.size = Vector2(image.get_size())

    def draw(self, surface: Surface) -> None:
        super().draw(surface)
        surface.blit(self.image, self.pos)

class HealthBar(Sprite2D):

    def __init__(self, parent: Node2D, max_health: int, pos: Vector2, size: Vector2, border: int = 1):
        super().__init__(parent, pos, Surface(size))
        self.max_health = max_health
        self.health = max_health
        self.border = border
        self.border_color = Color(255, 255, 255)
        self.value_color = Color(255, 0, 0)
        self.z_index = 5
        self.image.set_colorkey((0, 0, 0))

    def draw(self, surface: Surface) -> None:
        self.image.fill((0, 0, 0))
        pygame.draw.rect(self.image, self.border_color, (0, 0, self.size.x, self.size.y), self.border)
        pygame.draw.rect(self.image, self.value_color, (self.border, self.border, (self.size.x - self.border * 2) * self.health * 1.0 / self.max_health, self.size.y - self.border * 2))
        super().draw(surface)

class Bullet(Sprite2D):

    def __init__(self, parent: Node2D, pos: Vector2, direction: Vector2):
        super().__init__(parent, pos, Surface((10, 10)))
        self.speed = 800
        self.damage = 5
        self.knockback_force = 5
        self.can_penetrate = False
        self.direction = direction
        self.z_index = 2
        self.image.set_colorkey((0, 0, 0))
        self.can_collide = True
        self.pos -= self.size / 2

    def update(self, delta: float) -> None:
        self.pos += self.speed * self.direction * delta
        self.collision_rect.topleft = self.pos

        rect = pygame.display.get_surface().get_rect()
        if self.pos.x < 0 or self.pos.x > rect.width or self.pos.y < 0 or self.pos.y > rect.height:
            self.remove()

    def draw(self, surface: Surface) -> None:
        pygame.draw.circle(self.image, (0, 255, 0), self.size / 2, self.size.x / 2)
        super().draw(surface)

class Gun(Node2D):

    def __init__(self, parent: Node2D):
        super().__init__(parent, Vector2(parent.get_rect().center), Vector2())
        self.z_index = 3

        self.__laste_fire_time = 0
        self.firing_rate = 3
        self.bullet_damage = 5
        self.bullet_speed = 800
        self.bullet_knockback_force = 5
        self.bullet_can_penetrate = False
        self.fire_bullet_count = 1

    def _create_bullet(self, direction: Vector2) -> None:
        bullet = Bullet(self, self.pos.copy(), direction)
        bullet.can_penetrate = self.bullet_can_penetrate
        bullet.damage = self.bullet_damage
        bullet.speed = self.bullet_speed
        bullet.knockback_force = self.bullet_knockback_force

    def _create_multiple_bullets(self, count: int, base_direction: Vector2, rotate_angle: float) -> None:
        for i in range(1, count + 1):
            angle = base_direction
            if self.fire_bullet_count % 2 == 0:
                if i == 1:
                    angle = base_direction.rotate(rotate_angle / 2)
                else:
                    angle = base_direction.rotate((i-1) * rotate_angle + rotate_angle / 2)
            else:
                angle = base_direction.rotate(i * rotate_angle)

            self._create_bullet(angle)

    def fire(self, direction: Vector2) -> None:
        if self.get_root().get_ticks() - self.__laste_fire_time < 1000.0 / self.firing_rate:
            return

        half = self.fire_bullet_count // 2
        self._create_multiple_bullets(half, direction, 5)

        if not self.fire_bullet_count % 2 == 0:
            self._create_bullet(direction)

        self._create_multiple_bullets(half, direction, -5)

        self.__laste_fire_time = self.get_root().get_ticks()

class Player(Sprite2D):

    def __init__(self, parent: Node2D, pos: Vector2):
        super().__init__(parent, pos, Surface(Vector2(60, 60)))
        self.speed = 500
        self.z_index = 1
        self.can_collide = True
        self.image.fill((255, 0, 0))
        self.limit_rect = Rect(pygame.display.get_surface().get_rect())
        self.died_signal = Signal()

        self.max_health = 100
        self.health = self.max_health
        self.score = 0
        self.kill_count = 0

        self.add_in_group("player")

        self.gun = Gun(self)
        self.gun.bullet_damage = 50
        self.gun.firing_rate = 5
        self.gun.bullet_speed = 650
        self.gun.bullet_knockback_force = 5
        self.gun.fire_bullet_count = 1
        # self.gun.bullet_can_penetrate = True

        self._init_data = self._get_init_data()

    def __str__(self) -> str:
        return f"""Player(
            bullet_damage: {self.gun.bullet_damage},
            firing_rate: {self.gun.firing_rate},
            bullet_speed: {self.gun.bullet_speed},
            bullet_knockback_force: {self.gun.bullet_knockback_force},
            fire_bullet_count: {self.gun.fire_bullet_count},
            health: {self.health},
        )"""

    def update(self, delta: float) -> None:
        keys = pygame.key.get_pressed()
        direction = Vector2()
        if keys[pygame.K_w]:
            direction.y = -1
        if keys[pygame.K_s]:
            direction.y = 1
        if keys[pygame.K_a]:
            direction.x = -1
        if keys[pygame.K_d]:
            direction.x = 1

        pos = self.pos
        direction = direction.normalize() if direction.length() != 0 else direction
        pos += direction * self.speed * delta

        if pos.x < self.limit_rect.left:
            pos.x = self.limit_rect.left
        if pos.x > self.limit_rect.right - self.size.x:
            pos.x = self.limit_rect.right - self.size.x
        if pos.y < self.limit_rect.top:
            pos.y = self.limit_rect.top
        if pos.y > self.limit_rect.bottom - self.size.y:
            pos.y = self.limit_rect.bottom - self.size.y

        self.pos = pos
        self.collision_rect.topleft = self.pos
        self.gun.pos = Vector2(self.get_rect().center)

        shoot_direction = Vector2(pygame.mouse.get_pos()) - self.get_rect().center
        shoot_direction = shoot_direction.normalize() if shoot_direction.length()!= 0 else shoot_direction
        # if pygame.mouse.get_pressed()[0]:
        self.gun.fire(shoot_direction)

    def set_health(self, health: int) -> None:
        self.health = pygame.math.clamp(health, 0, self.max_health)
        if self.health <= 0:
            self.died_signal.emit()

    def _get_init_data(self) -> dict:
        return {
            "pos": self.pos.copy(),
            "speed": self.speed,
            "health": self.health,
            "score": self.score,
            "kill_count": self.kill_count,
            "max_health": self.max_health,
            "bullet_can_penetrate": self.gun.bullet_can_penetrate,
            "bullet_damage": self.gun.bullet_damage,
            "firing_rate": self.gun.firing_rate,
            "bullet_speed": self.gun.bullet_speed,
            "bullet_knockback_force": self.gun.bullet_knockback_force,
            "fire_bullet_count": self.gun.fire_bullet_count,
        }

    def restore_init_data(self) -> None:
        self.pos = self._init_data["pos"]
        self.speed = self._init_data["speed"]
        self.health = self._init_data["health"]
        self.score = self._init_data["score"]
        self.kill_count = self._init_data["kill_count"]
        self.max_health = self._init_data["max_health"]
        self.gun.bullet_can_penetrate = self._init_data["bullet_can_penetrate"]
        self.gun.bullet_damage = self._init_data["bullet_damage"]
        self.gun.firing_rate = self._init_data["firing_rate"]
        self.gun.bullet_speed = self._init_data["bullet_speed"]
        self.gun.bullet_knockback_force = self._init_data["bullet_knockback_force"]
        self.gun.fire_bullet_count = self._init_data["fire_bullet_count"]

class Cursor(Sprite2D):

    def __init__(self, parent: Node2D):
        super().__init__(parent, Vector2(0, 0), Surface((12, 12)))
        self.z_index = 9999
        self.thickness = 2
        self.color = Color((0, 255, 0))
        self.image.set_colorkey((0, 0, 0))
        self.can_paused = False
        pygame.mouse.set_visible(False)

    def update(self, delta: float) -> None:
        self.pos = pygame.mouse.get_pos()

    def draw(self, surface: Surface) -> None:
        pygame.draw.line(self.image, self.color, Vector2(self.size.x / 2 - self.thickness / 2, 0), Vector2(self.size.x / 2 - self.thickness / 2, self.size.y), self.thickness)
        pygame.draw.line(self.image, self.color, Vector2(0, self.size.y / 2 - self.thickness / 2), Vector2(self.size.x, self.size.y / 2 - self.thickness / 2), self.thickness)
        super().draw(surface)

class Enemy(Sprite2D):

    init_data = {}

    def __init__(self, parent: Node2D, pos: Vector2):
        super().__init__(parent, pos, Surface((30, 30)))
        self.speed = 80
        self.z_index = 0
        self.image.fill((255, 255, 255))
        self.can_collide = True

        self.player = self.get_root().get_first_node_in_group("player")

        self.max_health = 500
        self.health = self.max_health

        Enemy.init_data = self._get_init_data()

        self.health_bar = HealthBar(self, self.max_health, Vector2(self.pos.x, self.pos.y - 15), Vector2(self.size.x, 8), 2)

        self.has_collided_signal.connect(self._on_has_collided_signal)

    def update(self, delta: float) -> None:
        self.collision_rect.topleft = self.pos
        self.health_bar.pos = Vector2(self.pos.x, self.pos.y - 15)

        direction = Vector2(self.player.get_rect().center) - Vector2(self.get_rect().center)
        if direction.length()!= 0:
            direction = direction.normalize()
        self.pos += direction * self.speed * delta

    def draw(self, surface: Surface) -> None:
        pygame.draw.circle(self.image, (255, 0, 0), self.size / 2, 7.5)
        super().draw(surface)

    def _get_init_data(self) -> dict:
        return {
            "speed": self.speed,
            "health": self.health,
            "max_health": self.max_health,
        }

    def _on_has_collided_signal(self, node: Node2D) -> None:
        if isinstance(node, Bullet):
            self.health -= node.damage
            self.health_bar.health = self.health
            self.pos += node.direction * node.knockback_force
            if self.health <= 0:
                self.player.score += 5
                self.player.kill_count += 1
                self.remove()
            if not node.can_penetrate:
                node.remove()

        if isinstance(node, Player):
            self.player.score -= 10
            self.player.set_health(self.player.health - 10)
            self.player.kill_count += 1
            self.remove()

class Lable(Node2D):

    def __init__(self, parent: Node2D, pos: Vector2, text: str = ""):
        super().__init__(parent, pos, Vector2())
        self.font = pygame.font.SysFont("SimHei", 30)
        self.font_color = Color(255, 255, 255)
        self.text_surfaces = []
        self.__text = text
        self.set_text(text)

    def update(self, delta: float) -> None:
        self.text_surfaces.clear()
        lines = self.__text.split("\n")
        line_height = self.font.get_linesize()
        y = self.pos.y
        max_width = 0
        for line in lines:
            text_surface = self.font.render(line, True, self.font_color)
            self.text_surfaces.append((text_surface, Vector2(self.pos.x, y)))
            y += line_height
            if text_surface.get_width() > max_width:
                max_width = text_surface.get_width()

        self.size = Vector2(max_width, len(lines) * line_height)

    def draw(self, surface: Surface) -> None:
        for text_surface, pos in self.text_surfaces:
            surface.blit(text_surface, pos)

    def set_text(self, text: str) -> None:
        self.__text = text
        # self.text_surfaces.clear()
        # lines = self.__text.split("\n")
        # line_height = self.font.get_linesize()
        # y = self.pos.y
        # max_width = 0
        # for line in lines:
        #     text_surface = self.font.render(line, True, self.font_color)
        #     self.text_surfaces.append((text_surface, Vector2(self.pos.x, y)))
        #     y += line_height
        #     if text_surface.get_width() > max_width:
        #         max_width = text_surface.get_width()

        # self.size = Vector2(max_width, len(lines) * line_height)

    def get_text(self) -> str:
        return self.__text

class Button(Node2D):

    def __init__(self, parent: Node2D, pos: Vector2,  text: str):
        super().__init__(parent, pos, Vector2())
        self.padding = Vector2(10)
        self.is_pressed = False
        self.text_lbl = Lable(self, pos + self.padding, text)
        self.bg_color = Color(0, 0, 0)
        self.border_color = Color(255, 255, 255)
        self.border_width = 3
        self.hot_keys = []
        self.hot_key_pressed = False
        self.set_text(text)
        self.pressed_singal = Signal()

    def update(self, delta: float) -> None:
        self.size = Vector2(self.text_lbl.size) + self.padding * 2
        self.text_lbl.pos = self.pos + self.padding
        self.text_lbl.z_index = self.z_index
        self.text_lbl.can_paused = self.can_paused
        self.text_lbl.visible = self.visible

        if self.visible:
            if pygame.mouse.get_pressed()[0] and self.get_rect().collidepoint(pygame.mouse.get_pos()) and not self.is_pressed:
                self.pressed_singal.emit()
                self.is_pressed = True
            if not pygame.mouse.get_pressed()[0]:
                self.is_pressed = False

        keys = pygame.key.get_pressed()
        for key in self.hot_keys:
            if keys[key]:
                if self.hot_key_pressed:
                    break
                self.pressed_singal.emit()
                self.hot_key_pressed = True
                break
            else:
                self.hot_key_pressed = False

    def draw(self, surface: Surface) -> None:
        pygame.draw.rect(surface, self.bg_color, Rect(self.pos.x, self.pos.y, self.size.x, self.size.y))
        pygame.draw.rect(surface, self.border_color, Rect(self.pos.x, self.pos.y, self.size.x, self.size.y), self.border_width)

    def set_text(self, text: str) -> None:
        self.text_lbl.set_text(text)
        self.size = Vector2(self.text_lbl.size) + self.padding * 2

    def get_text(self) -> str:
        return self.text_lbl.get_text()

class BuffPanel(Sprite2D):

    def __init__(self, parent: Node2D):
        super().__init__(parent, Vector2(0, 0), Surface(pygame.display.get_surface().get_size(), pygame.SRCALPHA))
        self.image.fill(Color(0, 0, 0, 100))

        self.buff_btns = []
        self.buff_btn1 = Button(self, Vector2(10, 10), "buff1")
        self.buff_btn2 = Button(self, Vector2(120, 10), "buff2")
        self.buff_btn3 = Button(self, Vector2(230, 10), "buff3")
        self.buff_btns.append(self.buff_btn1)
        self.buff_btns.append(self.buff_btn2)
        self.buff_btns.append(self.buff_btn3)

        self.player = self.get_root().get_first_node_in_group("player")

        self.visible = False
        self.can_paused = False
        for btn in self.buff_btns:
            btn.can_paused = self.can_paused

    def update(self, delta: float) -> None:
        width = 0
        max_height = 0
        for btn in self.buff_btns:
            btn.z_index = self.z_index
            width += btn.size.x
            if btn.size.y > max_height:
                max_height = btn.size.y

        pos = Vector2((self.size.x - width - 2 * 20) / 2, (self.size.y - max_height) / 2)
        for btn in self.buff_btns:
            btn.pos = pos.copy()
            pos.x += btn.size.x + 20
            btn.visible = self.visible

    def draw(self, surface: Surface) -> None:
        super().draw(surface)

    def _on_buff_btn_pressed(self, buff: Buff) -> None:
            buff.use(self.player)
            self.visible = False
            self.get_root().pause(not self.get_root().is_paused())

    def _bind_buff(self, btn: Button) -> None:
        b = random.choice(Buffs)
        buff = b[0](random.randint(b[1], b[2]))
        btn.set_text(f"{buff.name}\n{buff.desc}")
        btn.pressed_singal.disconnect_all()
        btn.pressed_singal.connect(lambda: self._on_buff_btn_pressed(buff))

    def display(self) -> None:
        for btn in self.buff_btns:
            self._bind_buff(btn)

        self.visible = True

class GameOverPanel(Sprite2D):

    def __init__(self, parent: Node2D):
        super().__init__(parent, Vector2(0, 0), Surface(pygame.display.get_surface().get_size(), pygame.SRCALPHA))
        self.image.fill(Color(0, 0, 0, 100))
        self.z_index = 99
        self.can_paused = False
        self.visible = False

        self.lbl = Lable(self, Vector2(), "游戏结束")
        self.lbl.font_color = Color(255, 0, 0)
        self.lbl.font = pygame.font.SysFont("SimHei", 50)
        self.lbl.can_paused = False

        self.restart_bnt = Button(self, Vector2(10, 10), "重新开始")
        self.restart_bnt.can_paused = False

    def update(self, delta: float) -> None:
        self.lbl.visible = self.visible
        self.restart_bnt.visible = self.visible

        self.lbl.z_index = self.z_index
        self.restart_bnt.z_index = self.z_index

        self.lbl.pos = (self.size - self.lbl.size) / 2
        self.lbl.pos.y -= 100
        self.restart_bnt.pos = (self.size - self.restart_bnt.size) / 2
        self.restart_bnt.pos.y += self.lbl.size.y

class TopUI(Node2D):

    def __init__(self, parent: Node2D):
        super().__init__(parent, Vector2(0, 0), Vector2(pygame.display.get_surface().get_size()))
        self.z_index = 99
        self.add_in_group("top_ui")

        self.player = self.get_root().get_first_node_in_group("player")

        self.player_health_bar = HealthBar(self, self.player.max_health, Vector2(), Vector2(400, 20), 3)
        self.player_health_bar.z_index = self.z_index
        self.player_health_bar.pos.x = (self.size.x - self.player_health_bar.size.x) / 2
        self.player_health_bar.pos.y = self.size.y - self.player_health_bar.size.y - 10

        self.player_health_lbl = Lable(self, Vector2(10, 10))
        self.player_health_lbl.z_index = self.z_index
        self.player_health_lbl.pos.y = self.player_health_bar.pos.y - self.player_health_lbl.size.y - 5

        self.score_lbl = Lable(self, Vector2(10, 10))
        self.score_lbl.z_index = self.z_index

        self.timer_lbl = Lable(self, Vector2(10, 10))
        self.timer_lbl.z_index = self.z_index

        self.kill_count_lbl = Lable(self, Vector2(10, 10))
        self.kill_count_lbl.z_index = self.z_index

        self.buff_panel = BuffPanel(self)
        self.buff_panel.z_index = self.z_index + 1
        self.buff_panel.visible = False

        pause_btn = Button(self, Vector2(10, 10), "暂停")
        pause_btn.visible = False
        pause_btn.can_paused = False
        pause_btn.hot_keys.append(pygame.K_ESCAPE)
        def _on_pause_btn_pressed():
            if self.over_panel.visible: return
            if self.buff_panel.visible: return
            self.get_root().pause(not self.get_root().is_paused())
        pause_btn.pressed_singal.connect(_on_pause_btn_pressed)

        self.over_panel = GameOverPanel(self)
        self.over_panel.z_index = self.z_index + 1

    def update(self, delta: float) -> None:
        self.player_health_bar.health = self.player.health

        lbl_text = f"{self.player.health}/{self.player.max_health}"
        self.player_health_lbl.set_text(lbl_text)
        self.player_health_lbl.pos.x = (self.size.x - self.player_health_lbl.size.x) / 2

        self.score_lbl.set_text(f"分数: {self.player.score}")

        self.timer_lbl.pos.x = (self.size.x - self.timer_lbl.size.x) / 2

        self.kill_count_lbl.pos.x = self.size.x - self.kill_count_lbl.size.x - 10
        self.kill_count_lbl.set_text(f"击杀: {self.player.kill_count}")

    def _convert_time(self, time: int) -> str:
        minutes = time // 60
        seconds = time % 60
        return f"{minutes:02}:{seconds:02}"

    def update_timer_lbl(self, offset: int) -> None:
        self.timer_lbl.set_text(f"{self._convert_time(int(self.get_root().get_ticks(offset) / 1000))}")

class MainScene(Node2D):

    def __init__(self, root: Root):
        super().__init__(root, Vector2(0, 0), Vector2(pygame.display.get_surface().get_size()))
        self.z_index = 0
        self.max_enemy_count = 10
        self.create_enemies_range = 100
        self.update_buff_time = 10
        self.enemy_health = 500
        self.enemy_speed = 80

        Cursor(self)
        self.player = Player(self, self.size / 2)
        self.enemies = Node2D(self, Vector2(0, 0), Vector2(0, 0))
        self.top_ui = TopUI(self)

        self.player.died_signal.connect(self.game_over)
        self.top_ui.over_panel.restart_bnt.pressed_singal.connect(self._on_game_over_btn_pressed)

        self.start_time = self.get_root().get_ticks()
        self.over_time = 0

    def update(self, delta: float) -> None:
        self.top_ui.update_timer_lbl(-self.over_time)

        if len(self.enemies.children) < self.max_enemy_count:
            pos = Vector2()
            flag = random.randrange(0, 4)
            if flag == 0:
                pos = Vector2(random.randint(0, self.size.x), random.randint(-self.create_enemies_range, 0))
            elif flag == 1:
                pos = Vector2(random.randint(0, self.size.x), random.randint(self.size.y, self.size.y + self.create_enemies_range))
            elif flag == 2:
                pos = Vector2(random.randint(-self.create_enemies_range, 0), random.randint(0, self.size.y))
            else:
                pos = Vector2(random.randint(self.size.x, self.size.x + self.create_enemies_range), random.randint(0, self.size.y))
            enemy = Enemy(self.enemies, pos)
            enemy.max_health = self.enemy_health
            enemy.health = self.enemy_health
            enemy.speed = self.enemy_speed

        for enemy in self.enemies.children[:]:
            if enemy.health <= 0:
                self.enemies.remove_child(enemy)

        if self.get_root().get_ticks() - self.start_time >= self.update_buff_time * 1000:
            if int((self.get_root().get_ticks() - self.start_time) / 1000) % self.update_buff_time == 0:
                self.get_root().pause(True)
                self.top_ui.buff_panel.display()
                self.enemy_health += 100
                self.enemy_speed += 5
                self.start_time = self.get_root().get_ticks()

    def game_over(self) -> None:
        self.get_root().pause(True)
        self.top_ui.over_panel.visible = True
        self.over_time = self.get_root().get_ticks()

    def _on_game_over_btn_pressed(self) -> None:
        self.get_root().pause(False)
        self.player.restore_init_data()
        self.enemy_health = Enemy.init_data["health"]
        self.enemy_speed = Enemy.init_data["speed"]
        self.enemies.remove_all_children()
        self.player.gun.remove_all_children()
        self.top_ui.over_panel.visible = False
        self.start_time = self.get_root().get_ticks()

class Game:

    def __init__(self):
        self.screen = pygame.display.set_mode((1280, 720))
        self.clock = pygame.time.Clock()
        self.running = True
        self.root = Root()
        self.root.clear_color = Color(47, 47, 47)

        MainScene(self.root)

    def run(self) -> None:
        while self.running:
            self.clock.tick(120)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

            self.screen.fill(self.root.clear_color)

            delta = self.clock.get_time() / 1000
            self.root.update(delta)

            for node in sorted(self.root.get_all_children(), key=lambda node: node.z_index):
                if self.root.is_paused() and node.can_paused:
                    if node.visible:
                        node.draw(self.screen)
                    continue

                node.update(delta)
                if node.visible:
                    node.draw(self.screen)

                if isinstance(node, Bullet):
                     for other_node in self.root.get_all_children():
                        if node.parent == other_node: continue
                        if not isinstance(other_node, Enemy): continue
                        if node.collision_rect.colliderect(other_node.collision_rect):
                            other_node.has_collided_signal.emit(node)
                            if not node.can_penetrate:
                                break

                if isinstance(node, Player):
                    for other_node in self.root.get_all_children():
                        if not isinstance(other_node, Enemy): continue
                        if node.collision_rect.colliderect(other_node.collision_rect):
                            other_node.has_collided_signal.emit(node)

            pygame.display.flip()

        pygame.quit()

Game().run()


#coding=utf-8
"""
imgcv
"""

from setuptools import setup
from setuptools import find_packages

install_requires = [
]

setup(
    name = "imgcv",
    version = "1.0.0",
    description = 'image computer visior',
    author='Hyxbiao',
    author_email="hyxbiao@gmail.com",
    packages = find_packages(),
    entry_points={
        'console_scripts': [
            'imgcv = imgcv.tools.imgcv:main',
            'imgbrowser = imgcv.tools.imgbrowser:main',
        ]
    },
    install_requires = install_requires,
    zip_safe = False,
)


import functools
import os
import re
import requests
import csv
import sys
from datetime import time, timedelta

import argparse

#print(response.json())

class event_type:
    GOAL = 0
    PENALTY = 1
    ASSIST = 2

class game_event:
    def toPeriod(self, int_period):
        int_period = int(int_period)
        if int_period == 1:
            return str(int_period) + 'st'
        elif int_period == 2:
            return str(int_period) + 'nd'
        elif int_period == 3:
            return str(int_period) + 'rd'
        else:
            return str(int_period) + 'th'
    def __init__(self, id, name, start_time, end_time, period, participant, partNumber, event_type, penalty_duration = 0, event_subtype = ''):
        self.id = id
        self.name = name
        self.participant = participant
        self.partNumber = partNumber
        self.start_time = start_time
        self.end_time = end_time
        self.period = self.toPeriod(period)
        self.event_type = event_type
        self.event_subtype = event_subtype
        self.penalty_duration = penalty_duration

def score_sort(item1, item2):
    if(item1.period < item2.period or (item1.period == item2.period and item1.start_time >= item2.start_time)):
        return -1
    else:
        return 1

class score_track:
    def __init__(self):
        self.scores_ = []
    def add_score(self, score):
        self.scores_.append(score)
        self.scores_ = sorted(self.scores_, key=functools.cmp_to_key(score_sort))
    def score_str(self, period, time, team1, team2):
        dict = {team1: 0, team2: 0}
        for score in filter(lambda x: x.event_type == event_type.GOAL, self.scores_):
            if score.period > period or (score.period == period and score.start_time < time):
                continue
            dict[score.name] += 1
        vals = list(dict.values())
        return '' + str(vals[0]) + ' -- ' +  str(vals[1])

def collectGameTime(dateObj):
    return timedelta(minutes=int(dateObj['minutes']), seconds=int(dateObj['seconds']))

def computePenalty(start, dur):
    if start.seconds <= dur.seconds:
        return timedelta(minutes=0, seconds=0)
    return start - dur

def obtainGoalCode(dict):
    if dict['isPowerplay']:
        return 'PPG'
    elif dict['isShorthanded']:
        return 'SHG'
    elif dict['isEmptyNet']:
        return 'ENG'
    elif dict['isPenaltyShot']:
        return 'PSG'
    else:
        return 'REG'

def writeGameToFile(hockey_csv, response, date):
    rj = response.json()
    idTeamName = {}
    out_writer = csv.writer(hockey_csv)
    for team in rj['teams']:
        idTeamName[team['id']] = team['name']
    teamNames = list(idTeamName.values())
    scores = score_track()
    for goal in rj['goals']:
        scores.add_score(game_event(goal['teamId'], idTeamName[goal['teamId']], collectGameTime(goal['gameTime']), collectGameTime(goal['gameTime']), goal['gameTime']['period'], goal['participant']['fullName'], goal['participant']['number'], event_type.GOAL, 0, obtainGoalCode(goal)))
        for assist in goal['assists']:
            scores.add_score(game_event(goal['teamId'], idTeamName[goal['teamId']], collectGameTime(goal['gameTime']), collectGameTime(goal['gameTime']), goal['gameTime']['period'], assist['fullName'], assist['number'], event_type.ASSIST, 0, obtainGoalCode(goal)))

    for pen in rj['penalties']:
        pen_period = int(pen['gameTime']['period'])
        pen_starttime = collectGameTime(pen['gameTime'])
        pen_endtime = pen_starttime
        pen_duration = 0
        if 'description' in pen['duration']:
            pen_duration = int(re.findall("\d+", pen['duration']['description'])[0])
            pen_endtime = computePenalty(collectGameTime(pen['gameTime']), timedelta(minutes=pen_duration))
        scores.add_score(game_event(pen['teamId'], idTeamName[pen['teamId']], pen_starttime, pen_endtime , pen_period, pen['participant']['fullName'], pen['participant']['number'], event_type.PENALTY, pen_duration, pen['infraction']))

        if pen_starttime.total_seconds() < pen_duration * 60 and pen_period < 3:
            carryover_start = timedelta(minutes=20, seconds=0)
            carryover_duration = timedelta(minutes=pen_duration) - pen_starttime
            carryover_endtime = carryover_start - carryover_duration
            scores.add_score(game_event(pen['teamId'], idTeamName[pen['teamId']], carryover_start, carryover_endtime, pen_period + 1, pen['participant']['fullName'], pen['participant']['number'], event_type.PENALTY, pen_duration, pen['infraction']))

    for score in scores.scores_:
        if score.event_type == event_type.GOAL:
            out_writer.writerow([teamNames[0], teamNames[1], date, 'GOAL', score.event_subtype, score.participant, score.partNumber, score.name, score.start_time, score.end_time, score.period, 0, scores.score_str(score.period, score.start_time, teamNames[0], teamNames[1])])

        if score.event_type == event_type.ASSIST:
            out_writer.writerow([teamNames[0], teamNames[1], date, 'ASSIST', score.event_subtype, score.participant, score.partNumber, score.name, score.start_time, score.end_time, score.period, 0, scores.score_str(score.period, score.start_time, teamNames[0], teamNames[1])])

        if score.event_type == event_type.PENALTY:
            out_writer.writerow([teamNames[0], teamNames[1], date, 'PENALTY', score.event_subtype, score.participant, score.partNumber, score.name, score.start_time, score.end_time, score.period, score.penalty_duration, scores.score_str(score.period, score.start_time, teamNames[0], teamNames[1])])

def main():
    parser = argparse.ArgumentParser('Collect data from VIAHA webpage and dump to csv spreadsheets.')
    parser.add_argument('-s','--separate', dest='separate', action='store_const', const=True, default=False, help='If enabled, games will be split into separate files.')
    parser.add_argument('scheduleId', type=int, nargs='?', help='Provide the ID of the schedule for the games you want to collect.')
    parser.add_argument('teamId', type=int, nargs='?', help='Provide the team you are interested in from the provided schedule')

    args=parser.parse_args()

    if args.scheduleId is None or args.teamId is None:
        raise Exception('Cannot run script without a schedule and team ID')

    gameId = sys.argv[1]
    scheduleUrl = 'https://api.hisports.app/api/games'
    paramStr = '?filter={{"where":{{"and":[{{"scheduleId":{}}},{{"or":[{{"homeTeamId":{}}},{{"awayTeamId":{}}}]}}]}},"include":["arena","schedule","group","teamStats"],"order":["startTime ASC","id DESC"],"limit":null,"skip":null}}'.format(args.scheduleId, args.teamId, args.teamId)
    headers = {'authorization' : 'API-Key f75fa549e81421f19dc929bc91f88820b6d09421'}
    sess = requests.Session()
    req = requests.Request('GET', scheduleUrl, headers=headers)
    prep = req.prepare()
    prep.url += paramStr
    resp = sess.send(prep)

    collectfilename = 'games-season-{}-{}-{}.csv'.format(resp.json()[0]['seasonId'], args.scheduleId, args.teamId)
    if args.separate == False:
        if os.path.isfile(collectfilename):
            os.remove(collectfilename)
        with open(collectfilename, 'a') as file:
            out_writer = csv.writer(file)
            out_writer.writerow(['Home Team', 'Away Team', 'Date', 'Event', 'Event Type', 'Player Name', 'Player Number', 'Player Team', 'Start Time', 'End Time', 'Period', 'Penalty Mins', 'Score'])

    for game in resp.json():
        gameUrl = 'https://api.hisports.app/api/games/{}/boxScore'.format(game['id'])
        req = requests.Request('GET', gameUrl, headers=headers)
        resp = sess.send(req.prepare())
        if args.separate:
            with open('game-{}-{}-{}.csv'.format(game['date'], args.scheduleId, args.teamId), 'w+') as file:
                out_writer = csv.writer(file)
                out_writer.writerow(['Home Team', 'Away Team', 'Date', 'Event', 'Event Type', 'Player Name', 'Player Number', 'Player Team', 'Start Time', 'End Time', 'Period', 'Penalty Mins', 'Score'])
                writeGameToFile(file, resp, game['date'])
        else:
            with open(collectfilename, 'a') as file:
                writeGameToFile(file, resp, game['date'])

if __name__ == '__main__':
    main()


from __future__ import division

from vistrails.db.domain import DBPEFunction, DBPEParameter
from vistrails.core.paramexplore.param import PEParam
import copy

import unittest
from vistrails.db.domain import IdScope

################################################################################

class PEFunction(DBPEFunction):
    """ Stores a function for a parameter exploration """

    ##########################################################################
    # Constructors and copy

    def __init__(self, *args, **kwargs):
        DBPEFunction.__init__(self, *args, **kwargs)
        if self.id is None:
            self.id = -1
        if self.module_id is None:
            self.module_id = -1
        if self.port_name is None:
            self.port_name = ""
        if self.is_alias is None:
            self.is_alias = 0
        self.set_defaults()

    def set_defaults(self, other=None):
        pass

    def __copy__(self):
        """ __copy__() -> ModuleFunction - Returns a clone of itself """
        return PEFunction.do_copy(self)

    def do_copy(self, new_ids=False, id_scope=None, id_remap=None):
        cp = DBPEFunction.do_copy(self, new_ids, id_scope, id_remap)
        cp.__class__ = PEFunction
        cp.set_defaults(self)
        return cp

    @staticmethod
    def convert(_function):
        if _function.__class__ == PEFunction:
            return
        _function.__class__ = PEFunction
        for _parameter in _function.db_get_parameters():
            PEParam.convert(_parameter)
        _function.set_defaults()

    ##########################################################################
    # Properties

    id = DBPEFunction.db_id
    module_id = DBPEFunction.db_module_id
    port_name = DBPEFunction.db_port_name
    is_alias = DBPEFunction.db_is_alias

    def _get_params(self):
        self.db_parameters.sort(key=lambda x: x.db_pos)
        return self.db_parameters
    def _set_params(self, params):
        self.db_parameters = params

    parameters = property(_get_params, _set_params)
    params = property(_get_params, _set_params)

    def add_parameter(self, param):
        self.db_add_parameter(param)
    addParameter = add_parameter

    def add_parameters(self, params):
        for p in params:
            self.db_add_parameter(p)

    ##########################################################################
    # Operators

    def __str__(self):
        """ __str__() -> str - Returns a string representation of itself """
        return ("<PEFunction id=%s module_id=%s port_name='%s' is_alias=%s params=%s)@%X" %
                (self.id,
                 self.module_id,
                 self.port_name,
                 self.is_alias,
                 [str(p) for p in self.params],
                 id(self)))

    def __eq__(self, other):
        """ __eq__(other: ModuleFunction) -> boolean
        Returns True if self and other have the same attributes. Used by ==
        operator.

        """
        if type(self) != type(other):
            return False
        if self.port_name != other.port_name:
            return False
        if self.module_id != other.module_id:
            return False
        if self.is_alias != other.is_alias:
            return False
        if len(self.params) != len(other.params):
            return False
        for p,q in zip(self.params, other.params):
            if p != q:
                return False
        return True

    def __ne__(self, other):
        """ __ne__(other: ModuleFunction) -> boolean
        Returns True if self and other don't have the same attributes.
        Used by !=  operator.

        """
        return not self.__eq__(other)

################################################################################
# Testing

class TestModuleFunction(unittest.TestCase):

    def create_function(self, id_scope=IdScope()):
        param = PEParam(id=id_scope.getNewId(PEParam.vtType),
                            pos=2,
                            interpolator='Stepper',
                            dimension=4,
                            value='[1, 2]')
        function = PEFunction(id=id_scope.getNewId(PEFunction.vtType),
                                  module_id=7,
                                  port_name='value',
                                  is_alias=0,
                                  parameters=[param])
        return function

    def test_copy(self):
        id_scope = IdScope()
        f1 = self.create_function(id_scope)
        f2 = copy.copy(f1)
        self.assertEquals(f1, f2)
        self.assertEquals(f1.id, f2.id)
        f3 = f1.do_copy(True, id_scope, {})
        self.assertEquals(f1, f3)
        self.assertNotEquals(f1.id, f3.id)

    def testComparisonOperators(self):
        f = self.create_function()
        g = self.create_function()
        self.assertEqual(f, g)
        g.module_id = 1
        self.assertNotEqual(f, g)
        g.module_id = 7
        g.port_name = "val"
        self.assertNotEqual(f, g)
        g.port_name = "value"
        g.is_alias = 1
        self.assertNotEqual(f, g)

    def test_str(self):
        str(self.create_function())

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


import tensorflow as tf

def accuracy(output, target, top_k=(1,)):
    """
    output : [10, 6]
    target: [10]
    """
    max_k = max(top_k)
    batch_size = target.shape[0]

    pred = tf.math.top_k(output, max_k).indices # [10, 6]
    pred = tf.transpose(pred, perm=[1, 0]) # [6, 10] to compare top_1, top_2,... between pred and target

    target = tf.broadcast_to(target, pred.shape)
    correct = tf.equal(pred, target)

    res = []
    for k in top_k:
        correct_k = tf.cast(tf.reshape(correct[:k], [-1]), dtype=tf.float32)
        correct_k = tf.reduce_sum(correct_k)
        acc = float(correct_k * (100 / batch_size))
        res.append(acc)

    return res

output = tf.random.normal([10, 6])
output = tf.math.softmax(output, axis=1)
target = tf.random.uniform([10], maxval=6, dtype=tf.int32)
acc = accuracy(output, target, top_k=(1,2,3,4,5,6))


from qiskit import *
from qiskit.visualization import plot_histogram
from qiskit.visualization import plot_state_city, plot_bloch_multivector
from qiskit.visualization import plot_state_paulivec, plot_state_hinton
from qiskit.visualization import plot_state_qsphere

# quantum circuit to make a Bell state
bell = QuantumCircuit(2, 2)
bell.h(0)
bell.cx(0, 1)

meas = QuantumCircuit(2, 2)
meas.measure([0,1], [0,1])

# execute the quantum circuit
backend = BasicAer.get_backend('qasm_simulator') # the device to run on
circ = bell.compose(meas)
result = backend.run(transpile(circ, backend), shots=1000).result()
counts  = result.get_counts(circ)
print(counts)

#히스토그램
plot_histogram(counts)

#히스토그램 그래프 옵션
# Execute 2-qubit Bell state again
second_result = backend.run(transpile(circ, backend), shots=1000).result()#트랜스파일: 서킷(cric)을 벡엔드로 소스코드를 변환한다.
second_counts  = second_result.get_counts(circ)
# Plot results with legend
legend = ['First execution', 'Second execution']#히스토그램에 레이블 지정
plot_histogram([counts, second_counts], legend=legend, figsize=(15,12), color=['red', 'blue'], bar_labels=False)#figsize :그래프 사이즈 설정

#마치 건물처럼 표현하는 그래프
backend = BasicAer.get_backend('statevector_simulator') # the device to run on
result = backend.run(transpile(bell, backend)).result()
psi  = result.get_statevector(bell)

plot_state_city(psi)

#힌튼
plot_state_hinton(psi)

#qsphere 상태 벡터의 진폭과 위상이 구체에 그려지는 양자 상태
plot_state_qsphere(psi)

#블로흐 구면
plot_bloch_multivector(psi)

codingproject/whatsyoureta/ETA_3Qiskit 시각화하기/ETA-3 여러가지 시각화 도구main.py


"""
Author: Matthew Smith (45326242)
Date: 15/04/2021
Title: AERO4450 Design Report Progress Check
"""

import numpy as np
import matplotlib.pyplot as plt
import math
import scipy.sparse as sps
import scipy.sparse.linalg as splinalg

# Parameters
M_N2 = 28 # g/mol
M_F2 = 44 # g/mol
M_O2 = 32 # g/mol
mdot_a = 900 # g/s
mdot_f = 30 # g/s
T_in = 800 # K
T_act = 40000 # K
A = 5*10**11 # (1/s)
T_ref = 298.15 # K

# Thermodynamic Properties (formation enthalpy,Cp)
P = {'F2': (0,2000),
     'FO2': (-12,2200),
     'O2': (0,1090),
     'N2': (0,1170)
        }

# Preliminaries

# Task 1

b = (0.77*M_O2)/(0.23*M_N2)
m_air = 2*M_O2/0.23
Zst = M_F2/(M_F2 + m_air)
AFst = m_air/M_F2
Zavg = mdot_f/(mdot_a + mdot_f)
AFavg = mdot_a/mdot_f

print("Zst =",Zst)
print("AFst =",AFst)
print("Zavg =",Zavg)
print("AFavg =",AFavg)

# Task 2

Y_pc_max = 2*(M_F2/2 + M_O2)/(2*b*M_N2 + 2*(M_F2/2 + M_O2))

# Define the piecewise function Ypc(Z)
def Y_pc(Z):
    if Z <= Zst:
        grad = Y_pc_max/Zst
        c = 0
        Y = grad*Z + c
    if Z > Zst:
        grad = -Y_pc_max/(1-Zst)
        c = -grad
        Y = grad*Z + c
    return Y

# Plot Y_pc(Z)
plt.figure(figsize=(10,8))
plt.plot([0,Zst],[0,Y_pc_max],'b-')
plt.plot([Zst,1],[Y_pc_max,0],'b-')
plt.plot([0,Zst],[Y_pc_max,Y_pc_max],'r--')
plt.plot([Zst,Zst],[0,Y_pc_max],'r--')
plt.xticks([0.0,0.137,0.2,0.4,0.6,0.8,1.0])
plt.yticks([0.0,0.2,0.335,0.4,0.6,0.8,1.0])
plt.xlabel("Mixture Fraction (Z)")
plt.ylabel("Mass Fraction (Y)")
plt.title("Mass Fraction of FO2 vs. Mixture Fraction")
plt.xlim(0,1)
plt.ylim(0,1)
plt.show()
print("Ymax =",Y_pc_max)

# Task 4

# Find ao and af
ao = M_O2/(M_F2/2 + M_O2)
af = 0.5*M_F2/(M_F2/2 + M_O2)
print("ao =",ao)
print("af =",af)

def Y_O2(Z,Y_FO2):
    Y = 0.23*(1-Z) - ao*Y_FO2
    # Ensure that Y is non-negative
    if Y < 0:
        return 0
    else:
        return Y

def Y_F2(Z,Y_FO2):
    Y = Z - af*Y_FO2
    # Ensure that Y is non-negative
    if Y < 0:
        return 0
    else:
        return Y

# YN2 is a conserved scalar
def Y_N2(Z):
    return 0.77*(1-Z)

# Sum of all Y's should be 1
def Y_Total(Z,Y_FO2):
    return Y_O2(Z,Y_FO2) + Y_N2(Z) + Y_F2(Z,Y_FO2) + Y_FO2

# Create lists for all mass fractions
Zs = np.linspace(0,1,200)
O2 = [Y_O2(Z,Y_pc(Z)) for Z in Zs]
F2 = [Y_F2(Z,Y_pc(Z)) for Z in Zs]
N2 = [Y_N2(Z) for Z in Zs]
FO2 = [Y_pc(Z) for Z in Zs]
Total = [Y_Total(Z,Y_pc(Z)) for Z in Zs]

# Plot the mass fractions vs. Z
plt.figure(figsize=(10,8))
plt.plot(Zs,O2,'c-',label='O2')
plt.plot(Zs,F2,'m-',label='F2')
plt.plot(Zs,N2,'g-',label='N2')
plt.plot(Zs,Total,'k-',label='Sum')
plt.plot(Zs,FO2,'b-',label='FO2')
plt.plot([Zst,Zst],[0,1],'r--',label='Zst')
plt.xlabel("Mixture Fraction (Z)")
plt.ylabel("Mass Fraction (Y)")
plt.xlim(0,1)
plt.ylim(0,1.1)
plt.yticks([0.0,0.2,0.23,0.4,0.6,0.77,0.8,1.0])
plt.legend()
plt.show()

# Task 5

def phi(prop,Z,c):
    # Y_FO2 depends on combustion progress
    Y_FO2 = c*Y_pc(Z)
    # Define formation enthalpy
    if prop == 'h_f':
        val = (P['F2'][0]*Y_F2(Z,Y_FO2) + P['FO2'][0]*Y_FO2 +
               P['O2'][0]*Y_O2(Z,Y_FO2) + P['N2'][0]*Y_N2(Z))*10**6
    # Define heat capacity
    if prop == 'Cp':
        val = (P['F2'][1]*Y_F2(Z,Y_FO2) + P['FO2'][1]*Y_FO2 +
               P['O2'][1]*Y_O2(Z,Y_FO2) + P['N2'][1]*Y_N2(Z))
    # Define total enthalpy
    if prop == 'h':
        val = phi('h_f',Z,c)*Y_FO2 + (T_in - T_ref)*phi('Cp',Z,c)
    return val

# Task 6

# TotaL enthalpy is a conserved scalar
def h(Z,c):
    return phi('h',0,c) + Z*(phi('h',1,c) - phi('h',0,c))

def T(Z,c):
    return T_ref + (h(Z,c) - phi('h_f',Z,c))/phi('Cp',Z,c)

def W(Z,c):
    Y_FO2 = c*Y_pc(Z)
    return Y_F2(Z,Y_FO2)*Y_O2(Z,Y_FO2)*A*np.exp(-T_act/T(Z,c))

# Task 7

Zs = np.linspace(0,1,500)

# Plot the temperature vs. Z for different combustion progresses
plot1 = []
plot2 = []
plot3 = []
plot4 = []
for z in Zs:
    for c in [0,1/3,2/3,1]:
        if c == 1/3:
            plot1.append(T(z,c))
        if c == 2/3:
            plot2.append(T(z,c))
        if c == 0:
            plot3.append(T(z,c))
        if c == 1:
            plot4.append(T(z,c))
plt.figure(figsize=(10,8))
plt.plot(Zs,plot1,'r-',label='c = 1/3')
plt.plot(Zs,plot2,'b-',label='c = 2/3')
plt.plot(Zs,plot3,'g-',label='c = 0')
plt.plot(Zs,plot4,'m-',label='c = 1')
plt.title('Temperature vs. Z for Different c Values')
plt.xlabel('Mixture Fraction (Z)')
plt.ylabel('Temperature (K)')
plt.xlim(0,1)
plt.ylim(500,3500)
plt.yticks([500,800,1000,1500,2000,2500,3000,3500])
plt.legend()
plt.show()

# Plot the reaction rate vs. Z for different combustion progresses
plot1 = []
plot2 = []
for z in Zs:
    for c in [1/3,2/3]:
        if c == 1/3:
            plot1.append(W(z,c))
        if c == 2/3:
            plot2.append(W(z,c))
plt.figure(figsize=(10,8))
plt.plot(Zs,plot1,'r-',label='c = 1/3')
plt.plot(Zs,plot2,'b-',label='c = 2/3')
plt.title('Reaction Rate vs. Z for Different c Values')
plt.xlabel('Mixture Fraction (Z)')
plt.ylabel('W (1/s)')
plt.xlim(0,1)
plt.legend()
plt.show()

# Flamelet Model

# Task 1

nZ = 101
dZ = 1/(nZ-1)
Z_values = np.linspace(0,1,nZ)

# Define flamelet model that output the steady-state mass fractions for a given
# Nst
def flamelet_model(Nst):

    W_max = 500
    # Set time-step and CFL number
    dt = 0.01/W_max
    CFL = dt*Nst/(dZ**2)
    t = 0

    # Initial conditions
    current_Y = np.array([Y_pc(z) for z in Z_values])

    # Initial reaction rates
    current_W = np.zeros(nZ)
    for i in range(1,nZ-1):
        c = current_Y[i]/Y_pc(i*dZ)
        current_W[i] =  W(i*dZ,c)

    # Define implicit coefficient matrix
    implicit_matrix = ((1+2*CFL) * sps.eye(nZ, k=0)
                    -CFL * sps.eye(nZ, k=-1)
                    -CFL * sps.eye(nZ, k=+1))

    # Dirichlet boundary conditions
    B = implicit_matrix.tolil()

    B[0,:], B[nZ-1,:] = 0, 0
    B[0,0], B[nZ-1,nZ-1] = 1, 1

    implicit_matrix = B.tocsr()

    # Begin general updates until steady-state solution is achieved or FO2 goes
    # extinct
    previous_Y = np.zeros(nZ)
    while abs(np.amax(current_Y) - np.amax(previous_Y)) > 1*10**-7:
        t += dt
        previous_Y = current_Y.copy()
        # Use sparse matrix solver
        current_Y = splinalg.spsolve(implicit_matrix,(previous_Y+current_W*dt))

        # Update reaction rates
        for i in range(1,nZ-1):
            c = current_Y[i]/Y_pc(i*dZ)
            current_W[i] = W(i*dZ,c)
    print('Number of time steps used =', t/dt)
    return current_Y

# Task 2

# Show steady-state solution for Nst = 30 (subcritical)
Y_ss = flamelet_model(30)
Ypc = [Y_pc(Z) for Z in Z_values]
plt.figure(figsize=(10,8))
plt.plot(Z_values,Y_ss,'b-',label='Steady-State Solution')
plt.plot(Z_values,Ypc,'r--',label='Y_pc(Z)')
plt.title('Mass Fraction of FO2 vs. Mixture Fraction for Nst = 30')
plt.xlabel('Mixture Fraction (Z)')
plt.ylabel('Mass Fraction (Y)')
plt.xlim(0,1)
plt.ylim(0,0.4)
plt.legend()
plt.show()

# Task 3

# Golden ratio
gr = (math.sqrt(5) + 1) / 2

# Define Golden-Section Search function
def gss(f, a, b, tol=0.01):
    # Find initial c and d values
    c = b - (b - a) / gr
    d = a + (b - a) / gr
    while abs(b - a) > tol:
        # If f(c) goes to extinction, return 100
        if np.amax(f(c)) < 10**-3:
            x = 100
        # If f(c) reaches steady-state, return max Y_FO2
        else:
            x = np.amax(f(c))
        # If f(d) goes to extinction, return 100
        if np.amax(f(d)) < 10**-3:
            y = 100
        # If f(d) reaches steady-state, return max Y_FO2
        else:
            y = np.amax(f(d))
        # When f(c) and f(d) go to extinction, a = a, b = c
        if x and y == 100:
            b = c
            c = b - (b - a) / gr
            d = a + (b - a) / gr
            continue
        # When f(c) and f(d) both have a steady solution, a = d, b = b
        if x and y > 10**-3:
            a = d
            c = b - (b - a) / gr
            d = a + (b - a) / gr
            continue
        # If f(c) < f(d), b = d, a = a
        if x < y:
            b = d
        else:
            a = c

        c = b - (b - a) / gr
        d = a + (b - a) / gr

    return (b + a) / 2

#print(gss(flamelet_model,50.5,51,tol=0.01))

# ^^ uncomment this if you want to see the golden search result
# It takes roughly 5 mins to run though

# Critical value found form golden search
Ncr = 50.64387
print('Ncr =',Ncr)

# Plot critical solution
Y_ss = flamelet_model(Ncr)
Ypc = [Y_pc(Z) for Z in Z_values]
plt.figure(figsize=(10,8))
plt.plot(Z_values,Y_ss,'b-',label='Steady-State Solution')
plt.plot(Z_values,Ypc,'r--',label='Y_pc(Z)')
plt.title('Mass Fration of FO2 vs. Mixture Fraction for Ncr')
plt.xlabel('Mixture Fraction (Z)')
plt.ylabel('Mass Fraction (Y)')
plt.xlim(0,1)
plt.ylim(0,0.4)
plt.legend()
plt.show()

# Plot critical temperatures
Temps = np.zeros(nZ)
Temps[0] = T(0,0)
Temps[nZ-1] = T(1,0)
for i in range(1,nZ-1):
    c = Y_ss[i]/Y_pc(i*dZ)
    Temps[i] = T(i*dZ,c)
T_a = np.amax(Temps)
plt.figure(figsize=(10,8))
plt.plot(Z_values,Temps,'b-')
plt.plot([0,1],[T_a,T_a],'r--')
plt.title('Temperature vs. Mixture Fraction')
plt.xlabel('Mixture Fraction (Z)')
plt.ylabel('Temperature (K)')
plt.xlim(0,1)
plt.ylim(750,3000)
plt.yticks([750,1000,1250,1500,1750,2000,2250,2500,2750,2812.34,3000])
plt.show()

print('Adiabatic Temp =',T_a)

# Task 4

# Find residence time
t_res = (Zavg - Zavg**2)/(2*Ncr)

print('Residence Time =',t_res)


from treenode import TreeNode
from tree_builder import build_tree, get_node
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        """use dfs to build path between root and given node"""
        def traverse(v, w, a):
            a.append(w)
            if v is w:
                return True
            if w.left and traverse(v, w.left, a):
                return True
            if w.right and traverse(v, w.right, a):
                return True
            a.pop()
            return False

        a = []
        b = []
        traverse(p,root,a)
        traverse(q,root,b)
        for u,v in zip(a,b):
            if u is v:
                res = u
            else:
                break
        return res.val

tree = build_tree([3,5,1,6,2,0,8,None,None,7,4])
pp,qq=5,1
pp=get_node(tree,pp)
qq=get_node(tree,qq)
assert Solution().lowestCommonAncestor(tree,pp,qq) == 3
# pp,qq=5,4
# pp=get_node(tree,pp)
# qq=get_node(tree,qq)
# assert Solution().lowestCommonAncestor(tree,pp,qq) == 5


import threading
import time

# 使用线程来执行类的成员函数，则类必须定义run方法，并且必须继承threading类
# 调用start的时候，自动调用run方法，run方法结束了，那么线程也结束了
class MyThread(threading.Thread):
    def run(seft):
        for i in range(3):
            time.sleep(1)
            msg = "I'm " + seft.name + ' @ ' + str(i)
            print(msg)

if __name__ == "__main__":
    t = MyThread()
    t.start()


from player import *
from gameMap import *
from creature import *
from item import *
from treasure import *
import random as r

fullMap = []
newMap = gameMap(20,20, fullMap)
newPlayer = Player(2, 9, 9, 20, 5, "P")
running = True
numCreatures = 10
numTreasure = 30
numLocked = r.randint(0, numTreasure)
numOpen = numTreasure - numLocked

atkItem = r.randint(0, numTreasure)
hpItem  = numTreasure - atkItem

hostCreatures = r.randint(0, numCreatures)
passiveCreatures = numCreatures - hostCreatures

creatures = []
treasures = []
items = []

for i in range(hostCreatures):
    creatures.append(Creature(r.randint(0,19), r.randint(0,19), r.randint(2,15), r.randint(1,10), True, "C"))

for i in range(passiveCreatures):
    creatures.append(Creature(r.randint(0,19), r.randint(0,19), r.randint(2,15), r.randint(1,10), False, "C"))

for i in range(atkItem):
    items.append(attackMod(r.randint(-3, 3)))

for i in range(hpItem):
    items.append(healthMod(r.randint(-10, 10)))

for i in range(numLocked):
    treasures.append(Treasure(r.randint(0,19), r.randint(0,19), r.randint(2,15), True, "T", items[0]))
    items.pop(0)

for i in range(numOpen):
    treasures.append(Treasure(r.randint(0,19), r.randint(0,19), r.randint(2,15), False, "T", items[0]))
    items.pop(0)

def checkMapItems(creatureList, treasureList):
    for a in creatureList:
        for b in treasureList:
            if a.x == b.x and a.y == b.y:
                a.x += 1

def playerPosition(mapList, player):
    posy = mapList.map[player.y]
    posy[player.x] = player.symbol

def creaturePosition(mapList, player, creatureList):
    for i in creatureList:
        if i.alive == True:
            if i.x == player.x:
                if i.y == player.y:
                    i.x += 1
            posy = mapList.map[i.y]
            posy[i.x] = i.symbol
        if i.alive == False:
            creatureList.remove(i)

def treasurePosition(mapList, player, treasureList):
    for i in treasureList:
        if i.open == False:
            if i.x == player.x:
                if i.y == player.y:
                    i.x += 1
            posy = mapList.map[i.y]
            posy[i.x] = i.symbol
        if i.open == True:
            i.giveItem(newPlayer)
            treasureList.remove(i)

newMap.createMap()

print("Welcome to this short interaction game")
input("Input anything to start!: ")

def update():
    while running == True:
        newMap.clearOld()
        checkMapItems(creatures, treasures)
        playerPosition(newMap, newPlayer)
        creaturePosition(newMap, newPlayer, creatures)
        treasurePosition(newMap, newPlayer, treasures)
        newMap.showMap()
        print("P = Player, C = Creature, T = Treasure")
        print("Health: " + str(newPlayer.health))
        print("Damage: " + str(newPlayer.damage))
        print("Input Left, Right, Up or Down to move")
        print("Input anything else to skip")
        movement = input("Input: ")
        if movement.upper() == "LEFT":
            newPlayer.x -= 1
        if movement.upper() == "RIGHT":
            newPlayer.x += 1
        if movement.upper() == "UP":
            newPlayer.y -= 1
        if movement.upper() == "DOWN":
            newPlayer.y += 1
        else:
            pass

        print("Input Attack or Interact")
        action = input("Input: ")
        print("Input Direction (Left, Right, Up or Down)")
        direction = input("Direction: ")
        if action.upper() == "ATTACK":
            if direction.upper() == "LEFT":
                for i in creatures:
                    if i.x == newPlayer.x - 1 and i.y == newPlayer.y:
                        i.health -= newPlayer.damage
                        print("Creature Health Remaining:" + str(i.health))
                        i.update()
                for i in treasures:
                    if i.x == newPlayer.x - 1 and i.y == newPlayer.y:
                        i.health -= newPlayer.damage
                        print("Treasure Health Remaining:" + str(i.health))
                        i.update()
            if direction.upper() == "RIGHT":
                for i in creatures:
                    if i.x == newPlayer.x + 1 and i.y == newPlayer.y:
                        i.health -= newPlayer.damage
                        print("Creature Health Remaining:" + str(i.health))
                        i.update()
                for i in treasures:
                    if i.x == newPlayer.x + 1 and i.y == newPlayer.y:
                        i.health -= newPlayer.damage
                        print("Treasure Health Remaining:" + str(i.health))
                        i.update()
            if direction.upper() == "UP":
                for i in creatures:
                    if i.x == newPlayer.x and i.y == newPlayer.y - 1:
                        i.health -= newPlayer.damage
                        print("Creature Health Remaining:" + str(i.health))
                        i.update()
                for i in treasures:
                    if i.x == newPlayer.x and i.y == newPlayer.y - 1:
                        i.health -= newPlayer.damage
                        print("Treasure Health Remaining:" + str(i.health))
                        i.update()
            if direction.upper() == "DOWN":
                for i in creatures:
                    if i.x == newPlayer.x and i.y == newPlayer.y + 1:
                        i.health -= newPlayer.damage
                        print("Creature Health Remaining:" + str(i.health))
                        i.update()
                for i in treasures:
                    if i.x == newPlayer.x and i.y == newPlayer.y + 1:
                        i.health -= newPlayer.damage
                        print("Treasure Health Remaining:" + str(i.health))
                        i.update()
        if action.upper() == "INTERACT":
            if direction.upper() == "LEFT":
                for i in creatures:
                    if i.x == newPlayer.x - 1 and i.y == newPlayer.y:
                        i.interact(newPlayer)

                for i in treasures:
                    if i.x == newPlayer.x - 1 and i.y == newPlayer.y:
                        i.tryOpen()
                        i.update()
                        i.giveItem(newPlayer)

            if direction.upper() == "RIGHT":
                for i in creatures:
                    if i.x == newPlayer.x + 1 and i.y == newPlayer.y:
                        i.interact(newPlayer)
                for i in treasures:
                    if i.x == newPlayer.x + 1 and i.y == newPlayer.y:
                        i.tryOpen()
                        i.update()
                        i.giveItem(newPlayer)

            if direction.upper() == "UP":
                for i in creatures:
                    if i.x == newPlayer.x and i.y == newPlayer.y - 1:
                        i.interact(newPlayer)
                for i in treasures:
                    if i.x == newPlayer.x and i.y == newPlayer.y - 1:
                        i.tryOpen()
                        i.update()
                        i.giveItem(newPlayer)

            if direction.upper() == "DOWN":
                for i in creatures:
                    if i.x == newPlayer.x and i.y == newPlayer.y + 1:
                        i.interact(newPlayer)
                for i in treasures:
                    if i.x == newPlayer.x and i.y == newPlayer.y + 1:
                        i.tryOpen()
                        i.update()
                        i.giveItem(newPlayer)

        else:
            pass

update()

#def (target, posx, posy)


"""Helpers for tests."""
import json

import pytest

from .common import MQTTMessage

from tests.async_mock import patch
from tests.common import load_fixture

@pytest.fixture(name="generic_data", scope="session")
def generic_data_fixture():
    """Load generic MQTT data and return it."""
    return load_fixture("ozw/generic_network_dump.csv")

@pytest.fixture(name="light_data", scope="session")
def light_data_fixture():
    """Load light dimmer MQTT data and return it."""
    return load_fixture("ozw/light_network_dump.csv")

@pytest.fixture(name="sent_messages")
def sent_messages_fixture():
    """Fixture to capture sent messages."""
    sent_messages = []

    with patch(
        "homeassistant.components.mqtt.async_publish",
        side_effect=lambda hass, topic, payload: sent_messages.append(
            {"topic": topic, "payload": json.loads(payload)}
        ),
    ):
        yield sent_messages

@pytest.fixture(name="light_msg")
async def light_msg_fixture(hass):
    """Return a mock MQTT msg with a light actuator message."""
    light_json = json.loads(
        await hass.async_add_executor_job(load_fixture, "ozw/light.json")
    )
    message = MQTTMessage(topic=light_json["topic"], payload=light_json["payload"])
    message.encode()
    return message

@pytest.fixture(name="switch_msg")
async def switch_msg_fixture(hass):
    """Return a mock MQTT msg with a switch actuator message."""
    switch_json = json.loads(
        await hass.async_add_executor_job(load_fixture, "ozw/switch.json")
    )
    message = MQTTMessage(topic=switch_json["topic"], payload=switch_json["payload"])
    message.encode()
    return message

@pytest.fixture(name="sensor_msg")
async def sensor_msg_fixture(hass):
    """Return a mock MQTT msg with a sensor change message."""
    sensor_json = json.loads(
        await hass.async_add_executor_job(load_fixture, "ozw/sensor.json")
    )
    message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
    message.encode()
    return message

@pytest.fixture(name="binary_sensor_msg")
async def binary_sensor_msg_fixture(hass):
    """Return a mock MQTT msg with a binary_sensor change message."""
    sensor_json = json.loads(
        await hass.async_add_executor_job(load_fixture, "ozw/binary_sensor.json")
    )
    message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
    message.encode()
    return message

@pytest.fixture(name="binary_sensor_alt_msg")
async def binary_sensor_alt_msg_fixture(hass):
    """Return a mock MQTT msg with a binary_sensor change message."""
    sensor_json = json.loads(
        await hass.async_add_executor_job(load_fixture, "ozw/binary_sensor_alt.json")
    )
    message = MQTTMessage(topic=sensor_json["topic"], payload=sensor_json["payload"])
    message.encode()
    return message


# 투포인터
def trap(heights):
    if not heights:
        return 0

    volume = 0
    left, right = 0, len(heights)-1
    left_max, right_max = heights[left], heights[right]

    while left <= right:
        left_max, right_max = max(heights[left], left_max), max(
            heights[right], right_max)

        # 더 높은쪽으로 이동
        if left_max <= right_max:
            volume += left_max - heights[left]
            left += 1
        else:
            volume += right_max - heights[right]
            right -= 1
    return volume

# 스택

def trap2(heights):
    stack = []  # 인덱스 추가
    volume = 0

    for i in range(len(heights)):
        # 변곡점 만나는 경우
        while stack and heights[i] > heights[stack[-1]]:
            # 스택에서 꺼내기
            top = stack.pop()

            # 스택이 없으면 종료
            if not len(stack):
                break

            # 이전과의 차이만큼 물높이 처리
            distance = i - stack[-1] - 1
            waters = min(heights[i], heights[stack[-1]]) - heights[top]

            volume += distance * waters

        stack.append(i)
    return volume


import sys
import pygame
from setting import Settings
from setting import Ship
import game_functions as gf

def run_game():
    # Initialize game and create a screen object.
    pygame.init()

    ai_settings = Settings()

    screen = pygame.display.set_mode(
        (ai_settings.screen_width, ai_settings.screen_height))
    ship = Ship(screen)
    pygame.display.set_caption("Andy and Mr. Umair's Rocket game")
    bg_color = (30,67,78)
    # Start the main loop for the game.
    while True:
        gf.check_events(ship)
        ship.update()
        # Watch for keyboard and mouse events.

        # Make the most recently drawn screen visible.
        gf.update_screen(ai_settings, screen, ship)

run_game()


import pymunk
import pymunk.pygame_util
import pygame
from classes.ammo.ammo_box import AmmoBox
from classes.coin.coin import Coin

import os
import random
import math
from functions.math import get_xys, get_distance

class Enemy:
    def __init__(self, game, space, radius, pos):
        self.game = game
        self.body = pymunk.Body()
        self.body.position = pos
        self.radius = 20
        self.image = pygame.transform.scale(self.original_image, (radius * 2, radius * 2))
        self.rect = self.image.get_rect()
        self.shape = pymunk.Circle(self.body, radius)
        self.shape.collision_type = game.collision_types["ENEMY"]
        self.shape.elasticity = 0.8
        self.shape.friction = 1
        self.shape.mass = radius / 10
        self.shape.color = self.color
        space.add(self.body, self.shape)

        self.health_bar = pygame.surface.Surface((120, 30))
        self.health_bar_size = (120, 30)

        self.s = 3

        # IMPLEMENTING PATH FINDING
        # self.graph = graph
        self.game.graph.A_star(
            self.game.graph.map[round(self.body.position[0] // self.game.TILE_SIZE)][
                round(self.body.position[1] // self.game.TILE_SIZE)],
            self.game.graph.map[round(self.game.player.body.position[0] // self.game.TILE_SIZE)][
                round(self.game.player.body.position[1] // self.game.TILE_SIZE)]
        )
        # print(self.game.graph.A_star(
        #     self.game.graph.map[round(self.body.position[0] // self.game.TILE_SIZE)][
        #         round(self.body.position[1] // self.game.TILE_SIZE)],
        #     self.game.graph.map[round(self.game.player.body.position[0] // self.game.TILE_SIZE)][
        #         round(self.game.player.body.position[1] // self.game.TILE_SIZE)]
        # )[self.game.graph.map[round(self.body.position[0] // self.game.TILE_SIZE)][
        #         round(self.body.position[1] // self.game.TILE_SIZE)]])
        self.path = []
        self.create_path()
        # print(len(self.path))

    def create_path(self):
        routes = self.game.graph.A_star(
            self.game.graph.map[round(self.body.position[0] // self.game.TILE_SIZE)][
                round(self.body.position[1] // self.game.TILE_SIZE)],
            self.game.graph.map[round(self.game.player.body.position[0] // self.game.TILE_SIZE)][
                round(self.game.player.body.position[1] // self.game.TILE_SIZE)]
        )
        node = routes[self.game.graph.map[round(self.game.player.body.position[0] // self.game.TILE_SIZE)][
                round(self.game.player.body.position[1] // self.game.TILE_SIZE)]]
        while node is not None:
            self.path.append(node)
            node = routes[node]
        self.path.pop()

    def move(self):
        # for item in self.path:
        #     x,y = self.game.get_position_by_player((item.x * self.game.TILE_SIZE,
        #                                                        item.y * self.game.TILE_SIZE))
        #     pygame.draw.rect(self.game.window, (0, 255, 0),
        #                      (round(x), round(y), self.game.TILE_SIZE, self.game.TILE_SIZE))
        self.create_path()
        if len(self.path) <= 0:
            return
        xy = (self.path[-1].x * self.game.TILE_SIZE + self.game.TILE_SIZE / 2, self.path[-1].y * self.game.TILE_SIZE + self.game.TILE_SIZE / 2)
        xs, ys = get_xys(self.body.position, xy)
        self.body.position = (self.body.position.x + xs * self.s, self.body.position.y + ys * self.s)
        if get_distance(self.body.position, xy) < self.radius:
            self.path.pop()

    def update(self, game):
        self.rect.center = game.get_position_by_player(self.body.position)
        new_rect = self.image.get_rect(center=self.rect.center)
        game.window.blit(self.image, new_rect)

    def show_hp(self, game):
        pygame.draw.rect(self.health_bar, (0, 0, 0), (0, 0, self.health_bar_size[0], self.health_bar_size[1]))
        pygame.draw.rect(self.health_bar, (35, 189, 26), (2, 2, (self.health_bar_size[0] - 4) * (self.hp / self.max_hp),
                                                          self.health_bar_size[1] - 4))
        x, y = game.get_position_by_player(self.body.position)
        game.window.blit(self.health_bar, (x - 60, y - self.radius * 2 - 10))

    # Call on delete
    def __del__(self):
        if random.random() > 0.6:
            ammo_type = ["light", "medium"][random.randrange(2)]
            self.game.ground_items.append(AmmoBox(self.game, self.body.position, ammo_type, random.randrange(1, 6)))
        for i in range(2):
            self.game.coins.append(Coin(self.game,
                                        (self.body.position.x + 100 * (random.random() - 0.5),
                                         self.body.position.y + (100 * random.random() * 0.5))))
        self.game.space.remove(self.body, self.shape)

    def special_attack(self):
        pass

class BasicEnemy(Enemy):
    color = (255, 250, 0, 100)
    original_image = pygame.image.load(os.path.join("imgs", "basic.png"))
    collision_damage = 5

    spawn_cost = 2

    def __init__(self, game, space, radius, pos):
        super().__init__(game, space, radius, pos)
        self.max_hp = 15
        self.hp = 15


#Brownian Motion Simulator
#Simulate first on $R^1$
import numpy as np
import numpy
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt

def graph(points):

	data = np.array(points)
	fig = plt.figure()
	ax = fig.add_subplot(111)
	ax.scatter(data[:,0],data[:,1])
	ax.set_xlabel("X")
	ax.set_ylabel("Y")
	plt.axis('scaled')
	plt.show()

	return

def run1d(n):
	function = BMinterval(n)
	pointlist = convert(function)
	graph(pointlist)
	return

def grapher(func):
	a = convert(func)
	graph(a)
	return

def convert(func):
	a = []
	for term in func:
		a.append([term, func[term]])
	return a

def BMinterval(n,startpos,starttime):
	#creates a 1-d Brownian motion on $[0,1]$ with $D_n$ dyadic level.

	B = {}
	i = 1
	B[starttime] = startpos
	B[starttime + 1] = startpos + np.random.randn()

	while i < n:
		k = 0
		while 2*k + 1 <= np.power(2,i):
			diadic = float(np.power(2,i))
			d = (2*k + 1) / diadic
			B[starttime + d] = startpos + .5 * ( B[starttime + (d - 1 / diadic)] + B[starttime + (d + 1 / diadic)] - 2*startpos) + .5 * np.random.randn()/ diadic
			k = k + 1
		i = i + 1

	return B

def BM(n,t):
	#creates a depth n brownian motion on [0,t], where t is an integer:
	i = 1
	B = BMinterval(n,0,0)
	while i < t:
		B = dict(B.items() + BMinterval(n, B[i], i).items())
		i = i + 1
	return B

def BM2d(n,t):
	B1 = BM(n,t)
	B2 = BM(n,t)
	list = []
	for term in B1:
		list.append([B1[term],B2[term]])
	return list

def fracpart(number):
	return number - np.floor(number)

def inbox(points):
	##Returns percentage of in points that are (up to ZxZ) in a the box, [0,1/2]x[0,1/2]
	c = 0
	for term in points:
		if (fracpart(term[0]) <= .5) and (fracpart(term[1]) <= .5):
			c = c + 1
	return c / float(len(points))

def fold(points):
	new = []
	for term in points:
		new.append([fracpart(term[0]),fracpart(term[1])])
	return new

def inint(points,k):
	c = 0
	for term in points:
		if (fracpart(points[term])) <= k:
			c = c + 1
	return c / float(len(points))

def fold2(points):
	new = []
	for term in points:
		new.append([fracpart(points[term])])
	return new


#pip3 install wikiepdia-api
#pip3 install elasticsearch
#pip3 install nltk
#pip3 install gensim
#pip3 install pandas
#pip3 install tabulate
import pickle
import wikipediaapi
from model.WikiPage import WikiPage
from elasticsearch import Elasticsearch
import json
from time import sleep
import gensim
from gensim import corpora, models
import nltk
from nltk.stem import WordNetLemmatizer, SnowballStemmer
import pandas as pd
from tabulate import tabulate
nltk.download('stopwords')
nltk.download('wordnet')

wiki = wikipediaapi.Wikipedia('en', extract_format=wikipediaapi.ExtractFormat.WIKI)
index = "ir_project"
es = Elasticsearch()

################################################# PAGES DOWNLOAD AND INDEXING ##########################################

def getPagesfromCategory(category, limit):
    pages = []
    count = 0
    for el in wiki.page(category).categorymembers.values():
        if el.namespace == wikipediaapi.Namespace.MAIN:
            pages.append(WikiPage(el))
            count += 1
            print("{}) {} ".format(count, el))
        if count >= limit:
            break

    print(category + ": download DONE")
    return pages

def setNormalizedCitations(pages):
    numbers = []
    for page in pages:
        numbers.append(page.citations)
    maximum = max(numbers)

    for page in pages:
        page.setCitationsNorm( round((page.citations - 0) / (maximum - 0), 4) )

    return pages

def getAllPages(limit):
    actors = getPagesfromCategory("Category:Golden Globe Award-winning producers", limit)
    guitar_companies = getPagesfromCategory("Category:Guitar manufacturing companies of the United States", limit)
    bands = getPagesfromCategory("Category:Grammy Lifetime Achievement Award winners", limit)
    pages = setNormalizedCitations(actors + guitar_companies + bands)

    # write collection to files
    pages_json = []
    for page in pages:
        pages_json.append(dict(page))

    with open('pages.json', 'w') as f:
            json.dump(pages_json, f, indent=4)

def createIndex(data):
    # read index config from json file
    with open('index-config.json') as f:
        client_body = json.load(f)

    # wipe and create index
    if es.indices.exists(index):
         es.indices.delete(index=index)
    es.indices.create(index=index, ignore=400, body=client_body)

    for page in data:
        es.index(index=index, id=page["url"].replace(" ", "_"), body=page)

############################################## TOPIC MODELING ##########################################################

def lemmatize_stemming(text):
    stemmer = SnowballStemmer('english')
    return stemmer.stem(WordNetLemmatizer().lemmatize(text, pos='v'))

def preprocess(text):
    result = []
    for token in gensim.utils.simple_preprocess(text):
        if token not in gensim.parsing.preprocessing.STOPWORDS and len(token) > 3:
            result.append(lemmatize_stemming(token))
    return result

def getTopics(recalculate):
    with open("pages.json", "r") as read_file:
        data = json.load(read_file)

    corpus = []  # list of strings: list of docs
    for page in data:
        corpus.append(page["abstract"])

    processed_docs = [] # list of lists: list of tokenized docs
    for doc in corpus:
        processed_docs.append(preprocess(doc))

    dictionary = gensim.corpora.Dictionary(processed_docs)
    dictionary.filter_extremes(no_below=5, keep_n=100000)

    if recalculate:
        print("Recalculating topics...")
        bow_corpus = [dictionary.doc2bow(doc) for doc in processed_docs]
        lda_model = gensim.models.LdaMulticore(bow_corpus, num_topics=3, id2word=dictionary, passes=2, workers=2)
        with open("lda_model.pk", 'wb') as pickle_file:
            pickle.dump(lda_model, pickle_file)
    else:
        with open("lda_model.pk", 'rb') as pickle_file:
            lda_model = pickle.load(pickle_file)

    # calculates topic for each document
    final_docs = []
    for page in data:
        document = dictionary.doc2bow(preprocess(page["abstract"]))
        index, score = sorted(lda_model[document], key=lambda tup: -1 * tup[1])[0]
        page["topic"] = index
        final_docs.append(page)

    return(lda_model, final_docs)

################################################## SEARCH ################################################################

def print_results(results):
    df = pd.DataFrame(columns=['score', 'title', "citations", "citations_norm", "topic", "url"])
    for hit in results['hits']['hits']:
        df.loc[len(df)] =[hit['_score'], hit['_source']['title'], hit['_source']['citations'],hit['_source']['citations_norm'], hit['_source']['topic'], hit['_source']['url']]
    print(tabulate(df, headers='keys', tablefmt='psql', showindex=False))

def search(query=None):
    results = es.search(index=index, body={ "from" : 0, "size" : 12, "query": {"match": query}})
    print_results(results)

def search_phrase(query=None):
    results = es.search(index=index, body={"query": {"match_phrase": query}})
    print_results(results)

def search_fuzzy(query):
    results = es.search(index=index, body={"query": {"fuzzy": query}})
    print_results(results)

def search_boolean(query):
    results = es.search(index=index, body={"query": {"bool": query}})
    print_results(results)

def search_with_topic(query, topic):
    results = es.search(index=index, body={"query": {"bool": {"must": { "match": query }, "filter": {"term": {"topic": topic}}}}})
    print_results(results)

def queries_samples():
    print("\nquery: {query: {match: {abstract:is an american pianist}}}")
    print("Notes: it returns both alive and dead pianists (is/was) due to the analyzer")
    search(query={"abstract":"is an american pianist"})

    print("\n\nquery: {query: {match_phrase: {text:was an american pianist}}}")
    print("Notes: it returns only dead pianist")
    search_phrase(query={"text":"was an american pianist"})

    print("\n\nquery: {query: {match_phrase: {text:is an american pianist}}}")
    print("Notes: it returns only alive pianist")
    search_phrase(query={"text":"is an american pianist"})

    print("\n\nquery: {query: {fuzzy: {title: {value: batles}}}}")
    print("Notes: it returns \"The Beatles\" despite the misspelling ")
    search_fuzzy(query={"title": {"value": "batles"}})

    print("\n\nquery: {query: {bool: {must: {match: {abstract: guitarist}},must_not: [{match: {abstract: company}}, {match: {abstract: manufacturer}}],must: {range: {citations_norm: {gt: 0.500}}}}}}")
    print("Notes: it return only guitarists that have a lot of citations in wikiepdia")
    search_boolean(query={"must": {"match": {"abstract": "guitarist"}},
                          "must_not": [{"match": {"abstract": "company"}}, {"match": {"abstract": "manufacturer"}}],
                          "must": {"range": {"citations_norm": {"gt": "0.500"}}}
                          }
                   )

    print("\n\nquery: {query: {bool: {must: {match: {abstract: guitarist}},must: {match: {text: drugs}}}}}")
    print("Notes: it returns all the guitarists that have a relation with drugs")
    search_boolean(query={"must": {"match": {"abstract": "guitarist"}},
                          "must": {"match": {"text": "drugs"}}
                          }
                   )

    print("\n\nquery: { query: {match: {abstract: philanthropist}}}")
    print("Notes: it returns all the philantropist from the corpus. They are all producers")
    search(query={"abstract": "philanthropist"})

    print("\n\nquery:  {query: {match_phrase: {text: philanthropist}}}")
    print("Notes: Since i intentionally declare \"philanthropist\" as synonym of \"rock\" in the text_analyzer filter, this query returns rock stars ")
    search_phrase(query={"text": "philanthropist"})
    print("\n\n")

def menu():
    while True:
        for idx, topic in model.print_topics(-1):
            print('Topic {}: {}'.format(idx, topic))
        print("\ninsert a keyword")
        q = input()
        print("insert topic id")
        topic = input()
        search_with_topic(query={"abstract": q}, topic=topic)
        print("\n\n")

if __name__ == '__main__':
    # getAllPages(100)
    print("please wait for indexing...")
    model, docs = getTopics(False)
    createIndex(docs)
    sleep(5)

    queries_samples()
    menu()


from .utils import get_colors

def show_help_mess(error: bool = False) -> None:
    """Usage: pytrash <param> [param[, param ...]]

    {0}-h, --help{1}
        Print this help message and exit.

    {0}-d, --del <path> [path[ path ...]]{1}
        Move files/dirs to trash (~/.local/share/Trash/).

    {0}-f, --find <pattern>{1}
        Search for files and directories in the trash.

    {0}-r, --restore [pattern]{1}
        Print list of files/dirs on trash with the possibility
        of their recovery. If the pattern is specified, then
        only matches with this pattern are displayed.

    {0}-c, --clear{1}
        Clear trash.

    {0}-s, --size{1}
        Show the size of the trash.
"""

    colors = get_colors()
    if error:
        print(('{0}Wrong parameters.{1} '
               '\'pytrash --help\'{2} for help').format(colors['red'],
                                                        colors['cyan'],
                                                        colors['reset']))
        raise SystemExit

    # show usage
    print(str(show_help_mess.__doc__).format(colors['cyan'], colors['reset']))


class TrainedAI:
    def __init__(self):
        self.playerBase = set()
        self.cheaterLobbies = set()
        self.cheatedPlayers = set()
        self.CheaterData = set()
        self.PlayerData = set()

class NaturalSelectionAI:
    def __init__(self):
        self.Data = set()
        self.Iterations = set()

class Player:
    def __init__(self):
        self.MatchData = set()
        self.Username = ""
        self.Password = ""

def CheckPlayerForCheats(player, selection):
    if player.MatchData == selection.Data:
        return True
    else:
        return False


import os
import argparse

import cv2
import numpy as np
from glob import glob
from PIL import Image

def img2video(video_name):
    filelist = []
    root_dir = video_name
    for (root, dirs, files) in os.walk(root_dir):
        print("root : " + root)
        if len(files) > 0:
            for file_dir in files:
                file_root = root + '/' + file_dir
                #print("file root :" + file_root)
                filelist.append(file_root)
    return filelist

def dataLoader_img(video_name,locateframe):
    filelist = []
    root_dir = video_name
    for (root, dirs, files) in os.walk(root_dir):
        if len(dirs) > 0:
            for dir_name in dirs:
                if dir_name == 'images' :
                    file =  root +'/'+dir_name + '/' + locateframe +'.png'
                    #print(" root : " + file)
                    filelist.append(file)

    return filelist

def dataLoader_focal(video_name,locateframe):
    filelist = []
    root_dir = video_name
    for (root, dirs, files) in os.walk(root_dir):
        #print(" root : " + root)
        if len(dirs) > 0:
            for dir_name in dirs:
                #print(" root : " + dir_name)
                if dir_name == 'focal' :
                    file =  root +'/'+dir_name + '/' + locateframe +'.png'
                    #print(" root : " + file)
                    filelist.append(file)
    return filelist

if __name__ == "__main__":
    video_name = '../siamfc-pytorch/tools/data/NonVideo4_tiny'
    locateframe ='005'
    #dataLoader(locateframe)
    print(dataLoader_img(video_name,locateframe))


import pandas as pd
import numpy as np
import scipy.stats as stats
import pylab as pl
import re
import seaborn as sns

pd.set_option('display.max_columns', 15)
pd.set_option('display.max_rows', 40)

column_types = {
 'Account Number':'int32',
 'Assessment Year': 'int16',
 'Neighbourhood': 'category',
 'Assessed Value':'object'
}

columns = ['Account Number','Assessment Year','Neighbourhood','Assessed Value']
filepath = '\\Coding\\DataAnalystInterview\\AssessmentData.csv'

'''Reduces size from 255mb to ~30mb by converting datatypes and dropping columns'''
Data = pd.read_csv(filepath, usecols = columns, dtype = column_types, header = 0, sep = ',')
Data.rename(columns = {'Assessed Value':'Assessed_Value'}, inplace=True)
Data['Assessed_Value'] = Data.Assessed_Value.str.replace(',','').astype('float').astype('int32')

'''Pivot Table - Neighborhood vs sum of assessments by year'''

NeighbourhoodTable = pd.pivot_table(Data, index = "Neighbourhood", columns = "Assessment Year", values = "Assessed_Value", aggfunc = [np.sum], fill_value = 0)

''' RenamedNeighbourhoods = new or renamed neighborhoods with no assessments in any year from 2012 - 2018'''

RenamedNeighbourhoods = (NeighbourhoodTable[NeighbourhoodTable['sum'].all(axis=1) != True])
NeighbourhoodTable = (NeighbourhoodTable[NeighbourhoodTable['sum'].all(axis=1) != False])

#Reviewed Renamed Neighbourhoods to determine areas that would affect results. These are renamed areas that have high impact missing data
'''Magrath Heights Area - 254848500 in 2012 to Magrath Heights'''
'''Terwillegar South - 1145614500 to 2012 to South Terwillegar'''

NeighbourhoodTable.loc['MAGRATH HEIGHTS', ('sum', 2012)] += 254848500
NeighbourhoodTable.loc['SOUTH TERWILLEGAR', ('sum', 2012)] += 1145614500

'''Table by Percentage Change'''

NeighbourhoodTableChange = NeighbourhoodTable.pct_change(axis=1)
NeighbourhoodTableChange.columns = NeighbourhoodTableChange.columns.droplevel()
del NeighbourhoodTableChange.index.name
del NeighbourhoodTableChange[2012]
NeighbourhoodTableChange.columns = ['2012-2013','2013-2014', '2014-2015', '2015-2016', '2016-2017', '2017-2018']

'''Changes to Neighbourhood Table'''
NeighbourhoodTable = NeighbourhoodTable.xs('sum', axis = 1)
del NeighbourhoodTable.index.name
del NeighbourhoodTable.columns.name

#Sum the Total % Change. Decided not to take the absolute value of change because 5 years increasing steadily is
#very different from 5 years increasing and decreasing but ending in the same place. Check for variation at the end

NeighbourhoodTableChange['Total % Change'] = NeighbourhoodTableChange.sum(axis=1)

NeighbourhoodTableChange = NeighbourhoodTableChange.sort_values(by='Total % Change')
Neighbourhoods = NeighbourhoodTable.mean(axis=1).astype(int)

#NeighbourhoodTable: Table with Raw Assessment Values and Sum of all Assessment Values for Neighbourhoods with data from 2012-2018
NeighbourhoodTable.to_csv(r'\\Coding\\DataAnalystInterview\\NeighbourhoodAssessments.csv')

#RenamedNeighbourhoodsL: Table with Raw Assessment Values of Neighbourhoods with missing 2012 - 2018 data
RenamedNeighbourhoods.to_csv(r'\\Coding\\DataAnalystInterview\\RenamedNeighbourhoods.csv')

#NeighbourhoodTableChange: Table with %Change in all years with data and Standard Deviation
NeighbourhoodTableChange.to_csv(r'\\Coding\\DataAnalystInterview\\NeighbourhoodTableChange.csv')

#Neighbourhoods: Table with Average Assessments from 2012-2018 in each Neighborhood to segment the analysis
Neighbourhoods.to_csv(r'\\Coding\\DataAnalystInterview\\Neighbourhoods.csv')

'''print (NeighbourhoodTable.info())'''
'''print (NeighbourhoodTable)'''
'''print (NeighbourhoodTable.std(axis=1))'''
'''print (Data.loc[Data['Neighbourhood'] == 'MACTAGGART AREA'])'''
'''print (set(Data['Neighbourhood']))'''
'''RenamedNeighbourhoods = (NeighbourhoodTable['sum'][:] != 0).all(axis=1).dropna()'''
#NeighbourhoodTable.to_csv(r'C:\Users\aviel\Desktop\Coding\Data Analyst Interview\NeighbourhoodAssessments.csv')
#RenamedNeighbourhoods.to_csv(r'C:\Users\aviel\Desktop\Coding\Data Analyst Interview\RenamedNeighbourhoods.csv')


import requests
import time
import json
from hoshino import aiorequests

apiroot = 'https://help.tencentbot.top'

async def getprofile(viewer_id: int, interval: int = 1, full: bool = False) -> dict:
    reqid = json.loads(await aiorequests.get(f'{apiroot}/enqueue?full={full}&target_viewer_id={viewer_id}').content.decode('utf8'))['reqeust_id']

    if reqid is None:
        return "id err"

    while True:
        query = json.loads(await aiorequests.get(f'{apiroot}/query?request_id={reqid}').content.decode('utf8'))
        status = query['status']
        if status == 'done':
            return query['data']
        elif status == 'queue':
            time.sleep(interval)
        else: # notfound or else
            return "queue"

async def queryarena(defs: list, page: int) -> dict:
    return json.loads(await aiorequests.get(f'{apiroot}/arena?def={",".join([str(x) for x in defs])}&page={page}').content.decode('utf8'))