from pygame import *
from pacman import Pacman
from nodes import NodeGroup
from pellets import PelletGroup
from ghosts import *
from fruit import Fruit
from pauser import Pauser
from text import TextGroup
from sprites import Spritesheet
from maze import Maze
from portal import *
from levels import *
from button import *

class GameController(object):
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode(SCREENSIZE, 0, 32)
        self.background = None
        self.background_flash = None
        self.setBackground()
        self.clock = pygame.time.Clock()
        self.pelletsEaten = 0
        self.fruit = None
        self.pause = Pauser(True)
        self.text = TextGroup()
        self.score = 0
        self.gameover = False
        self.sheet = Spritesheet()
        self.maze = Maze(self.sheet)
        self.flashBackground = False
        self.portal = None
        self.portal2 = None
        self.portal3 = None
        self.portal4 = None
        self.level = LevelController()
        self.mainScreen = True
        self.gameScreen = False
        self.hsScreen = False
        self.eat_sound = pygame.mixer.Sound("pacman_chomp.wav")
        self.main_menu_sound = pygame.mixer.Sound("pacman_intermission.wav")
        self.beginning_sound = pygame.mixer.Sound("pacman_beginning.wav")
        self.eat_fruit = pygame.mixer.Sound("pacman_eatfruit.wav")
        self.eat_ghost = pygame.mixer.Sound("pacman_eatghost.wav")
        self.death_sound = pygame.mixer.Sound("pacman_death.wav")

    def setBackground(self):
        self.background = pygame.surface.Surface(SCREENSIZE).convert()
        self.background_flash = pygame.surface.Surface(SCREENSIZE).convert()
        self.background.fill(BLACK)

    def startGame(self):
        print("Start game")
        self.level.reset()
        self.maze.getMaze("maze")
        self.maze.constructMaze(self.background, self.background_flash, 0)
        self.nodes = NodeGroup("maze.txt")
        self.pellets = PelletGroup("maze.txt")
        self.pacman = Pacman(self.nodes, self.sheet)
        self.ghosts = GhostGroup(self.nodes, self.sheet)
        self.pelletsEaten = 0
        self.fruit = None
        self.pause.force(True)
        self.text.showReady()
        self.gameover = False
        self.maze.reset()
        self.flashBackground = False
        self.text.updateLevel(self.level.level + 1)
        self.portal = None
        self.portal2 = None
        self.portal3 = None
        self.portal4 = None

    def startLevel(self):
        print("Start game")
        self.setBackground()
        self.maze.getMaze("maze")
        self.maze.constructMaze(self.background, self.background_flash, 0)
        self.nodes = NodeGroup("maze.txt")
        self.pellets = PelletGroup("maze.txt")
        self.pacman.nodes = self.nodes
        self.pacman.reset()
        self.ghosts = GhostGroup(self.nodes, self.sheet)
        self.pelletsEaten = 0
        self.text.updateLevel(self.level.level+1)
        self.fruit = None
        self.pause.force(True)
        self.flashBackground = False
        self.maze.reset()
        self.portal = None
        self.portal2 = None
        self.portal3 = None
        self.portal4 = None

    def resolveLevelClear(self):
        self.level.nextLevel()
        self.startLevel()
        self.pause.pauseType = None

    def restartLevel(self):
        print("Restart game")
        self.pacman.reset()
        self.ghosts = GhostGroup(self.nodes, self.sheet)
        self.pause.force(True)
        self.fruit = None
        self.flashBackground = False
        self.maze.reset()
        # self.portal = None  # commented so portals dont disappear on reset/death
        # self.portal2 = None
        # self.portal3 = None
        # self.portal4 = None

    def update(self):
        if not self.gameover:
            dt = self.clock.tick(30) / 1000.0
            if not self.pause.paused:
                self.pacman.update(dt)
                self.ghosts.update(dt, self.pacman)
                if self.fruit is not None:
                    self.fruit.update(dt)

                if self.portal is not None:
                    self.portal.update(dt)
                    self.portal2.update(dt)
                if self.portal3 is not None:
                    self.portal3.update(dt)
                    self.portal4.update(dt)

                if self.pause.pauseType != None:
                    self.pause.settlePause(self)

                self.checkPelletEvents()
                self.checkGhostEvents()
                self.checkFruitEvents()
                self.checkPortalEvents()

            else:
                if self.flashBackground:
                    self.maze.flash(dt)

                if self.pacman.animateDeath:
                    self.pacman.updateDeath(dt)

            self.pause.update(dt)
            self.pellets.update(dt)
            self.text.update(dt)
        self.checkEvents()
        self.text.updateScore(self.score)
        self.render()

    def checkEvents(self):
        for event in pygame.event.get():
            if event.type == QUIT:
                if self.score > 0:
                    with open("high_scores.txt", 'a') as f:
                        f.write(f'Highscore was {game.score}\n')
                exit()
            elif event.type == KEYDOWN:
                if event.key == K_SPACE:
                    if self.gameover:
                        self.startGame()
                    else:
                        self.pause.player()
                        if self.pause.paused:
                            self.text.showPause()
                        else:
                            self.text.hideMessages()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                mouse_x, mouse_y = pygame.mouse.get_pos()
                if self.play_button.rect.collidepoint(mouse_x, mouse_y):
                    self.mainScreen = False
                    self.gameScreen = True
                elif self.score_button.rect.collidepoint(mouse_x, mouse_y):
                    self.mainScreen = False
                    self.hsScreen = True
                elif self.back_button.rect.collidepoint(mouse_x, mouse_y):
                    self.mainScreen = True
                    self.hsScreen = False

    def checkPelletEvents(self):
        pellet = self.pacman.eatPellets(self.pellets.pelletList)
        if pellet:
            self.eat_sound.set_volume(0.2)
            self.eat_sound.play()
            self.pelletsEaten += 1
            self.score += pellet.points
            if self.pelletsEaten == 25 or self.pelletsEaten == 150:
                if self.fruit is None:
                    self.fruit = Fruit(self.nodes, self.sheet, "cherry")
            if self.pelletsEaten == 75:
                if self.portal is None:
                    self.portal = Portal(self.nodes, self.sheet)
                if self.portal2 is None:
                    self.portal2 = Portal(self.nodes, self.sheet)
            if self.pelletsEaten == 125:
                if self.portal3 is None:
                    self.portal3 = Portal2(self.nodes, self.sheet)
                if self.portal4 is None:
                    self.portal4 = Portal2(self.nodes, self.sheet)
            self.pellets.pelletList.remove(pellet)
            if pellet.name == "powerpellet":
                self.ghosts.resetPoints()
                self.ghosts.freightMode()
            if self.pellets.isEmpty():
                self.pacman.visible = False
                self.ghosts.hide()
                self.pause.startTimer(3, "clear")
                self.flashBackground = True

    def checkGhostEvents(self):
        self.ghosts.release(self.pelletsEaten)
        ghost = self.pacman.eatGhost(self.ghosts)
        if ghost is not None:
            if ghost.mode.name == "FREIGHT":
                self.eat_ghost.set_volume(0.2)
                self.eat_ghost.play()
                self.score += ghost.points
                self.text.createTemp(ghost.points, ghost.position)
                self.ghosts.updatePoints()
                ghost.spawnMode(speed=2)
                self.pause.startTimer(1)
                self.pacman.visible = False
                ghost.visible = False

            elif ghost.mode.name != "SPAWN":
                self.death_sound.set_volume(0.2)
                self.death_sound.play()
                self.pacman.loseLife()
                self.ghosts.hide()
                self.pause.startTimer(3, "die")

    def checkFruitEvents(self):
        if self.fruit is not None:
            if self.pacman.eatFruit(self.fruit):
                self.eat_fruit.set_volume(0.2)
                self.eat_fruit.play()
                self.score += self.fruit.points
                self.text.createTemp(self.fruit.points, self.fruit.position)
                self.fruit = None

            elif self.fruit.destroy:
                self.fruit = None

    def checkPortalEvents(self):
        if self.portal is not None:
            if self.pacman.enterPortal(self.portal):
                b = self.nodes.getNode(19*TILEWIDTH, 4*TILEHEIGHT, self.nodes.nodeList)
                self.pacman.node = b
                self.pacman.setPosition()
                self.pacman.direction = STOP
            elif self.portal.destroy:
                self.portal = None

        if self.portal2 is not None:
            if self.pacman.enterPortal(self.portal2):
                b = self.nodes.getNode(3*TILEWIDTH, 32*TILEHEIGHT, self.nodes.nodeList)
                self.pacman.node = b
                self.pacman.setPosition()
                self.pacman.direction = STOP
            elif self.portal2.destroy:
                self.portal2 = None

        if self.portal3 is not None:
            if self.pacman.enterPortal(self.portal3):
                b = self.nodes.getNode(21*TILEWIDTH, 32*TILEHEIGHT, self.nodes.nodeList)
                self.pacman.node = b
                self.pacman.setPosition()
                self.pacman.direction = STOP
            elif self.portal3.destroy:
                self.portal3 = None

        if self.portal4 is not None:
            if self.pacman.enterPortal(self.portal4):
                b = self.nodes.getNode(5*TILEWIDTH, 4*TILEHEIGHT, self.nodes.nodeList)
                self.pacman.node = b
                self.pacman.setPosition()
                self.pacman.direction = STOP
            elif self.portal4.destroy:
                self.portal4 = None

    def resolveDeath(self):
        if self.pacman.lives == 0:
            self.gameover = True
            self.pacman.visible = False
            self.text.showGameOver()
        else:
            self.restartLevel()
        self.pause.pauseType = None

    def render(self):
        self.screen.blit(self.maze.background, (0,0))
        #self.nodes.render(self.screen)
        self.pellets.render(self.screen)
        if self.fruit is not None:
            self.fruit.render(self.screen)
        if self.portal is not None:
            self.portal.render(self.screen)
        if self.portal2 is not None:
            self.portal2.render(self.screen)
        if self.portal3 is not None:
            self.portal3.render(self.screen)
        if self.portal4 is not None:
            self.portal4.render(self.screen)
        self.pacman.render(self.screen)
        self.ghosts.render(self.screen)
        self.pacman.renderLives(self.screen)
        self.text.render(self.screen)
        pygame.display.update()

    def main_screen_ani(self, current_time):
        if current_time <= 0.5:
            self.screen.blit(self.sheet.getImage(4, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
        elif 0.5 < current_time <= 1:
            self.screen.blit(self.sheet.getImage(1, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (3*TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
        elif 1 < current_time <= 1.5:
            self.screen.blit(self.sheet.getImage(1, 1, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
        elif 1.5 < current_time <= 2:
            self.screen.blit(self.sheet.getImage(1, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 2 < current_time <= 2.5:
            self.screen.blit(self.sheet.getImage(4, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (12 * TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 3, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 2.5 < current_time <= 3:
            self.screen.blit(self.sheet.getImage(1, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (15 * TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 3, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 4, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 3 < current_time <= 3.5:
            self.screen.blit(self.sheet.getImage(1, 1, TILEWIDTH * 2, TILEHEIGHT * 2), (18 * TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 3, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 4, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 5, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 3.5 < current_time <= 4:
            self.screen.blit(self.sheet.getImage(1, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (21 * TILEWIDTH, 18 * TILEHEIGHT))
            pygame.draw.circle(self.screen, WHITE, (25 * TILEWIDTH, 19.2 * TILEHEIGHT), 8)
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (12 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 3, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 4, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 5, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
        elif 4 < current_time <= 4.5:
            self.screen.blit(self.sheet.getImage(4, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (23 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (15 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 3, TILEWIDTH * 2, TILEHEIGHT * 2), (12 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 4, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(6, 5, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
        elif 4.5 < current_time <= 5:
            self.screen.blit(self.sheet.getImage(0, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (23 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (15 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (12 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
        elif 5 < current_time <= 5.5:
            self.screen.blit(self.sheet.getImage(0, 1, TILEWIDTH * 2, TILEHEIGHT * 2), (21 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (12 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
        elif 5.5 < current_time <= 6:
            self.screen.blit(self.sheet.getImage(0, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (18 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 6 < current_time <= 6.5:
            self.screen.blit(self.sheet.getImage(4, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (15 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 6.5 < current_time <= 7:
            self.screen.blit(self.sheet.getImage(0, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (12 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(0, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 7 < current_time <= 7.5:
            self.screen.blit(self.sheet.getImage(0, 1, TILEWIDTH * 2, TILEHEIGHT * 2), (9 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(self.sheet.getImage(2, 6, TILEWIDTH * 2, TILEHEIGHT * 2), (TILEWIDTH, 18 * TILEHEIGHT))
        elif 7.5 < current_time <= 8:
            self.screen.blit(self.sheet.getImage(0, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (6 * TILEWIDTH, 18 * TILEHEIGHT))
        elif 8 < current_time <= 8.5:
            self.screen.blit(self.sheet.getImage(4, 0, TILEWIDTH * 2, TILEHEIGHT * 2), (3 * TILEWIDTH, 18 * TILEHEIGHT))
        elif 9 < current_time <= 11:
            self.screen.blit(self.sheet.getImage(6, 2, TILEWIDTH * 2, TILEHEIGHT * 2), (21 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(pygame.image.load('blinky_text.png'), (10 * TILEWIDTH, 15 * TILEHEIGHT))
        elif 11 < current_time <= 13:
            self.screen.blit(self.sheet.getImage(6, 3, TILEWIDTH * 2, TILEHEIGHT * 2), (21 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(pygame.image.load('pinky_text.png'), (10 * TILEWIDTH, 15 * TILEHEIGHT))
        elif 13 < current_time <= 15:
            self.screen.blit(self.sheet.getImage(6, 4, TILEWIDTH * 2, TILEHEIGHT * 2), (21 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(pygame.image.load('inkey_text.png'), (10 * TILEWIDTH, 15 * TILEHEIGHT))
        elif 15 < current_time <= 17:
            self.screen.blit(self.sheet.getImage(6, 5, TILEWIDTH * 2, TILEHEIGHT * 2), (21 * TILEWIDTH, 18 * TILEHEIGHT))
            self.screen.blit(pygame.image.load('clyde_text.png'), (10 * TILEWIDTH, 15 * TILEHEIGHT))

    def main(self):
        while True:
            if self.mainScreen:
                self.screen.blit(self.background, (0, 0))
                self.play_button = Button(self.screen, 'Play Game', 10 * TILEWIDTH, 29 * TILEHEIGHT, TILEHEIGHT, 9)
                self.score_button = Button(self.screen, 'High Score', 9.5 * TILEWIDTH, 32 * TILEHEIGHT, TILEHEIGHT, 10)
                self.image = pygame.image.load('pacman_title.png')
                self.screen.blit(self.image, (3 * TILEWIDTH, TILEHEIGHT))
                self.timer = pygame.time.get_ticks() / 1000
                self.main_screen_ani(self.timer)
                self.main_menu_sound.set_volume(0.2)
                self.main_menu_sound.play()
                self.play_button.draw()
                self.score_button.draw()
                self.checkEvents()
            elif self.gameScreen:
                game.startGame()
                self.main_menu_sound.stop()
                self.beginning_sound.set_volume(0.2)
                self.beginning_sound.play()
                while True:
                    game.update()
            elif self.hsScreen:
                self.screen.blit(self.background, (0, 0))
                self.row = 0
                self.font = pygame.font.Font("PressStart2P-vaV7.ttf", TILEHEIGHT)
                with open('high_scores.txt') as f:
                    for line in f:
                        temp_string = self.font.render(line, True, WHITE)
                        self.screen.blit(temp_string, (TILEWIDTH, self.row * TILEHEIGHT))
                self.back_button = Button(self.screen, 'Go back', 20 * TILEWIDTH, 29 * TILEHEIGHT, TILEHEIGHT, 7)
                self.back_button.draw()
                self.checkEvents()

            pygame.display.update()
            self.clock.tick(30)

if __name__ == "__main__":
    game = GameController()
    game.main()


import os.path
import io
import pytest
import atop_raw
from atop_raw import utils

def read_data(filename):
    root = os.path.dirname(__file__)
    real_filename = os.path.join(root, "data", filename)
    with open(real_filename, "rb") as f:
        data = f.read()
    return data

def test_read_all_in_right_order():
    data = read_data("atop_1_26_debian8_x86_64.log")
    stream = io.BytesIO(data)
    reader = atop_raw.create_reader(stream)
    for record in reader.records:
        record.header
        record.sstat
        record.pstats

def test_read_all_in_wrong_order():
    data = read_data("atop_1_26_debian8_x86_64.log")
    stream = io.BytesIO(data)
    reader = atop_raw.create_reader(stream)
    for record in reader.records:
        record.pstats
        record.header
        record.sstat

def test_skip_all_records():
    data = read_data("atop_1_26_debian8_x86_64.log")
    stream = io.BytesIO(data)
    reader = atop_raw.create_reader(stream)
    for _record in reader.records:
        pass

def test_processutils():
    data = read_data("atop_1_26_debian8_x86_64.log")
    stream = io.BytesIO(data)
    reader = atop_raw.create_reader(stream)
    for record in reader.records:
        report = utils.ProcessReport(reader, record.sstat)
        for pstat in record.pstats:
            cpu = report.get_cpu_percent(pstat)
            mem = report.get_mem_percent(pstat)
            assert cpu == pytest.approx(0.00742272, abs=0.0001)
            assert mem == pytest.approx(0.03105252, abs=0.0001)
            break
        break


import  variables as gav

from pyspark.sql import SparkSession
from pyspark import SparkConf
import logging
import logging.config

logging.config.fileConfig(fname=gav.config_file_path)
logger = logging.getLogger(__name__)

def get_spark_session():
    """
    This method is used to create spark session.
    :return: spark
    """
    try:
        logger.info("Started get_spark_session().")
        spark_conf = SparkConf()
        spark_conf.set("spark.app.name", "Udemy Analytics")
        spark_conf.set("spark.master", "local[*]")

        spark = SparkSession.builder.config(conf=spark_conf).getOrCreate()

    except Exception as exp:
        logger.error("Error in get_spark_session()..", exc_info=True)
        raise
    else:
        logger.info("Completed get_spark_session().\n")
        return spark


# -*- coding: utf-8 -*-
import os
import sys
from setuptools import setup, find_packages
from setuptools.command.test import test as TestCommand

here = os.path.dirname(os.path.abspath((__file__)))

# meta infos
NAME = "vae_topicmodel"
DESCRIPTION = "VAE topic model"
VERSION = "0.1"

AUTHOR = "foxfi"
EMAIL = "foxdoraame@gmail.com"

# package contents
MODULES = []
PACKAGES = find_packages()

# dependencies
INSTALL_REQUIRES = [
    # "pyyaml==3.12",
    #"tensorflow-gpu==1.2.1",
    # "scikit-learn==0.19.0"
]

# entry points
ENTRY_POINTS = """
[console_scripts]
vae_topic_run=vae_topicmodel.run:main
vae_topic_runtest=vae_topicmodel.run_test:main
vae_image_run=vae_topicmodel.image_run:main
vae_image_runtest=vae_topicmodel.image_run_test:main
"""

def read_long_description(filename):
    path = os.path.join(here, filename)
    if os.path.exists(path):
        return open(path).read()
    return ""

setup(
    name=NAME,
    version=VERSION,
    description=DESCRIPTION,
    long_description=read_long_description("README.md"),
    author=AUTHOR,
    author_email=EMAIL,

    py_modules=MODULES,
    packages=PACKAGES,

    entry_points=ENTRY_POINTS,
    install_requires=INSTALL_REQUIRES
)


import sys
from collections import deque
sys.stdin = open("../input.txt", "rt")

N,M,V = map(int,input().split())

#행렬 만들기
graph = [[0]*(N+1) for _ in range(N+1)]
for i in range (M):
    a,b = map(int,input().split())
    graph[a][b] = graph[b][a] = 1

#방문 리스트 행렬
visited1 = [0]*(N+1)
visited2 = visited1.copy()

#dfs 함수 만들기
def dfs(V):
    visited1[V] = 1 #방문처리
    print(V, end=' ')
    for i in range(1, N+1):
        if graph[V][i] == 1 and visited1[i] == 0:
            dfs(i)

#bfs 함수 만들기
dq = deque()
def bfs(V):
    # queue = [V]
    dq.append(V)
    visited2[V] = 1 #방문처리
    while dq:
        V = dq.popleft() #방문 노드 제거
        print(V, end = ' ')
        for i in range(1, N+1):
            if(visited2[i] == 0 and graph[V][i] == 1):
                dq.append(i)
                visited2[i] = 1 # 방문처리

dfs(V)
print()
bfs(V)


import sys
import cv2
import time
import pyautogui
import configparser
import numpy as np

print('MineFish V2')
print('[V2.0.1]')
print('By Nitro (admin@nitrostudio.dev)\n')

config = configparser.ConfigParser()
config.read('./config.ini')

text = f'./img/{config.get("MineFishV2 Setting", "image").strip()}'

locStart = (int(config.get("MineFishV2 Setting", "starting_x").strip()),int(config.get("MineFishV2 Setting", "starting_y").strip()))
locEnd = (int(config.get("MineFishV2 Setting", "size_x").strip()), int(config.get("MineFishV2 Setting", "size_y").strip()))

def getScreen(p1, p2):
    try:
        img = pyautogui.screenshot(region=p1+p2)
        return img
    except:
        print("[Error] Ignoring an error that occurred while grabbing the screen.")
        return None

def detectImg(image, imgT, precision, p1) :
    imgRGB = np.array(image)

    # Change order into bgr
    b, g, r = cv2.split(imgRGB)
    imgBGR = cv2.merge([r,g,b])

    imgGray = cv2.cvtColor(imgBGR, cv2.COLOR_BGR2GRAY)
    target = cv2.imread(imgT, 0) # cv.IMREAD_GRAYSCALE
    w, h = target.shape[::-1]

    res = cv2.matchTemplate(imgGray, target, cv2.TM_CCOEFF_NORMED)
    position = np.where(res >= precision) # Get Location

    if len(position[0]) == 0:
        return False
    else:
        return True

print("[Info] Initialized completed.")

total = 1
while True:
    img = getScreen(locStart, locEnd)
    if img is None:
        print("[Error] Cannot capture image.")
        sys.exit(0)
        break

    capFalse = detectImg(img, text, 0.7, locStart)
    if capFalse:
        print("[Info] Detected! - Total: " + str(total))
        total += 1
        pyautogui.click(button='right')
        time.sleep(0.5)
        pyautogui.click(button='right')
        time.sleep(4)

    time.sleep(0.15) # delay


"""
Code illustration: 4.07

    this entire file added here

@ Tkinter GUI Application Development Blueprints
"""

import sys
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import *
from tkinter.colorchooser import *
from configparser import ConfigParser
import configurations

class PreferencesWindow():

    def __init__(self, view):
        self.parent = view.parent
        self.fill_preference_colors()
        self.view = view
        self.create_prefereces_window()

    def fill_preference_colors(self):
        self.board_color_1 = configurations.BOARD_COLOR_1
        self.board_color_2 = configurations.BOARD_COLOR_2
        self.highlight_color = configurations.HIGHLIGHT_COLOR

    def set_color_1(self):
        self.board_color_1 = askcolor(initialcolor=self.board_color_1)[-1]

    def set_color_2(self):
        self.board_color_2 = askcolor(initialcolor=self.board_color_2)[-1]

    def set_highlight_color(self):
        self.highlight_color = askcolor(initialcolor=self.highlight_color)[-1]

    def create_prefereces_window(self):
        self.pref_window = Toplevel(self.parent)
        self.pref_window.title("set chess preferences")
        self.create_prefereces_list()
        self.pref_window.transient(self.parent)

    def create_prefereces_list(self):
        Label(self.pref_window, text="Board Color 1").grid(
            row=1, sticky=W, padx=5, pady=5)
        Label(self.pref_window, text="Board Color 2").grid(
            row=2, sticky=W, padx=5, pady=5)
        Label(self.pref_window, text="Highlight Color").grid(
            row=3, sticky=W, padx=5, pady=5)
        self.board_color_1_button = Button(
            self.pref_window, text='Select Board Color 1', command=self.set_color_1)
        self.board_color_1_button.grid(
            row=1, column=1, columnspan=2, sticky=E, padx=5, pady=5)
        self.board_color_2_button = Button(
            self.pref_window, text='Select Board Color 2', command=self.set_color_2)
        self.board_color_2_button.grid(
            row=2, column=1, columnspan=2, sticky=E, padx=5, pady=5)
        self.highlight_color_button = Button(
            self.pref_window, text='Select Highlight Color', command=self.set_highlight_color)
        self.highlight_color_button.grid(
            row=3, column=1, columnspan=2, sticky=E, padx=5, pady=5)
        Button(self.pref_window, text="Save", command=self.on_save_button_clicked).grid(
            row=4, column=2, sticky=E, padx=5, pady=5)
        Button(self.pref_window, text="Cancel", command=self.on_cancel_button_clicked).grid(
            row=4, column=1, sticky=E, padx=5, pady=5)

    def on_save_button_clicked(self):
        self.set_new_values()
        self.pref_window.destroy()
        self.view.reload_colors(
            self.board_color_1, self.board_color_2, self.highlight_color)

    def set_new_values(self):
        config = ConfigParser()
        config.read('chess_options.ini')
        config.set('chess_colors', 'board_color_1', self.board_color_1)
        config.set('chess_colors', 'board_color_2', self.board_color_2)
        config.set('chess_colors', 'highlight_color', self.highlight_color)
        configurations.BOARD_COLOR_1 = self.board_color_1
        configurations.BOARD_COLOR_2 = self.board_color_2
        configurations.HIGHLIGHT_COLOR = self.highlight_color
        with open('chess_options.ini', 'w') as config_file:
            config.write(config_file)

    def on_cancel_button_clicked(self):
        self.pref_window.destroy()


#Identifying the portfolio weights that minimise the Value at Risk (VaR).
#The logic is very similar to the one followed with a Monte Carlo simulation approach
#returns the parametric portfolio VaR to a confidence level determined by the value of the “alpha” argument
#(confidence level will be 1 – alpha), and to a time scale determined by the “days” argument.

import pandas as pd
import numpy as np
from datetime import datetime
from pandas_datareader import data, wb
import matplotlib.pyplot as plt

import scipy.optimize as sco
from scipy import stats

#Select assets
tickers = ['TSLA', 'APHA', 'QQQ', 'AAPL', 'DAL', 'WFC', 'QCOM', 'BAM', 'ROKU']

#Sepecify start and end date
start = datetime(2010, 1, 1)
todayDate = datetime.today().strftime('%Y-%m-%d')

#Create dataframe with asset data
df = pd.DataFrame([data.DataReader(ticker, 'yahoo', start, todayDate)['Adj Close'] for ticker in tickers]).T
df.columns = tickers

def calc_portfolio_perf_VaR(weights, mean_returns, cov, alpha, days):
    portfolio_return = np.sum(mean_returns * weights) * days
    portfolio_std = np.sqrt(np.dot(weights.T, np.dot(cov, weights))) * np.sqrt(days)
    portfolio_var = abs(portfolio_return - (portfolio_std * stats.norm.ppf(1 - alpha)))
    return portfolio_return, portfolio_std, portfolio_var

def simulate_random_portfolios_VaR(num_portfolios, mean_returns, cov, alpha, days):
    results_matrix = np.zeros((len(mean_returns)+3, num_portfolios))
    for i in range(num_portfolios):
        weights = np.random.random_sample(len(mean_returns))
        weights /= np.sum(weights)
        portfolio_return, portfolio_std, portfolio_VaR = calc_portfolio_perf_VaR(weights, mean_returns, cov, alpha, days)
        results_matrix[0,i] = portfolio_return
        results_matrix[1,i] = portfolio_std
        results_matrix[2,i] = portfolio_VaR
        #iterate through the weight vector and add data to results array
        for j in range(len(weights)):
            results_matrix[j+3,i] = weights[j]

    results_df = pd.DataFrame(results_matrix.T,columns=['ret','stdev','VaR'] + [ticker for ticker in tickers])

    return results_df

mean_returns = df.pct_change().mean()
cov = df.pct_change().cov()
num_portfolios = 100000
rf = 0.11
days = 252
alpha = 0.05
results_frame = simulate_random_portfolios_VaR(num_portfolios, mean_returns, cov, alpha, days)

#This time we plot the results of each portfolio with annualised return remaining on the y-axis
#but the x-axis this time representing the portfolio VaR (rather than standard deviation).
#The plot colours the data points according to the value of VaR for that portfolio.

#locate positon of portfolio with minimum VaR
min_VaR_port = results_frame.iloc[results_frame['VaR'].idxmin()]
#create scatter plot coloured by VaR
plt.subplots(figsize=(10,8))
plt.scatter(results_frame.VaR,results_frame.ret,c=results_frame.VaR,cmap='RdYlBu')
plt.xlabel('Value at Risk')
plt.ylabel('Returns')
plt.colorbar()
#plot red star to highlight position of minimum VaR portfolio
plt.scatter(min_VaR_port[2],min_VaR_port[0],marker=(5,1,0),color='r',s=500)

#plt.show()

print(min_VaR_port.to_frame().T)

#Value at Risk (VaR) calculation goes as follos:
# VaR = Rp - (z * SDp)
# Rp = portfolio return
# z = critical t
# Sdp = portfolio standard deviation

#Sharpe ratio calculation goes as follow:
#Sharpe ratio = (Rp - Rf) / SDp
# Rp = portfolio return
# Sdp = portfolio standard deviation
# Rf = Risk free rate (Treasury bill interest rate was used as reference)

#From this we can see that VaR decreases when portfolio returns increase and vice versa
#Whereas the Sharpe ratio increases as portfolio returns increase
#Therefore, what minimises VaR in terms of returns actually maximises the Sharpe ratio.

#Last but not least we introduce a second approach to calculating minimum VaR portfolio
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
def calc_portfolio_VaR(weights, mean_returns, cov, alpha, days):
    portfolio_return = np.sum(mean_returns * weights) * days
    portfolio_std = np.sqrt(np.dot(weights.T, np.dot(cov, weights))) * np.sqrt(days)
    portfolio_var = abs(portfolio_return - (portfolio_std * stats.norm.ppf(1 - alpha)))
    return portfolio_var
def min_VaR(mean_returns, cov, alpha, days):
    num_assets = len(mean_returns)
    args = (mean_returns, cov, alpha, days)
    constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
    bound = (0.0,1.0)
    bounds = tuple(bound for asset in range(num_assets))
    result = sco.minimize(calc_portfolio_VaR, num_assets*[1./num_assets,], args=args,
                        method='SLSQP', bounds=bounds, constraints=constraints)
    return result

min_port_VaR = min_VaR(mean_returns, cov, alpha, days)

print(pd.DataFrame([round(x,2) for x in min_port_VaR['x']],index=tickers).T)


from flask import url_for
from sih.tests import TestCase, logged_as
from sih.extensions import db
from sih.modules.stations.models import Source

class SourcesViewTestCase(TestCase):

    def setUp(self):
        super(SourcesViewTestCase, self).setUp()

        source = Source(id=1, name='Test 1', identifier='test1',
                        url='http://example.com/1')
        db.session.add(source)

        self.url = url_for('stations.sources_view', source_id=source.id)

    def test_admin_permission_required(self):
        """Apenas usuários com papel de *admin* podem visualizar fontes de
        dados.
        """

        response = self.client.get(self.url)
        self.assert403(response)

    @logged_as('admin', 'test')
    def test_view_source(self):
        """Deve ser possível visualizar uma fonte de dados.
        """

        response = self.client.get(self.url)
        self.assert200(response)


# -*- coding: utf-8 -*-
"""
Created on Wed Aug 18 17:14:11 2021

This code is to match voter master files which don't contain date information
To identify CEOs' registrant ID

@author: haoch
"""
#%%
import numpy as np
import pandas as pd
import glob
import datetime
from dateutil import parser
import json
pd.set_option('display.max_columns',None)

#%%
FL=pd.read_csv('Voter history/Combined File/District of Columbia.csv',low_memory=False)
CEO_file=pd.read_csv('Voter history\data\CEO_file.csv',sep='|')
#%%
#Cleaning target
CEO_file['Spouse last name']=CEO_file['Spouse full name'].apply(lambda x:x.split(',')[0] if len(str(x))>3 else x)
CEO_file['CEO first name']=CEO_file['Full Name'].apply(lambda x:find_first_name(x) if len(str(x))>3 else x)
CEO_file['Spouse first name']=CEO_file['Spouse full name'].apply(lambda x:find_first_name(x) if len(str(x))>3 else x)
CEO_file['Spouse DOY']=CEO_file['Spouse DOB'].apply(lambda x: x.year if type(x)==datetime.date else '')
CEO_file['Spouse DOM']=CEO_file['Spouse DOB'].apply(lambda x: x.month if type(x)==datetime.date else '')
CEO_file['DOY']=CEO_file['DOB'].apply(lambda x: x.year if type(x)==datetime.date else '')
CEO_file['DOM']=CEO_file['DOB'].apply(lambda x: x.month if type(x)==datetime.date else '')
CEO_file=CEO_file.sort_values(by=['Spouse SSN','DOB'],ascending=False).reset_index(drop=True)
CEO_file=CEO_file.drop_duplicates(subset = ["LexID"],keep='first')
#%%
#list of state for each CEO and spouse
#list of last name
#%%
# get year of birth and month of birth from CEO file
def get_DOY(date):
    try:
        date=parser.parse(date)
        return date.year
    except:
        return ''
def get_DOM(date):
    try:
        date=parser.parse(date)
        return date.month
    except:
        return ''

#%%
# transform a column of variable into string sperated by ';'
def get_col_list(df,colnm):
    df=df[~df[colnm].isnull()]
    col_list=df[colnm].tolist()
    col_list=list(set(col_list))
    col_list=';'.join(col_list)
    return col_list

# For addresses file 'Home', I divide this file into different group based on CEO
# for each group, extract address state column into a string separeted by ';'
def get_CEO_hm_state(Home,CEO_file):
    group_h=Home.groupby('LexID')
    for ind,row in CEO_file.iterrows():
        ID=CEO_file.loc[ind,'LexID']
        try:
            df=group_h.get_group(ID)
        except:
            continue
        state_list=get_col_list(df,'Street Address state')
        zip_list=get_col_list(df,'Zip')
        CEO_file.loc[ind,'hm state list']=state_list
        CEO_file.loc[ind,'zip list']=zip_list
    return CEO_file
# extract address city list
def get_CEO_hm_city(Home_city,CEO_file):
    group_h=Home_city.groupby('LexID')
    for ind,row in CEO_file.iterrows():
        ID=CEO_file.loc[ind,'LexID']
        try:
            df=group_h.get_group(ID)
        except:
            continue
        city_list=get_col_list(df,'city')
        CEO_file.loc[ind,'hm city list']=city_list
    return CEO_file

#%%
# match CEO based on name, zip code, city and state
def get_match(FL,demo):
    state_map=json.load(open('states_hash.json',))
    #filter based on state
    target_state=state_map.get(FL.loc[0,'State'])
    test=demo[demo['hm state list'].str.contains(target_state)]
    FL['LastName']=FL['LastName'].apply(lambda x:x.upper() if type(x)==str else x)
    if 'DOB' in FL:
        FL['DOY']=FL['DOB'].apply(lambda x: get_DOY(x))
        FL['DOM']=FL['DOB'].apply(lambda x: get_DOM(x))
        demo=pd.merge(test,FL,left_on=['CEO last name','DOY','DOM'],right_on=['LastName','DOY','DOM'],how='inner')
    elif 'YOB' in FL:
        FL['YOB']=FL['YOB'].apply(lambda x: str(x))
        demo=pd.merge(test,FL,left_on=['CEO last name','DOY'],right_on=['LastName','YOB'],how='inner')
    else:
        print('no DOB')
        demo=pd.merge(test,FL,left_on=['CEO last name'],right_on=['LastName'],how='inner')
    if len(demo)==0:
        return pd.DataFrame()
    if 'Zip' in FL:
        demo['f']=demo.apply(lambda x: 1 if str(x['Zip'])[0:5] in x['zip list'] else 0,axis=1)
    else:
        demo['f']=1
#Because zip is more specific than city, we can ignore city if we consider zip
    # if 'City' in demo:
    #     demo['f']=demo.apply(lambda x: 1 if str(x['City']).upper() in x['hm city list'] else 0,axis=1)
    # else:
    #     demo['f']=1
    demo['f1']=demo.apply(lambda x: 1 if str(x['CEO first name']).split(' ')[0] in x['FirstName'].upper() else 0,axis=1)
    result=demo[(demo['f']==1)&(demo['f1']==1)]
    #result=demo[demo['f1']==1]
    return result

#%%
#extract all voter files
def get_res_list(demo):
    files = glob.glob("D:/RA Python/CEO/Voter history/Combined File/*.csv")
    #files = glob.glob("D:/RA Python/CEO/Voter history/test/*.csv")
    df_list=[]
    for f in files:
        print(f)
        FL = pd.read_csv(f,low_memory=False)
        result=get_match(FL,demo)
        df_list.append(result)
    return df_list

#%%
# check back to see if there are multiple records for same persons
def get_dup(test1):
    dup_list=[]
    group=test1.groupby(['LexID','State'])
    for ID, df in group:
        if len(df)>1:
            dup_list.append(df)
    return pd.concat(dup_list, axis=0)


import json
import os
from datetime import date, datetime, timedelta
from typing import List
from jinja2 import Environment, FunctionLoader
from app.hfi.pdf_data_formatter import (get_date_range_string,
                                        get_fire_start_labels,
                                        get_formatted_dates,
                                        get_mean_intensity_groups,
                                        get_merged_station_data,
                                        get_prep_levels,
                                        get_sorted_dates,
                                        response_2_daily_jinja_format,
                                        response_2_prep_cycle_jinja_format)
from app.hfi.pdf_generator import build_mappings
from app.hfi.pdf_template import get_template
from app.schemas.hfi_calc import (DailyResult, DateRange,
                                  FireCentre,
                                  HFIResultResponse,
                                  StationDaily, StationInfo,
                                  StationPDFData,
                                  WeatherStation,
                                  WeatherStationProperties,
                                  FireStartRange)
from app.schemas.hfi_calc import HFIResultResponse
from app.schemas.shared import FuelType

test_hfi_result = os.path.join(os.path.dirname(__file__), 'test_hfi_result.json')
test_fcs = os.path.join(os.path.dirname(__file__), 'test_fire_centres.json')
jinja_env = Environment(loader=FunctionLoader(get_template), autoescape=True)
lowest_fire_starts = (FireStartRange(id=1, label='0-1', ))

def test_get_sorted_dates_same():
    """ Only one date of each date is returned in order """
    start_date = date.fromisocalendar(2022, 2, 2)
    end_date = start_date + timedelta(days=6)
    date_range: DateRange = DateRange(start_date=start_date,
                                      end_date=end_date)

    result = get_sorted_dates(date_range)
    assert len(result) == 7
    assert result[0] == start_date
    assert result[6] == end_date

def test_get_date_range_string_2():
    """ Only one date of each date is returned in order """
    dates = [date.fromisocalendar(2022, 2, 2), date.fromisocalendar(2022, 3, 3)]
    result = get_date_range_string(dates)
    assert result == '2022-01-11 to 2022-01-19'

def test_get_date_range_string_3():
    """ Only one date of each date is returned in order """
    dates = [date.fromisocalendar(2022, 1, 1),
             date.fromisocalendar(2022, 2, 2),
             date.fromisocalendar(2022, 3, 3)]
    result = get_date_range_string(dates)
    assert result == '2022-01-03 to 2022-01-19'

def test_get_date_range_string_empty():
    """ Only one date of each date is returned in order """
    result = get_date_range_string([])
    assert result == ''

def test_get_date_range_string_single():
    """ Only one date of each date is returned in order """
    result = get_date_range_string([date.fromisocalendar(2022, 1, 1)])
    assert result == '2022-01-03'

def test_get_fire_start_labels():
    """ Returns the fire start labels from a planning area result """
    with open(test_hfi_result, 'r') as hfi_result:
        result_json = json.load(hfi_result)
        result = HFIResultResponse(**result_json)
        fire_labels = get_fire_start_labels(result.planning_area_hfi_results[0].daily_results)
        assert fire_labels == ['0-1', '0-1', '0-1']

def test_get_prep_levels():
    """ Returns the prep levels from a list of daily results"""
    daily_results: List[DailyResult] = [
        DailyResult(
            date=datetime.fromisocalendar(2022, 2, 2),
            dailies=[],
            fire_starts=lowest_fire_starts,
            prep_level=1
        ),
        DailyResult(
            date=datetime.fromisocalendar(2022, 2, 2),
            dailies=[],
            fire_starts=lowest_fire_starts,
            prep_level=2
        )
    ]
    result = get_prep_levels(daily_results)
    assert result == [1, 2]

def test_get_mean_intensity_groups():
    """ Returns the prep levels from a list of daily results"""
    daily_results: List[DailyResult] = [
        DailyResult(
            date=datetime.fromisocalendar(2022, 2, 2),
            dailies=[],
            fire_starts=lowest_fire_starts,
            mean_intensity_group=1
        ),
        DailyResult(
            date=datetime.fromisocalendar(2022, 2, 2),
            dailies=[],
            fire_starts=lowest_fire_starts,
            mean_intensity_group=2
        )
    ]
    result = get_mean_intensity_groups(daily_results)
    assert result == [1, 2]

def test_all_array_functions():
    """ Per day metrics, ordered by date, shoud be the same length """
    with open(test_hfi_result, 'r') as hfi_result:
        result_json = json.load(hfi_result)
        result = HFIResultResponse(**result_json)

        # dates test
        sorted_dates = get_sorted_dates(result.date_range)
        formatted_dates: List[str] = get_formatted_dates(sorted_dates)
        assert len(sorted_dates) == len(formatted_dates)

        for area_result in result.planning_area_hfi_results:
            # # of migs and prep levels should equal # of dates
            mean_intensity_groups = get_mean_intensity_groups(area_result.daily_results)
            prep_levels = get_prep_levels(area_result.daily_results)

            assert len(sorted_dates) == len(mean_intensity_groups)
            assert len(formatted_dates) == len(mean_intensity_groups)
            assert len(sorted_dates) == len(prep_levels)
            assert len(formatted_dates) == len(prep_levels)

def test_get_merged_station_data():

    weather_station_1 = WeatherStation(
        code=1,
        station_props=WeatherStationProperties(name='s1',
                                               wfwx_station_uuid='1',
                                               elevation=1))
    weather_station_2 = WeatherStation(
        code=2,
        station_props=WeatherStationProperties(name='s2',
                                               wfwx_station_uuid='2',
                                               elevation=1,
                                               ))
    station_dict = {1: weather_station_1, 2: weather_station_2}
    station_daily1 = StationDaily(code=1, date=datetime.fromisocalendar(2022, 2, 2))
    station_daily2 = StationDaily(code=2, date=datetime.fromisocalendar(2022, 2, 2))
    fuel_types = {1: FuelType(id=1, abbrev='A', fuel_type_code='A', description='A')}
    planning_area_station_info = [StationInfo(station_code=1, selected=True, fuel_type_id=1),
                                  StationInfo(station_code=2, selected=True, fuel_type_id=1)]
    merged_station_data: List[StationPDFData] = get_merged_station_data(
        station_dict, [station_daily1, station_daily2], fuel_types, planning_area_station_info)
    assert len(merged_station_data) == 2
    assert merged_station_data[0].code == 1
    assert merged_station_data[0].station_props == weather_station_1.station_props
    assert merged_station_data[0].fuel_type == fuel_types[1]
    assert merged_station_data[1].code == 2
    assert merged_station_data[1].station_props == weather_station_2.station_props
    assert merged_station_data[1].fuel_type == fuel_types[1]

def test_response_2_prep_cycle_jinja_format():
    with open(test_hfi_result, 'r') as hfi_result, open(test_fcs, 'r') as fcs:
        result = json.load(hfi_result)
        fc_dict = json.load(fcs)
        fire_centres = []
        for fc_json in fc_dict['fire_centres']:
            fc = FireCentre(**fc_json)
            fire_centres.append(fc)

        fuel_types = {id: FuelType(id=id, abbrev='A', fuel_type_code='A', description='A')
                      for id in [22, 24, 26, 34]}
        _, planning_area_dict, station_dict = build_mappings(fire_centres)
        area_pdf_data, formatted_dates, date_range = response_2_prep_cycle_jinja_format(
            HFIResultResponse(**result), planning_area_dict, station_dict, fuel_types=fuel_types)

        # 7 planning areas in coastal
        assert len(area_pdf_data) == 7
        # assert correct order
        assert area_pdf_data[0].planning_area_name == 'Fraser Zone'
        assert area_pdf_data[1].planning_area_name == 'Pemberton Zone'
        assert area_pdf_data[2].planning_area_name == 'Sunshine Coast'
        assert area_pdf_data[3].planning_area_name == 'South Island'
        assert area_pdf_data[4].planning_area_name == 'Mid Island'
        assert area_pdf_data[5].planning_area_name == 'North Island'
        assert area_pdf_data[6].planning_area_name == 'Mid-Coast'
        assert formatted_dates == ['Monday August 02, 2021', 'Tuesday August 03, 2021',
                                   'Wednesday August 04, 2021']
        assert date_range == '2021-08-02 to 2021-08-04'

def test_response_2_daily_jinja_format():
    with open(test_hfi_result, 'r') as hfi_result, open(test_fcs, 'r') as fcs:
        result = json.load(hfi_result)
        fc_dict = json.load(fcs)
        fire_centres = []
        for fc_json in fc_dict['fire_centres']:
            fc = FireCentre(**fc_json)
            fire_centres.append(fc)

        _, planning_area_dict, station_dict = build_mappings(fire_centres)
        fuel_types = {id: FuelType(id=id, abbrev='A', fuel_type_code='A', description='A')
                      for id in [22, 24, 26, 34]}
        daily_pdf_data_by_date = response_2_daily_jinja_format(
            HFIResultResponse(**result), planning_area_dict, station_dict,
            fuel_types=fuel_types)

        # 4 daily results
        day_dates = list(daily_pdf_data_by_date.keys())
        assert len(day_dates) == 3
        assert day_dates[0] == '2021-08-02'
        assert day_dates[1] == '2021-08-03'
        assert day_dates[2] == '2021-08-04'

        for daily_planning_area_data in daily_pdf_data_by_date.values():
            # 7 planning areas in coastal
            assert len(daily_planning_area_data) == 7
            # assert correct order for each day
            for index in range(len(daily_planning_area_data)):
                assert daily_planning_area_data[index].order == index + 1


# -*- coding: utf-8 -*-

import ckanapi

# maximum number of results to read
MAX_ROWS = 200

class DatasetsPGI(object):

    ckan_url = u"http://dados.gov.br"
    api_key = u""

    def __init__(self):
        self.read_api_key()
        self.ckansite = ckanapi.RemoteCKAN(self.ckan_url, apikey=self.api_key)
        self.datasets = self.ckansite.action.dataset_search(q=u"tags:PGI state:active",rows=MAX_ROWS)

    def read_api_key(self):
        try:
            with open("../../../api.key","r") as f:
                self.api_key=f.readline().strip()
        except IOError:
            raise Exception(u"Uma chave de API no arquivo api.key é necessária para a operação.")


import requests
import glom

from datetime import datetime

from airflow.decorators import task
from airflow import DAG
import sqlite3

from settings import OXY_USERNAME, OXY_PASSWORD, DB_FILE_PATH

@task(task_id="collect_crawl_job")
def collect_crawl_jobs():
    conn = sqlite3.connect(DB_FILE_PATH)
    cursor = conn.cursor()

    cursor.execute(
        f"""
            SELECT job_id FROM crawl_jobs
            WHERE status = 'pending'
        """
    )
    jobs = cursor.fetchall()
    if not jobs:
        print("No pending crawl jobs found")
        return

    job_ids = [_id[0] for _id in jobs]

    print(f"JOB IDS: {job_ids}")

    for job_id in job_ids:
        meta_url = f"http://ect.oxylabs.io/v1/jobs/{job_id}"
        response = requests.get(
            url=meta_url,
            auth=(OXY_USERNAME, OXY_PASSWORD),
        ).json()

        events = response.get("events", [])
        if len(events) == 0:
            print("Crawling job is not finished.")
            return

        indexing_event = events[0]
        if indexing_event.get("status", "") == "faulted":
            cursor.execute(
                f"""
                    UPDATE crawl_jobs
                    SET status = 'faulted'
                    WHERE job_id = {job_id}
                """
            )
            conn.commit()
            return

        sitemap_url = f"http://ect.oxylabs.io/v1/jobs/{job_id}/sitemap"
        response = requests.get(
            url=sitemap_url,
            auth=(OXY_USERNAME, OXY_PASSWORD),
        ).json()

        products = glom.glom(response, "results.0.sitemap")
        for product_url in products:
            try:
                cursor.execute(
                    f"""
                        INSERT INTO products (url, crawl_job_id)
                        VALUES ('{product_url}', '{job_id}')
                    """
                )
                conn.commit()
                print(f"New product {product_url}")
            except sqlite3.IntegrityError:
                print(f"Already exist {product_url}")

        print(f"Setting crawl job {job_id} to done.")
        cursor.execute(
            f"""
                UPDATE crawl_jobs
                SET status = 'done'
                WHERE job_id = '{job_id}'
            """
        )
        conn.commit()

with DAG(
    "collect_crawl_job",
    description="Collect results from crawl jobs.",
    schedule_interval="0 7 * * *",
    start_date=datetime(2022, month=6, day=6, hour=13),
    catchup=False,
    tags=["webinar"],
    default_args={
        "owner": "airflow",
    },
) as dag:
    (collect_crawl_jobs())


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
import datetime
from django.utils.timezone import utc

class Migration(migrations.Migration):

    dependencies = [
        ('patientSearch', '0001_initial'),
    ]

    operations = [
        migrations.CreateModel(
            name='ResultURL_DataResource',
            fields=[
                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
                ('data_resource', models.ForeignKey(to='patientSearch.DataResource',on_delete=models.DO_NOTHING)),
            ],
        ),
        migrations.RenameField(
            model_name='query_resulturl',
            old_name='query_id',
            new_name='query',
        ),
        migrations.RenameField(
            model_name='query_resulturl',
            old_name='resulturl_id',
            new_name='result_url',
        ),
        migrations.AddField(
            model_name='resulturl',
            name='last_update_time',
            field=models.DateTimeField(default=datetime.datetime(2017, 12, 7, 9, 12, 2, 265291, tzinfo=utc)),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='resulturl_dataresource',
            name='result_url',
            field=models.ForeignKey(to='patientSearch.ResultURL',on_delete=models.DO_NOTHING),
        ),
    ]


# Julius Bier Kirkegaard 2017
# juliusbierk@gmail.com

import numpy as np
from scipy import linalg, sparse
import scipy.sparse.linalg as sparse_linalg

def preprocess(system, rhs):
	system = list(system)
	rhs = list(rhs)
	neqs = len(system)
	nvars = len(system[0])

	var_sizes = [-1]*nvars
	for i in range(neqs):
		system[i] = list(system[i])
		for j in range(nvars):
			if system[i][j] is not None:
				if isinstance(system[i][j], float):
					system[i][j] = np.array(system[i][j]).reshape((1,1))
			if system[i][j] is not None:
				assert len(system[i][j].shape) == 2, 'System elements must be matrices %i,%i is not'%(i, j)
			var_sizes[j] = var_sizes[j] if system[i][j] is None else system[i][j].shape[1]

	for i in range(len(rhs)):
		if isinstance(rhs[i], float):
			rhs[i] = np.array(rhs[i]).reshape((1))
	rhs_sizes = list(map(len, rhs))

	### Test sizes of matrices
	dtype = np.float64
	assert len(system) == len(rhs), 'Unequal number equations and right-hand-side vectors'
	for i in range(neqs):
		assert nvars == len(system[i]), 'All equations must be the same length, equation %i does not comply'%i
		for j in range(nvars):
			if system[i][j] is not None:
				if system[i][j].dtype == np.complex64 or system[i][j].dtype == np.complex128:
					dtype = np.complex128
				assert system[i][j].shape[0] == rhs_sizes[i], 'Matrices must be consistent. Matrix %i,%i does not match right-hand side %i'(i,j,i)
				assert system[i][j].shape[1] == var_sizes[j], 'Matrices must be consistent. Matrix %i,%i does not variable %i'(i,j,j)
	for j in range(nvars):
		if rhs[j].dtype == np.complex64 or rhs[j].dtype == np.complex128:
			dtype = np.complex128

	return neqs, nvars, var_sizes, rhs_sizes, dtype

def postprocess(res, var_sizes):
	extra_output = False
	if isinstance(res, tuple):
		output = list(res)
		res = res[0]
		extra_output = True

	res = np.split(res, np.cumsum(var_sizes))[:-1]

	if extra_output:
		output[0] = res
		return tuple(output)
	else:
		return res

def build_matrix(A, system, neqs, nvars, rhs_sizes, var_sizes):
	assert A.shape[0] == A.shape[1], 'Number of equations and variables must equal'
	r = 0
	for i in range(neqs):
		c = 0
		for j in range(nvars):
			if system[i][j] is not None:
				A[r:r+rhs_sizes[i], c:c+var_sizes[j]] = system[i][j]
			c += var_sizes[j]
		r += rhs_sizes[i]

def solve_system(system, rhs, method=linalg.solve, **kwargs):
	neqs, nvars, var_sizes, rhs_sizes, dtype = preprocess(system, rhs)

	### Create full matrix
	A = np.zeros((sum(rhs_sizes),sum(var_sizes)), dtype=dtype)
	build_matrix(A, system, neqs, nvars, rhs_sizes, var_sizes)
	b = np.hstack(rhs)

	### Solve
	res = method(A, b, **kwargs)
	return postprocess(res, var_sizes)

def solve_sparse_system(system, rhs, method=sparse_linalg.spsolve, **kwargs):
	neqs, nvars, var_sizes, rhs_sizes, dtype = preprocess(system, rhs)

	### Create full matrix
	A = sparse.lil_matrix((sum(rhs_sizes),sum(var_sizes)), dtype=dtype)
	build_matrix(A, system, neqs, nvars, rhs_sizes, var_sizes)
	b = np.hstack(rhs)

	### Solve
	A = sparse.csr_matrix(A)
	res = method(A, b, **kwargs)
	return postprocess(res, var_sizes)

if __name__ == '__main__':
	### Solve system
	# A1 x + B1 y = a1
	# A2 x + B2 y = a2

	a1 = np.array([1, 2, 3])
	a2 = np.array([7, 8, 9, 10])
	A1 = np.array([[2, 0],
				   [0, 1],
				   [2, 1]])
	B1 = np.array([[2, 5, 0, 1, 2],
				   [0, 2, 0, 0, 1],
				   [0, 1, 0, 2, 0]])
	A2 = np.array([[3, 0],
				   [1, 2],
				   [0, 2+1j],
				   [3, 3]])
	B2 = np.array([[5, 0, 2, 2, 5],
				   [0, 1, 2, 0, 0],
				   [0, 0, 2, 1, 0],
				   [8, 0, 0, 0, 8]])

	print('Test dense solver')
	x, y = solve_system(((A1, B1), (A2, B2)), (a1, a2))
	print(np.allclose(np.dot(A1, x) + np.dot(B1, y), a1) and \
		  np.allclose(np.dot(A2, x) + np.dot(B2, y), a2))

	print('Test sparse solver')
	A2 = sparse.lil_matrix(A2)
	B1 = sparse.csc_matrix(B1)
	x, y = solve_sparse_system(((A1, B1), (A2, B2)), (a1, a2))
	A2 = A2.todense()
	B1 = B1.todense()
	print(np.allclose(np.dot(A1, x) + np.dot(B1, y), a1) and \
		  np.allclose(np.dot(A2, x) + np.dot(B2, y), a2))

	print('Test missing array')
	x, y = solve_system(((A1, B1), (None, B2)), (a1, a2))
	A2 = np.array([[0, 0],
				   [0, 0],
				   [0, 0],
				   [0, 0]])
	print(np.allclose(np.dot(A1, x) + np.dot(B1, y), a1) and \
		  np.allclose(np.dot(A2, x) + np.dot(B2, y), a2))


from operator import mod
from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
import ipaddress
from .helperfunctions import validators as hvalidator

def validate_ip(address):
    # using custom validator in order to allow for check in private,public ip, ranges, locals, IPv6 etc
    try:
        ip = ipaddress.ip_address(address)
    except ValueError:
        raise ValidationError(
            _('%(value)s is not an IP address'),params={'value':address}
            )

# Create your models here.
class Device(models.Model):
    # ip = models.GenericIPAddressField is the more common declartion in django of an field representing IP Address
        # and it comes with built in validation and some usefull helper functions
    ip = models.CharField(max_length=15,unique=True,validators=[validate_ip])
    customer_code = models.CharField(max_length=255,default="",unique=True)

    def __str__(self):
        return f"{self.customer_code}  {self.ip}"

class ProvisioningStatus(models.Model):
    device = models.OneToOneField(Device, to_field='ip',db_column='ip',on_delete=models.CASCADE,primary_key=True)
    status = models.BooleanField(default=False)

    def __str__(self):
        return f"CUST:{self.device.customer_code} IP:{self.device.ip} STATUS:{self.status}"


from bs4 import BeautifulSoup
import urllib.request

def find_answers(soup, counter):
    divs = soup.find_all("div", class_="Answer AnswerBase")  # finds all the div tags
    for d in divs:
        answers = d.find_all("p")  # within the span tags finds all the paragraph tags so answers can be kept together
        counter += 1
        with open("Text" + str(counter) + ".txt", "w+") as f:  # need to add in an if statement since some spans empty
            for a in answers:
                f.write(a.text)  # writes each answer in a separate text file, though some are empty cause no text
                f.write("\n")
    return counter

def soup_given_url(given_url):
    url = given_url
    content = urllib.request.urlopen(url)
    soup = BeautifulSoup(content, "html.parser")
    return soup

def main():
    url = ["https://www.quora.com/Have-you-ever-had-someone-react-negatively-or-strangely-to-your-name",
           "https://www.quora.com/People-who-enter-homes-for-a-living-Maintenance-cable-contractors-etc-what-s-the"
           "-strangest-thing-you-ve-encountered-when-entering-someone-s-home",
           "https://www.quora.com/What-is-the-most-difficult-thing-you-ever-faced-as-a-teen"]
    count = 0
    for u in url:
        soup = soup_given_url(u)
        count = find_answers(soup, count)

main()


import json
from system_info import SystemInfo

data = {}
h1 = SystemInfo()
data["cpu_temperature"] = h1.cpu_temperature
data["disk_space"] = h1.disk_space
data["cpu_use"] = h1.cpu_use
data["ram_info"] = h1.ram_info
print(json.dumps(data))


# code from Luke edited by Red_M on espernet or Red-M on github.com
from util import http,hook
import json

@hook.command(autohelp=False)
def mcstatus(inp, say=None):
    request = http.get("http://status.mojang.com/check")

    # make the shitty json less shitty, cbf parsing it normally
    data = json.loads(request.replace("}", "").replace("{", "").replace("]", "}").replace("[", "{"))

    outt = ""
    out = ""
    i=0
    # use a loop so we don't have to update it if they add more servers
    for server, status in data.items():
        i+=1
        if status == "green":
            if i==len(data):
                outt += ("%s online." % server.replace("login.minecraft.net","login is").replace("account.mojang.com","accounts are").replace("auth.mojang.com","authentication is").replace("session.minecraft.net","sessions are"))
            else:
                outt += ("%s online, " % server.replace("login.minecraft.net","login is").replace("account.mojang.com","accounts are").replace("auth.mojang.com","authentication is").replace("session.minecraft.net","sessions are"))
        else:
            if i==len(data):
                outt += ("%s offline." % server.replace("login.minecraft.net","login is").replace("account.mojang.com","accounts are").replace("auth.mojang.com","authentication is").replace("session.minecraft.net","sessions are"))
            else:
                outt += ("%s offline, " % server.replace("login.minecraft.net","login is").replace("account.mojang.com","accounts are").replace("auth.mojang.com","authentication is").replace("session.minecraft.net","sessions are"))
    out=outt.replace(", minecraft.net ",", The minecraft website is ")
    return out


import torch
from torch.autograd import Variable
import networks
from util import random_size, get_scale_weights
import os
import warnings
import numpy as np

class LRPolicy(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end

    def __call__(self, citer):
        return 1. - max(0., float(citer - self.start) / float(self.end - self.start))

# noinspection PyAttributeOutsideInit
class InGAN:
    def __init__(self, conf):
        # Acquire configuration
        self.conf = conf
        self.cur_iter = 0
        self.max_iters = conf.max_iters

        # Define input tensor
        self.input_tensor = torch.FloatTensor(1, 3, conf.input_crop_size, conf.input_crop_size).cuda()
        self.real_example = torch.FloatTensor(1, 3, conf.output_crop_size, conf.output_crop_size).cuda()

        # Define networks
        self.G = networks.Generator(conf.G_base_channels, conf.G_num_resblocks, conf.G_num_downscales, conf.G_use_bias,
                                    conf.G_skip)
        self.D = networks.MultiScaleDiscriminator(conf.output_crop_size,  self.conf.D_max_num_scales,
                                                  self.conf.D_scale_factor, self.conf.D_base_channels)
        self.GAN_loss_layer = networks.GANLoss()
        self.Reconstruct_loss = networks.WeightedMSELoss(use_L1=conf.use_L1)
        self.RandCrop = networks.RandomCrop([conf.input_crop_size, conf.input_crop_size], must_divide=conf.must_divide)
        self.SwapCrops = networks.SwapCrops(conf.crop_swap_min_size, conf.crop_swap_max_size)

        # Make all networks run on GPU
        self.G.cuda()
        self.D.cuda()
        self.GAN_loss_layer.cuda()
        self.Reconstruct_loss.cuda()
        self.RandCrop.cuda()
        self.SwapCrops.cuda()

        # Define loss function
        self.criterionGAN = self.GAN_loss_layer.forward
        self.criterionReconstruction = self.Reconstruct_loss.forward

        # Keeping track of losses- prepare tensors
        self.losses_G_gan = torch.FloatTensor(conf.print_freq).cuda()
        self.losses_D_real = torch.FloatTensor(conf.print_freq).cuda()
        self.losses_D_fake = torch.FloatTensor(conf.print_freq).cuda()
        self.losses_G_reconstruct = torch.FloatTensor(conf.print_freq).cuda()
        if self.conf.reconstruct_loss_stop_iter > 0:
            self.losses_D_reconstruct = torch.FloatTensor(conf.print_freq).cuda()

        # Initialize networks
        self.G.apply(networks.weights_init)
        self.D.apply(networks.weights_init)

        # Initialize optimizers
        self.optimizer_G = torch.optim.Adam(self.G.parameters(), lr=conf.g_lr, betas=(conf.beta1, 0.999))
        self.optimizer_D = torch.optim.Adam(self.D.parameters(), lr=conf.d_lr, betas=(conf.beta1, 0.999))

        # Learning rate scheduler
        # First define linearly decaying functions (decay starts at a special iter)
        start_decay = conf.lr_start_decay_iter
        end_decay = conf.max_iters
        # def lr_function(n_iter):
        #     return 1 - max(0, 1.0 * (n_iter - start_decay) / (conf.max_iters - start_decay))
        lr_function = LRPolicy(start_decay, end_decay)
        # Define learning rate schedulers
        self.lr_scheduler_G = torch.optim.lr_scheduler.LambdaLR(self.optimizer_G, lr_function)
        self.lr_scheduler_D = torch.optim.lr_scheduler.LambdaLR(self.optimizer_D, lr_function)

        # # do we resume from checkpoint?
        # if self.conf.resume:
        #     print('resuming checkpoint {}'.format(self.conf.resume))
        #     self.resume(self.conf.resume)

    def save(self, citer=None):
        if citer is None:
            filename = 'snapshot.pth.tar'
        elif isinstance(citer, str):
            filename = citer
        else:
            filename = 'snapshot-{:05d}.pth.tar'.format(citer)
        torch.save({'G': self.G.state_dict(),
                    'D': self.D.state_dict(),
                    'optim_G': self.optimizer_G.state_dict(),
                    'optim_D': self.optimizer_D.state_dict(),
                    'sched_G': self.lr_scheduler_G.state_dict(),
                    'sched_D': self.lr_scheduler_D.state_dict(),
                    'loss': self.GAN_loss_layer.state_dict(),
                    'iter': citer if citer else self.cur_iter},
                   os.path.join(self.conf.output_dir_path, filename))

    def resume(self, resume_path, test_flag=False):
        resume = torch.load(resume_path, map_location={'cuda:5': 'cuda:0'})
        missing = []
        if 'G' in resume:
            self.G.load_state_dict(resume['G'])
        else:
            missing.append('G')
        if 'D' in resume:
            self.D.load_state_dict(resume['D'])
        else:
            missing.append('D')
        if not test_flag:
            if 'optim_G' in resume:
                self.optimizer_G.load_state_dict(resume['optim_G'])
            else:
                missing.append('optimizer G')
            if 'optim_D' in resume:
                self.optimizer_D.load_state_dict(resume['optim_D'])
            else:
                missing.append('optimizer D')
            if 'sched_G' in resume:
                self.lr_scheduler_G.load_state_dict(resume['sched_G'])
            else:
                missing.append('lr scheduler G')
            if 'sched_D' in resume:
                self.lr_scheduler_D.load_state_dict(resume['sched_D'])
            else:
                missing.append('lr scheduler G')
            if 'loss' in resume:
                self.GAN_loss_layer.load_state_dict(resume['loss'])
            else:
                missing.append('GAN loss')
        if len(missing):
            warnings.warn('Missing the following state dicts from checkpoint: {}'.format(', '.join(missing)))

        print('resuming checkpoint {}'.format(self.conf.resume))

    def test(self, input_tensor, output_size, rand_affine, input_size, run_d_pred=True, run_reconstruct=True):
        with torch.no_grad():
            self.G_pred = self.G.forward(Variable(input_tensor.detach()), output_size=output_size, random_affine=rand_affine)
            if run_d_pred:
                scale_weights_for_output = get_scale_weights(i=self.cur_iter,
                                                             max_i=self.conf.D_scale_weights_iter_for_even_scales,
                                                             start_factor=self.conf.D_scale_weights_sigma,
                                                             input_shape=self.G_pred.shape[2:],
                                                             min_size=self.conf.D_min_input_size,
                                                             num_scales_limit=self.conf.D_max_num_scales,
                                                             scale_factor=self.conf.D_scale_factor)
                scale_weights_for_input = get_scale_weights(i=self.cur_iter,
                                                            max_i=self.conf.D_scale_weights_iter_for_even_scales,
                                                            start_factor=self.conf.D_scale_weights_sigma,
                                                            input_shape=input_tensor.shape[2:],
                                                            min_size=self.conf.D_min_input_size,
                                                            num_scales_limit=self.conf.D_max_num_scales,
                                                            scale_factor=self.conf.D_scale_factor)
                self.D_preds = [self.D.forward(Variable(input_tensor.detach()), scale_weights_for_input),
                                self.D.forward(Variable(self.G_pred.detach()), scale_weights_for_output)]
            else:
                self.D_preds = None

            self.G_preds = [input_tensor, self.G_pred]

            self.reconstruct = self.G.forward(self.G_pred, output_size=input_size, random_affine=-rand_affine) if run_reconstruct else None

        return self.G_preds, self.D_preds, self.reconstruct

    def train_g(self):
        # Zeroize gradients
        self.optimizer_G.zero_grad()
        self.optimizer_D.zero_grad()

        # Determine output size of G (dynamic change)
        output_size, random_affine = random_size(orig_size=self.input_tensor.shape[2:],
                                                 curriculum=self.conf.curriculum,
                                                 i=self.cur_iter,
                                                 iter_for_max_range=self.conf.iter_for_max_range,
                                                 must_divide=self.conf.must_divide,
                                                 min_scale=self.conf.min_scale,
                                                 max_scale=self.conf.max_scale,
                                                 max_transform_magniutude=self.conf.max_transform_magnitude)

        # Add noise to G input for better generalization (make it ignore the 1/255 binning)
        self.input_tensor_noised = self.input_tensor + (torch.rand_like(self.input_tensor) - 0.5) * 2.0 / 255

        # Generator forward pass
        self.G_pred = self.G.forward(self.input_tensor_noised, output_size=output_size, random_affine=random_affine)

        # Run generator result through discriminator forward pass
        self.scale_weights = get_scale_weights(i=self.cur_iter,
                                               max_i=self.conf.D_scale_weights_iter_for_even_scales,
                                               start_factor=self.conf.D_scale_weights_sigma,
                                               input_shape=self.G_pred.shape[2:],
                                               min_size=self.conf.D_min_input_size,
                                               num_scales_limit=self.conf.D_max_num_scales,
                                               scale_factor=self.conf.D_scale_factor)
        d_pred_fake = self.D.forward(self.G_pred, self.scale_weights)

        # If reconstruction-loss is used, run through decoder to reconstruct, then calculate reconstruction loss
        if self.conf.reconstruct_loss_stop_iter > self.cur_iter:
            self.reconstruct = self.G.forward(self.G_pred, output_size=self.input_tensor.shape[2:], random_affine=-random_affine)
            self.loss_G_reconstruct = self.criterionReconstruction(self.reconstruct, self.input_tensor, self.loss_mask)

        # Calculate generator loss, based on discriminator prediction on generator result
        self.loss_G_GAN = self.criterionGAN(d_pred_fake, is_d_input_real=True)

        # Generator final loss
        # Weighted average of the two losses (if indicated to use reconstruction loss)
        if self.conf.reconstruct_loss_stop_iter < self.cur_iter:
            self.loss_G = self.loss_G_GAN
        else:
            self.loss_G = (self.conf.reconstruct_loss_proportion * self.loss_G_reconstruct + self.loss_G_GAN)

        # Calculate gradients
        # Note that the gradients are propagated from the loss through discriminator and then through generator
        self.loss_G.backward()

        # Update weights
        # Note that only generator weights are updated (by definition of the G optimizer)
        self.optimizer_G.step()

        # Extra training for the inverse G. The difference between this and the reconstruction is the .detach() which
        # makes the training only for the inverse G and not for regular G.
        if self.cur_iter > self.conf.G_extra_inverse_train_start_iter:
            for _ in range(self.conf.G_extra_inverse_train):
                self.optimizer_G.zero_grad()
                self.inverse = self.G.forward(self.G_pred.detach(), output_size=self.input_tensor.shape[2:], random_affine=-random_affine)
                self.loss_G_inverse = (self.criterionReconstruction(self.inverse, self.input_tensor, self.loss_mask) *
                                       self.conf.G_extra_inverse_train_ratio)
                self.loss_G_inverse.backward()
                self.optimizer_G.step()

        # Update learning rate scheduler
        self.lr_scheduler_G.step()

    def train_d(self):
        # Zeroize gradients
        self.optimizer_D.zero_grad()

        # Adding noise to D input to prevent overfitting to 1/255 bins
        real_example_with_noise = self.real_example + (torch.rand_like(self.real_example[-1]) - 0.5) * 2.0 / 255.0

        # Discriminator forward pass over real example
        self.d_pred_real = self.D.forward(real_example_with_noise, self.scale_weights)

        # Adding noise to D input to prevent overfitting to 1/255 bins
        # Note that generator result is detached so that gradients are not propagating back through generator
        g_pred_with_noise = self.G_pred.detach() + (torch.rand_like(self.G_pred) - 0.5) * 2.0 / 255

        # Discriminator forward pass over generated example example
        self.d_pred_fake = self.D.forward(g_pred_with_noise, self.scale_weights)

        # Calculate discriminator loss
        self.loss_D_fake = self.criterionGAN(self.d_pred_fake, is_d_input_real=False)
        self.loss_D_real = self.criterionGAN(self.d_pred_real, is_d_input_real=True)
        self.loss_D = (self.loss_D_real + self.loss_D_fake) * 0.5

        # Calculate gradients
        # Note that gradients are not propagating back through generator
        # noinspection PyUnresolvedReferences
        self.loss_D.backward()

        # Update weights
        # Note that only discriminator weights are updated (by definition of the D optimizer)
        self.optimizer_D.step()

        # Update learning rate scheduler
        self.lr_scheduler_D.step()

    def train_one_iter(self, cur_iter, input_tensors):
        # Set inputs as random crops
        input_crops = []
        mask_crops = []
        real_example_crops = []
        mask_flag = False
        for input_tensor in input_tensors:
            real_example_crops += self.RandCrop.forward([input_tensor])

            if np.random.rand() < self.conf.crop_swap_probability:
                swapped_input_tensor, loss_mask = self.SwapCrops.forward(input_tensor)
                [input_crop, mask_crop] = self.RandCrop.forward([swapped_input_tensor, loss_mask])
                input_crops.append(input_crop)
                mask_crops.append(mask_crop)
                mask_flag = True
            else:
                input_crops.append(real_example_crops[-1])

        self.input_tensor = torch.cat(input_crops)
        self.real_example = torch.cat(real_example_crops)
        self.loss_mask = torch.cat(mask_crops) if mask_flag else None

        # Update current iteration
        self.cur_iter = cur_iter

        # Run a single forward-backward pass on the model and update weights
        # One global iteration includes several iterations of generator and several of discriminator
        # (not necessarily equal)
        # noinspection PyRedeclaration
        for _ in range(self.conf.G_iters):
            self.train_g()

        # noinspection PyRedeclaration
        for _ in range(self.conf.D_iters):
            self.train_d()

        # Accumulate stats
        # Accumulating as cuda tensors is much more efficient than passing info from GPU to CPU at every iteration
        self.losses_G_gan[cur_iter % self.conf.print_freq] = self.loss_G_GAN.item()
        self.losses_D_fake[cur_iter % self.conf.print_freq] = self.loss_D_fake.item()
        self.losses_D_real[cur_iter % self.conf.print_freq] = self.loss_D_real.item()
        if self.conf.reconstruct_loss_stop_iter > self.cur_iter:
            self.losses_G_reconstruct[cur_iter % self.conf.print_freq] = self.loss_G_reconstruct.item()


import pymongo

def test_1():
    # 实现 pymongo 数据库的增删改查
    # 连接数据库
    myclient = pymongo.MongoClient("mongodb://localhost:27017/")
    # 创建/使用数据库（有数据插入才会被创建）
    mydb = myclient["stark"]
    # 创建/使用集合（有数据插入才会被创建）
    mycol = mydb["sites"]
    try:
        # 插入一条数据
        data = {"name": "stark", "email": "starktan@163.com", "sn": 1}
        x = mycol.insert_one(data)
        # 插入的id
        print(x.inserted_id)
        # 插入多条数据
        data_list = [
            {"name": "stark", "email": "starktan@163.com", "sn": 2},
            {"_id": "my_id", "name": "stark", "email": "starktan@163.com", "sn": 3},
        ]
        x = mycol.insert_many(data_list)
        # 输出插入的所有文档对应的 _id 值
        print(x.inserted_ids)
        # 查询所有数据
        for x in mycol.find():
            print(x)
        print("*"*100)
        # 查询指定数据 （支持正则表达式）
        for x in mycol.find({"name": "stark", "sn": 3}):
            print(x)
        print("*" * 100)
        # 查询指定数据,获取指定字段 （除了 _id 你不能在一个对象中同时指定 0 和 1，如果你设置了一个字段为 0，则其他都为 1，反之亦然。）
        for x in mycol.find({"name": "stark", "sn": 3}, {"_id": 0, "name": 1}):
            print(x)
        print("*" * 100)
        # 修改第一条匹配数据
        myquery = {"sn": 1}
        newvalues = {"$set": {"name": "starktan"}}
        mycol.update_one(myquery, newvalues)
        # 修改所有匹配数据
        myquery = {"name": {"$regex": "^stark$"}}
        newvalues = {"$set": {"alexa": "123"}}
        mycol.update_many(myquery, newvalues)
        for x in mycol.find():
            print(x)
        print("*" * 100)
        # 排序
        mydoc = mycol.find().sort("sn", -1)
        for x in mydoc:
            print(x)
        print("*" * 100)
        # 修改第一条匹配数据
        mycol.delete_one({"name": "starktan"})
        # 修改第一条匹配
        mycol.delete_many({"name": "stark"})
        for x in mycol.find():
            print(x)
        print("*" * 100)
    finally:
        # 数据库列表
        dblist = myclient.list_database_names()
        print(dblist)
        # 数据库中的集合列表
        collist = mydb.list_collection_names()
        print(collist)
        # 删除 集合
        mydb.drop_collection("sites")
        # 删除 数据库
        myclient.drop_database("stark")

test_1()


import numpy as np
import torch

class Hook():
	def __init__(self, module, backward=False):
		if backward==False:
			self.hook = module[1].register_forward_hook(self.hook_fn)
			self.name = module[0]
		else:
			self.hook = module[1].register_backward_hook(self.hook_fn)
			self.name = module[0]
	def hook_fn(self, module, input, output):
		self.input = input
		self.output = output
	def close(self):
		self.hook.remove()

def compute_entropy_1st(modelx, train_loader, hookF, classes, device):
	H = [None] * len(hookF)
	H_classwise = [None] * len(hookF)
	P = [None] * len(hookF)
	N = [None] * len(hookF)
	M = torch.zeros(classes, device=device)
	for idx in range(len(hookF)):
		H_classwise[idx] = torch.zeros((np.prod(hookF[idx].output.shape[1:]), classes), device=device)
		P[idx] = torch.zeros((np.prod(hookF[idx].output.shape[1:]), classes), device=device)
		N[idx] = torch.zeros((np.prod(hookF[idx].output.shape[1:]), classes), device=device)
	with torch.no_grad():
		for xb, yb in train_loader:
			xb = xb.to(device)
			yb = yb.to(device)
			for this_idx_1 in range(classes):
				M[this_idx_1] += torch.sum(yb == this_idx_1).item()
			modelx(xb)
			for idx in range(len(hookF)):
				for this_idx_1 in range(classes):
					this_yb_1 = ((yb == this_idx_1).type(torch.float)).unsqueeze(dim = 1)
					P[idx][:, this_idx_1] += torch.sum((hookF[idx].output.view(this_yb_1.shape[0], -1)>0) * this_yb_1, dim=0)
					N[idx][:, this_idx_1] += torch.sum((hookF[idx].output.view(this_yb_1.shape[0], -1)<=0) * this_yb_1, dim=0)
	for idx in range(len(hookF)):
		P[idx] = torch.clamp(P[idx] / M.unsqueeze(dim=0), 0.0001, 0.9999)
		N[idx] = torch.clamp(N[idx] / M.unsqueeze(dim=0), 0.0001, 0.9999)
		for this_idx_1 in range(classes):
			H_classwise[idx][:,this_idx_1] -= (P[idx][:,this_idx_1] * torch.log2(P[idx][:,this_idx_1] ) + (N[idx][:,this_idx_1]  * torch.log2(N[idx][:,this_idx_1])))
		H[idx] = torch.sum(H_classwise[idx], dim=1)
	return H, H_classwise

def compute_PSPentropy(model, dataset, device, order = 1, classes = 10):
	hookF = [Hook(layer,backward=False) for layer in list(model._modules.items())]
	for batch_idx, (inputs, targets) in enumerate(dataset):
		inputs, targets = inputs.to(device), targets.to(device)
		model(inputs)
		break;

	if order == 1:
		for idx in range(len(hookF)):
			H, H_classwise= compute_entropy_1st(model, dataset, hookF, classes, device)
		for h in hookF:
			h.close()
		return H, H_classwise
	else:
		#not yet implemented
		error()


from django import forms
from models import *
import re
from django.core import validators
from django.forms import CharField, Textarea, ValidationError
from django.utils.translation import ugettext as _
email_separator_re = re.compile(r'[,;]+')

def _is_valid_email(email):
    try:
        validators.validate_email(email)
        return True
    except forms.ValidationError:
        return False

class EmailsListField(CharField):
    widget = Textarea
    def clean(self, value):
        super(EmailsListField, self).clean(value)
        emails = email_separator_re.split(value)
        if not emails:
            raise ValidationError(_(u'Enter at least one e-mail address.'))
        for email in emails:
            if not _is_valid_email(email.strip()):
                raise ValidationError(_('%s is not a valid e-mail address.') % email)
        return emails

class CreateLeagueForm(forms.Form):
    name = forms.CharField(max_length = 30, label='League Name',
        widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'League Name'}))
    description = forms.CharField(max_length = 200, label='League Description',
        widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'Description'}))
    email_ids = EmailsListField(label='Invite Members',
    widget=forms.Textarea(attrs={'class':'form-control','placeholder': 'Enter Email address seperated by comma', 'cols': 30, 'rows': 10}))

    def clean(self):
        cleaned_data = super(CreateLeagueForm, self).clean()
        name = cleaned_data.get('name')
        description = cleaned_data.get('description')
        email_ids = cleaned_data.get('email_ids')
        return cleaned_data

class JoinLeagueForm(forms.Form):
    uniquecode = forms.CharField(max_length = 30, label='Enter League Unique Code',
        widget=forms.TextInput(attrs={'class':'form-control', 'placeholder': 'UniqueCode'}))

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        self.tourn = kwargs.pop('tourn', None)
        self.g_type = kwargs.pop('gt', None)
        self.season = kwargs.pop('season', None)
        super(JoinLeagueForm, self).__init__(*args, **kwargs)

    def clean(self):
        cleaned_data = super(JoinLeagueForm, self).clean()
        uniqueCode = cleaned_data.get('uniqueCode')
        return cleaned_data

    def clean_uniquecode(self):
        uniquecode = self.cleaned_data.get('uniquecode')
        if not GameLeague.objects.filter(uniqueCode__exact=uniquecode):
            raise forms.ValidationError("Invalid UniqueCode")
        if not GameLeague.isValidCode(uniquecode, self.tourn, self.season, self.g_type):
            raise forms.ValidationError("UniqueCode does not match this tournament or game type")
        if GameLeague.isUserExist(self.user, uniquecode):
            raise forms.ValidationError("You have already joined this league")
        return uniquecode


from ....utils.utils import is_blender_4
from ...shader_base import Nodes
from ..source1_shader_base import Source1ShaderBase

class LightmapGeneric(Source1ShaderBase):
    SHADER = 'lightmappedgeneric'

    @property
    def isskybox(self):
        return self._vmt.get_int('%' + 'compilesky', 0) + self._vmt.get_int('%' + 'compile2Dsky', 0)

    @property
    def basetexture(self):
        texture_path = self._vmt.get_string('$basetexture', None)
        if texture_path is not None:
            return self.load_texture_or_default(texture_path, (0.3, 0, 0.3, 1.0))
        return None

    @property
    def bumpmap(self):
        texture_path = self._vmt.get_string('$bumpmap', None)
        if texture_path is not None:
            image = self.load_texture_or_default(texture_path, (0.6, 0.0, 0.6, 1.0))
            if self.ssbump:
                image = self.convert_ssbump(image)
            image.colorspace_settings.is_data = True
            image.colorspace_settings.name = 'Non-Color'
            return image
        return None

    @property
    def ssbump(self):
        return self._vmt.get_int('$ssbump', 0) == 1

    @property
    def phong(self):
        return self._vmt.get_int('$phong', 0) == 1

    @property
    def alpha(self):
        return self._vmt.get_int('$alpha', 0) == 1

    @property
    def alphatest(self):
        return self._vmt.get_int('$alphatest', 0) == 1

    @property
    def translucent(self):
        return self._vmt.get_int('$translucent', 0) == 1

    def create_nodes(self, material_name):
        if super().create_nodes(material_name) in ['UNKNOWN', 'LOADED']:
            return

        if self.isskybox:
            self.bpy_material.shadow_method = 'NONE'
            self.bpy_material.use_backface_culling = True
        material_output = self.create_node(Nodes.ShaderNodeOutputMaterial)
        shader = self.create_node(Nodes.ShaderNodeBsdfPrincipled, self.SHADER)
        self.connect_nodes(shader.outputs['BSDF'], material_output.inputs['Surface'])

        basetexture = self.basetexture

        if basetexture:
            basetexture_node = self.create_and_connect_texture_node(basetexture,
                                                                    shader.inputs['Base Color'],
                                                                    name='$basetexture')

            if self.alphatest:
                self.bpy_material.blend_method = 'HASHED'
                self.bpy_material.shadow_method = 'HASHED'
                self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Alpha'])
            if self.translucent:
                self.bpy_material.blend_method = 'BLEND'
                self.bpy_material.shadow_method = 'HASHED'
                self.bpy_material.use_backface_culling = True
                self.bpy_material.show_transparent_back = False
                self.connect_nodes(basetexture_node.outputs['Alpha'], shader.inputs['Alpha'])

        bumpmap = self.bumpmap
        if bumpmap and not self.ssbump:
            bumpmap_node = self.create_node(Nodes.ShaderNodeTexImage, '$bumpmap')
            bumpmap_node.image = bumpmap

            normalmap_node = self.create_node(Nodes.ShaderNodeNormalMap)

            self.connect_nodes(bumpmap_node.outputs['Color'], normalmap_node.inputs['Color'])
            self.connect_nodes(normalmap_node.outputs['Normal'], shader.inputs['Normal'])

        if not self.phong:
            if is_blender_4():
                shader.inputs['Specular IOR Level'].default_value = 0
            else:
                shader.inputs['Specular'].default_value = 0

class ReflectiveLightmapGeneric(LightmapGeneric):
    SHADER = 'lightmappedreflective'

class SDKLightmapGeneric(LightmapGeneric):
    SHADER = 'sdk_lightmappedgeneric'


"""This class defines an agent for the Blokus Game"""

import random
import datetime as dt
import logging

class OutOfMoves(Exception):
    pass

class Agent:

    def __init__(self, player_id):
        self.player_id = player_id

    def get_move(self, game):
        raise RuntimeError("get_move is not implimented")

class RandomAgent(Agent):

    def get_move(self, game):
        valid_moves = list(game.get_players_moves(self.player_id))
        return self.pick_random_move(valid_moves)

    def pick_random_move(self, moves):
        if len(moves) == 0:
            raise OutOfMoves(f"Player {self.player_id} is out of moves")

        rand_int = random.randrange(len(moves))
        return moves[rand_int]

class GreedyAgent(RandomAgent):

    def get_move(self, game):
        valid_moves = list(game.get_players_moves(self.player_id))
        max_len = max([m.get_size() for m in valid_moves])
        largest_moves = list(filter(lambda m: m.get_size() == max_len, valid_moves))
        return self.pick_random_move(largest_moves)

class PointAgent(Agent):

    def __init__(self, player_id):
        self.turn_counter = 0
        super().__init__(player_id)

    def get_move(self, game):

        moves = list(game.get_players_moves(self.player_id))

        logging.info("Analizing %s potential moves on move: %s", len(moves), self.turn_counter)

        if len(moves) == 0:
            raise OutOfMoves(f"Player {self.player_id} is out of moves")

        max_move = None
        max_count = 0

        t0 = dt.datetime.now()
        for move in moves:

            game.make_move(move)
            move_num = len(list(game.get_players_moves(self.player_id)))

            if move_num >= max_count:
                max_count = move_num
                max_move = move

            game.pop()

        self.turn_counter += 1

        t1 = dt.datetime.now()

        logging.info("Completed in %s seconds", (t1 - t0).total_seconds())

        if max_move is None:
            raise ValueError(f"Not returning a Max Move Moves Length: {len(moves)}")

        return max_move

class GreedyPointAgent(Agent):

    def __init__(self, player_id):
        self.turn_counter = 0
        super().__init__(player_id)

    def get_move(self, game):

        moves = list(game.get_players_moves(self.player_id))

        biggest_piece_size = self.get_biggest_piece_size(moves)

        logging.info("Analizing %s potential moves on move: %s", len(moves), self.turn_counter)

        if len(moves) == 0:
            raise OutOfMoves(f"Player {self.player_id} is out of moves")

        max_move = None
        max_count = 0

        moves = filter(lambda m: m.get_size() == biggest_piece_size, moves)

        t0 = dt.datetime.now()
        for move in moves:

            game.make_move(move)
            move_num = len(list(game.get_players_moves(self.player_id)))

            if move_num >= max_count:
                max_count = move_num
                max_move = move

            game.pop()

        self.turn_counter += 1

        t1 = dt.datetime.now()

        logging.info("Completed in %s seconds", (t1 - t0).total_seconds())

        if max_move is None:
            raise ValueError(f"Not returning a Max Move Moves Length: {len(moves)}")

        return max_move

    def get_biggest_piece_size(self, moves):

        max_piece_size = 0

        for move in moves:

            piece_size = move.get_size()

            if piece_size > max_piece_size:
                max_piece_size = piece_size

            if max_piece_size == 5:
                return 5

        return max_piece_size

class HumanInput(Agent):

    def get_move(self, game):
        player = game.players[self.player_id]

        piece = self.pick_piece(player)

        corner = self.pick_corner(player, piece)

        move = self.pick_move(game, piece, corner)

        return move

    def pick_piece(self, player):

        pieces = player.pieces

        string = "Please Pick a piece from one of the following:\n"
        string += "\n".join(pieces)
        string += ": "

        while True:
            piece = input(string)
            if piece in pieces:
                return piece
            else:
                print("Invalid piece please try again")

    def pick_corner(self, player, piece):

        moves = player.valid_moves.get_piece_moves(piece)
        corners = list({move.corner for move in moves})
        string = "Please pick a corner from the following by its index"
        strings = [f"{str(c.p2)}, {i}" for i, c in enumerate(corners)]
        string += "\n".join(strings)

        return self.pick_by_index(corners, string)

    def pick_move(self, game, piece, corner):
        moves = game.players[self.player_id].valid_moves.get_corner_piece_moves(corner, piece)
        moves = list(moves)
        for i, move in enumerate(moves):
            b = game.board.copy()
            print(f"Move {i}")
            b.update(move)
            b.display()

        string = f"pick a move in range [0, {len(moves)}]"
        return self.pick_by_index(moves, string)

    def pick_by_index(self, values, string):

        while True:

            try:
                index = self.get_index(string)
                return values[index]

            except IndexError:
                print("Invalid Selection please try again.")

    def get_index(self, string):
        resp = input(string)
        try:
            return int(resp)

        except ValueError:
            print("Not a valid int try again")