Beispiel #1
0
    def buildRiver(self, siteOneID, siteTwoID, river, allRivers):
        oldRiverPiece = river[-1][2]
        saiteL = self.worldSites[siteOneID]
        saiteR = self.worldSites[siteTwoID]
        borderLeft = 0
        borderRight = 0
        leftReversed = False
        rightReversed = False

        for bordrderL in saiteL.borders:
            if oldRiverPiece.end == bordrderL.start and oldRiverPiece.start != bordrderL.end:
                break
            elif oldRiverPiece.end == bordrderL.end and oldRiverPiece.start != bordrderL.start:
                leftReversed = True
                break
            borderLeft += 1

        for bordrderR in saiteR.borders:
            if oldRiverPiece.end == bordrderR.start and oldRiverPiece.start != bordrderR.end:
                break
            elif oldRiverPiece.end == bordrderR.end and oldRiverPiece.start != bordrderR.start:
                rightReversed = True
                break
            borderRight += 1

        if (
                borderLeft < len(saiteL.borders) and borderRight < len(saiteR.borders) and 
                saiteL.borders[borderLeft].elevation > saiteR.borders[borderRight].elevation and
                saiteL.borders[borderLeft].elevation >= oldRiverPiece.elevation
            ):
            #generate left
            if leftReversed:
                reversedBorder = Border(saiteL.borders[borderLeft].end, saiteL.borders[borderLeft].start)
                reversedBorder.elevation = saiteL.borders[borderLeft].elevation
                river.append((siteOneID, borderLeft, reversedBorder))
            else:
                river.append((siteOneID, borderLeft, saiteL.borders[borderLeft]))
            self.buildRiver(siteTwoID, saiteL.neighbours[borderLeft], river, allRivers)
        elif borderRight < len(saiteR.borders) and saiteR.borders[borderRight].elevation >= oldRiverPiece.elevation:
            #generate right
            if rightReversed:
                reversedBorder = Border(saiteR.borders[borderRight].end, saiteR.borders[borderRight].start)
                reversedBorder.elevation = saiteR.borders[borderRight].elevation
                river.append((siteTwoID, borderRight, reversedBorder))
            else:
                river.append((siteTwoID, borderRight, saiteR.borders[borderRight]))
            self.buildRiver(siteTwoID, saiteR.neighbours[borderRight], river, allRivers)
Beispiel #2
0
    def __init__(self) -> None:
        self.update_action_depending_on_state = {
            GameState.PLAY: self.update_play_screen,
            GameState.MENU: self.update_menu_screen,
            GameState.PAUSE: self.update_pause_screen,
            GameState.GAME_OVER: self.update_game_over_screen,
        }
        self.state = GameState.MENU

        self.grid = Grid()
        self.menu = Menu()
        self.start_menu = StartMenu()
        self.border = Border()

        self.clock = pygame.time.Clock()
        self.running = True
        self.to_draw = True

        self.player = type(next_indicator.next_one)()
        self.create_new_player()

        self.fps = 0
Beispiel #3
0
    def drawPista(self):
        self.sectors = []
        for s in json.load(open("pista.json")):
            self.sectors.append(Sector(**s))
        # FIXME to remove after testing
        self.scene.setPista(self.sectors)

        self.borders = []
        tmp = json.load(open("bordi.json"))

        for b in tmp:
            border = Border(*b)
            self.scene.addItem(border)
            self.borders.append(border)
Beispiel #4
0
 def connect(self, node1, node2):
     #if node1 and node2 is the same,return None
     if node1 == node2:
         return None
     #if node1 connects node2,return None
     if node1 in node2.borders.keys() or node2 in node1.borders.keys():
         return None
     #if node1 or node2 is nont in self.nodes,return None
     if node1 not in self.nodes.values() or node2 not in self.nodes.values(
     ):
         return None
     border = Border(node1, node2, self)  #create new border
     #add the new border to nodes
     node1.addBorder(border)
     node2.addBorder(border)
     #add the new border to the list of figure
     self.borders.append(border)
     return border
Beispiel #5
0
def main():
    from border import Border
    from whiteboardView import cvHelper
    b = Border()
    b.lineInterceptForm((1, 0), 3, (1, 6.3), 2.3)
Beispiel #6
0
class WhiteboardView:
    def __init__(self, whiteboard, debug=False, prod=False):
        self.p = whiteboard
        self.upcount = 0
        self.debug = debug
        self.prod = prod
        self.border = None
        self.penDown = False
        self.lastPen = None
        self.calibrating = False
        self.framesToSkip = 10
        self.corners = 0
        self.video = False
        self.ports = [4545, 4546, 4547, 4548]
        self.s = socket.socket()
        self.videoName = None
        self.videoWriter = None
        #Socket for video stream
        self.videosocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # opens socket to camera that is streaming video
    def connect(self):
        sleep(2)
        # multiple ports incase one is taken
        for port in self.ports:
            try:
                if self.debug:
                    print((self.p.slaveIP, port))
                self.s.connect((self.p.slaveIP, port))
                return
            except:
                print('port {} failed'.format(port))
                pass

    # sends up message to master whiteboard
    def up(self):
        self.penDown = False
        self.p.handle('up')
        self.upcount = 0

    #sends down message to master whiteboard
    # param pos is the position of the LED
    def down(self, pos):
        self.upcount = 0
        self.penDown = True
        self.p.handle("down," + str(pos[0]) + ',' + str(pos[1]))

    # sends LED position to master whiteboardd
    # param pos is the position of the LED
    def newLEDPos(self, pos):
        self.lastPen = pos
        self.p.handle(str(pos[0]) + ',' + str(pos[1]))
        #draw

    # Some logic to determine what message gets sent to master whiteboard
    # param LED is the coordinates of the touch
    def sendTouch(self, LED):
        LEDx, LEDy = LED
        if self.penDown:
            #checking distance between pen strokes -- don't want misfires to draw lines
            if self.lastPen is not None:
                # if lest pen stroke is more than 10 pixels away send up then down to stop lines from being drawn
                if abs(self.lastPen[0] - LEDx) > 10 or abs(self.lastPen[1] -
                                                           LEDy) > 10:
                    self.up()
                    self.down((LEDx, LEDy))
            self.newLEDPos((LEDx, LEDy))
        else:
            self.down((LEDx, LEDy))

    # checks if border is found.  Tries to find it if it is not.
    # param img is the image to check for boarder
    # returns true if border is found, false otherwise
    def borderCheck(self, img):
        #CHECKING FOR BORDER
        if self.debug:
            print('borderCheck')
        if self.border is None:
            self.border = Border(debug=self.debug)
            if self.prod:
                pass
        # preps the image recieved to find the corners
        if self.corners < 4:
            img1 = cvHelper.colorSelect2(img.copy())
            img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

            # Tells the master whiteboard to display the top left corner
            if self.corners == 0:
                #topLeft, NW
                print('nw')
                if not self.calibrating:
                    self.p.calibNW()
                    self.calibrating = True
                    self.framesToSkip = 10
                # wait a couple of frames to make sure we are detecting the calibration screen
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'topleft'):
                        print('found nw')
                        self.corners += 1
                        self.calibrating = False
                        self.framesToSkip = 10
                else:
                    self.framesToSkip -= 1
            # Tells the master whiteboard to display the top right corner
            elif self.corners == 1:
                #topRight, NE
                print('ne')
                if not self.calibrating:
                    self.p.calibNE()
                    self.calibrating = True
                    self.framesToSkip = 10
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'topright'):
                        self.calibrating = False
                        print('found ne')
                        self.corners += 1
                        self.framesToSkip = 10
                else:
                    self.framesToSkip -= 1
            # Tells the master whiteboard to display the bottom left corner
            elif self.corners == 2:
                #bottomleft, SW
                print('sw')
                if not self.calibrating:
                    self.p.calibSW()
                    self.calibrating = True
                    self.framesToSkip = 5
                # wait a couple of frames to make sure we are detecting the calibration screen
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'bottomleft'):
                        print('found sw')
                        self.calibrating = False
                        self.corners += 1
                else:
                    self.framesToSkip -= 1
            # Tells the master whiteboard to display the bottom right corner
            elif self.corners == 3:
                #bottomright, SE
                print('se')
                if not self.calibrating:
                    self.p.calibSE()
                    self.calibrating = True
                    self.framesToSkip = 5
                # wait a couple of frames to make sure we are detecting the calibration screen
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'bottomright'):
                        print('found se')
                        self.calibrating = False
                        self.corners += 1
                        self.p.doneCalib()
                else:
                    self.framesToSkip -= 1
        else:
            if self.debug:
                print('not checking for border')
            return True

    # Step through the video frame by frame.  Holds the logic of the image recognition
    # param img is the current frame from the video
    def nextFrame(self, img):
        if self.debug:
            print("next Frame")
            cv2.waitKey(1)

        #checks if border exists.  If it hasn't continue to look for it
        if not self.borderCheck(img):
            return

        #SHOW BORDER
        if self.debug:
            box = np.int0(self.border.borderboundries)
            img2 = img.copy()
            img2 = cv2.drawContours(img2, [box], 0, (255, 0, 255), 2)

        #CHECKING FOR LED
        img1 = cvHelper.colorSelect(img.copy())
        img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
        LED = self.detectLED(img1)
        if LED is not None:
            LEDx, LEDy = self.border.getPositionOfPoint(LED)
            if self.debug:
                img2 = cv2.circle(img2, LED, 5, (0, 255, 0), 2)
                print((LEDx, LEDy))
            if self.prod:
                self.sendTouch((LEDx, LEDy))
        else:
            if self.debug:
                print('No LED')
            if self.prod:
                if self.penDown:
                    self.up()

        if self.debug:
            cv2.imshow('img2', img2)

    # Detects the LED by grabbing all the white and finding the clusters of colored pixels.
    # param img is the binary (greyscaled) image to find the LED
    # returns the coordinates of the detected LED1
    def detectLED(self, img):
        #cv modes and methods
        modes = [
            cv2.RETR_EXTERNAL, cv2.RETR_LIST, cv2.RETR_CCOMP, cv2.RETR_TREE,
            cv2.RETR_FLOODFILL
        ]
        methods = [cv2.CHAIN_APPROX_NONE, cv2.CHAIN_APPROX_SIMPLE]
        #contours from image
        _, contours, _ = cv2.findContours(img, modes[0], methods[1])
        #sorted by smalles perimeters first
        cv2.imshow('detectLED', img)
        contours = sorted(contours, key=lambda x: cv2.arcLength(x, True))
        print(len(contours))

        #cycle through contours to find LED
        for c in contours:
            #weed out contours that are too large or too small
            if cv2.arcLength(c, False) < 15 or cv2.arcLength(c, True) > 60:
                continue
            #smallest circle closing the contour
            (x, y), _ = cv2.minEnclosingCircle(c)
            x = int(x)
            y = int(y)
            #return first in circle.
            #TODO get more specific?
            if self.border.inBorder((x, y)):
                return (x, y)
        return None

    # this method sets everything up to be recalibrated.
    # called by the master whiteboard
    def recalibrate(self):
        self.border = None
        self.penDown = False
        self.lastPen = None
        self.calibrating = False
        self.corners = 0

    # this method sets the file path to save the video
    # called by the master whiteboard
    # param filePath is the filepath to save the video
    def save(self, filePath):
        self.videoName = filePath
        print(filePath)
        sleep(2)

    # this method reads images sent over a socket via the slave whiteboard and calls nextFrame for every frame
    def runVideo(self):
        self.connect()
        if self.debug:
            print("runVideo")
        connection = self.s.makefile('rb')
        fourcc = cv2.VideoWriter_fourcc(*'XVID')
        # how to save the video ##### NO SOUND
        self.videoWriter = cv2.VideoWriter('whiteboardVideo.avi', fourcc, 15,
                                           (1280, 720))
        while True:
            try:
                #Socket first sends how long the image will be
                imLen = struct.unpack('<L',
                                      connection.read(
                                          struct.calcsize('<L')))[0]
                while not imLen:
                    if self.debug:
                        print("Waiting for imLen")
                    #assume network issues for no imLen
                    imLen = struct.unpack(
                        '<L', connection.read(struct.calcsize('<L')))[0]
                if self.debug:
                    print('imLen: {}'.format(imLen))

                stream = io.BytesIO()
                stream.write(connection.read(imLen))
                #data is the image recieved from the stream converted for opencv
                data = np.fromstring(stream.getvalue(), dtype=np.uint8)
                img = cv2.imdecode(data, 1)
                cv2.imshow('original', img)
                self.videoWriter.write(img)
                print('writing video')
                self.nextFrame(img)
            except Exception as e:
                print("Socket Error: whiteboardView.whiteboardView.runVideo")
                print(e)

    #this is mostly for testing. can break video frame by frame
    #video can be given via file path, camera port(as int), or via url
    #ex. /path/to/file, 0, tcp//@ip:port
    def runVideoFromPath(self, videoPath):
        self.video = True
        if self.debug:
            print("runVideo({})".format(videoPath))
        cap = cv2.VideoCapture(videoPath)

        ret, img = cap.read()
        if not ret and self.debug:
            print("no video")
        while ret:
            self.nextFrame(img)
            if self.debug:
                cv2.waitKey(0)
            ret, img = cap.read()

    # called by Master whiteboard to close all sockets and save/delete video found
    def close(self):
        self.videoWriter.release()
        if self.debug:
            print('whiteboardView.close')
        self.s.close()
        if self.videoName is None:
            os.remove('whiteboardVideo.avi')
            pass
        else:
            os.rename('whiteboardVideo.avi', self.videoName)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
Beispiel #7
0
    def borderCheck(self, img):
        #CHECKING FOR BORDER
        if self.debug:
            print('borderCheck')
        if self.border is None:
            self.border = Border(debug=self.debug)
            if self.prod:
                pass
        # preps the image recieved to find the corners
        if self.corners < 4:
            img1 = cvHelper.colorSelect2(img.copy())
            img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

            # Tells the master whiteboard to display the top left corner
            if self.corners == 0:
                #topLeft, NW
                print('nw')
                if not self.calibrating:
                    self.p.calibNW()
                    self.calibrating = True
                    self.framesToSkip = 10
                # wait a couple of frames to make sure we are detecting the calibration screen
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'topleft'):
                        print('found nw')
                        self.corners += 1
                        self.calibrating = False
                        self.framesToSkip = 10
                else:
                    self.framesToSkip -= 1
            # Tells the master whiteboard to display the top right corner
            elif self.corners == 1:
                #topRight, NE
                print('ne')
                if not self.calibrating:
                    self.p.calibNE()
                    self.calibrating = True
                    self.framesToSkip = 10
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'topright'):
                        self.calibrating = False
                        print('found ne')
                        self.corners += 1
                        self.framesToSkip = 10
                else:
                    self.framesToSkip -= 1
            # Tells the master whiteboard to display the bottom left corner
            elif self.corners == 2:
                #bottomleft, SW
                print('sw')
                if not self.calibrating:
                    self.p.calibSW()
                    self.calibrating = True
                    self.framesToSkip = 5
                # wait a couple of frames to make sure we are detecting the calibration screen
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'bottomleft'):
                        print('found sw')
                        self.calibrating = False
                        self.corners += 1
                else:
                    self.framesToSkip -= 1
            # Tells the master whiteboard to display the bottom right corner
            elif self.corners == 3:
                #bottomright, SE
                print('se')
                if not self.calibrating:
                    self.p.calibSE()
                    self.calibrating = True
                    self.framesToSkip = 5
                # wait a couple of frames to make sure we are detecting the calibration screen
                if self.framesToSkip == 0:
                    if self.border.findCorner(img1, 'bottomright'):
                        print('found se')
                        self.calibrating = False
                        self.corners += 1
                        self.p.doneCalib()
                else:
                    self.framesToSkip -= 1
        else:
            if self.debug:
                print('not checking for border')
            return True
Beispiel #8
0
from turtle import Screen, Turtle
from snake import Snake
from food import Food
from scoreboard import Scoreboard
from border import Border
import time

screen = Screen()
screen.setup(width=610, height=610)
screen.bgcolor("OliveDrab3")
screen.title("SNAKE")
screen.tracer(0)

border = Border()
snake = Snake()
food = Food()
score = Scoreboard()

game_is_on = True

screen.listen()
screen.onkey(snake.up, "w")
screen.onkey(snake.down, "s")
screen.onkey(snake.left, "a")
screen.onkey(snake.right, "d")

score.explanation()

while game_is_on:
    score.write_score()
    # animation settings
Beispiel #9
0
# -*- coding: cp1252 -*-

import pygame.sprite
import pygame
from border import Border

defaultBorder = Border(0, 0)
defaultForeground = (255, 255, 255)
defaultBackground = (0, 0, 0)
disabeledOverlay = (150, 150, 150, 150)


class Widget(pygame.sprite.DirtySprite):
    """
    Underlying class for interactive GUI-objects with PyGame;
    extends pygame.sprite.DirtySprite
    intended for use together with pygame.sprite.LayeredDirty
    """
    def __init__(self, x, y, width, height):
        """
        Initialisation of a Widget

        parameters:     int x-coordinate of the Widget (left)
                        int y-coordinate of the Widget (top)
                        int width of the Widget
                        int height of the Widget
        return values:  -
        """
        super(Widget, self).__init__()
        self.image = pygame.Surface((width, height), pygame.SRCALPHA, 32)
        self._bounds = self.image.get_rect().move(x, y)
Beispiel #10
0
    def generateRivers(self):
        self.rivers = []
        self.markOceans()
        self.calcBorderElevation()
        for site in self.worldSites.items():
            if site[1].elevation in range(3):
                neighbouringWater = None
                idx = 0
                for neighbour in site[1].neighbours:
                    if self.worldSites[neighbour].elevation < 0 and neighbouringWater == None:
                        neighbouringWater = neighbour
                        break
                if neighbouringWater != None:
                    for neighbour in site[1].neighbours:
                        if self.worldSites[neighbour].hasNeighbour(neighbouringWater) and self.worldSites[neighbour].elevation >= 0:
                            newRiver = []
                            isReversed = False
                            for edge in self.worldSites[neighbouringWater].borders:
                                if edge.start == site[1].borders[idx].end or edge.end == site[1].borders[idx].end:
                                    isReversed = True
                                    break
                            if isReversed:
                                reversedBorder = Border(site[1].borders[idx].end, site[1].borders[idx].start)
                                reversedBorder.elevation = site[1].borders[idx].elevation
                                newRiver.append((site[0], idx, reversedBorder))
                            else:
                                newRiver.append((site[0], idx, site[1].borders[idx]))
                            self.rivers.append(newRiver)
                            self.buildRiver(site[0], neighbour, newRiver, self.rivers)
                            break
                        idx += 1

        filteredRivers = [river for river in self.rivers if len(river) > 9 and abs(river[-1][2].elevation - river[0][2].elevation) > 5]
        self.rivers = []
        for filteredRiver in filteredRivers:
            hasHits = False
            for part in filteredRiver:
                for river in self.rivers:
                    for riverPart in river:
                        if (part[2].start == riverPart[2].start or 
                            part[2].end == riverPart[2].start or 
                            part[2].start == riverPart[2].end or 
                            part[2].end == riverPart[2].end):
                            hasHits = True
                            break
                    if hasHits:
                        break
                if hasHits:
                    break
            if not hasHits:
                self.rivers.append(filteredRiver)

        for river in self.rivers:
            step = int(len(river)/8)
            width = 8
            idx = 0
            for part in river:
                self.worldSites[part[0]].borders[part[1]].isRiver = True
                self.worldSites[part[0]].borders[part[1]].riverWidth = width
                idx += 1
                if idx == step:
                    idx = 0
                    width -= 1
        print("Result:")
        print("Rivers: ", len(self.rivers))
Beispiel #11
0
mixer.music.play(-1)

SCREEN_WIDTH = 900
SCREEN_HEIGHT = 700

turtle.colormode(255)

# screen setup
screen = turtle.Screen()
screen.tracer(0)
screen.setup(width=SCREEN_WIDTH, height=SCREEN_HEIGHT)
screen.bgcolor('grey')
screen.title("Pong Game")

# Border setup
border = Border(s_width=SCREEN_WIDTH, s_height=SCREEN_HEIGHT)

# paddle setup
paddle = Paddle(border_half_height=border.border_half_height,
                border_half_width=border.border_half_width)
paddle.goto((-1) * (SCREEN_WIDTH / 2 - 60), 0)

# ball setup
ball = Ball(border_half_height=border.border_half_height,
            border_half_width=border.border_half_width)

# score setup
score = Score(s_width=SCREEN_WIDTH, s_height=SCREEN_HEIGHT)

# level setup
level = Level(s_width=SCREEN_WIDTH, s_height=SCREEN_HEIGHT)
Beispiel #12
0
def main():
    # TODO 1: Configure screen
    screen = Screen()
    screen.setup(width=SCREEN_WIDTH, height=SCREEN_HEIGHT)
    screen.bgcolor(SCREEN_BACKGROUND_COLOR)
    screen.tracer(0)

    # Add borders
    border = Border()
    border.createBorder()

    # TODO 2: Configure initial snake
    snake = Snake()
    food = Food()
    scoreboard = Scoreboard()

    # TODO 3: Move the snake
    screen.listen()
    screen.onkey(snake.up, "Up")
    screen.onkey(snake.down, "Down")
    screen.onkey(snake.left, "Left")
    screen.onkey(snake.right, "Right")

    #global paused

    #def unpause():
    #    global paused
    #    paused = not paused

    #screen.onkey(unpause, "p")

    game_is_on = True
    while game_is_on:
        #while paused:
        #    sleep(0.2)
        screen.update()
        sleep(SLEEP_TIME)
        snake.move()

        # TODO 4: Detect collision with food
        snake_food_collision_distance = (
            food.width() + snake.head.width()) / 2 - COLLISION_ERROR
        if snake.head.distance(food) < snake_food_collision_distance:
            scoreboard.score += 1
            snake.add_segment()
            food.refresh()
            for segment in snake.tail:
                while segment.position() == food.position():
                    food.clear()
                    food.refresh()
            scoreboard.refresh()

        # TODO 5: Detect collision with walls
        pass_x_wall = (
            snake.head.xcor() < -SCREEN_WIDTH / 2 + snake.head.width()
            or snake.head.xcor() > SCREEN_WIDTH / 2 - snake.head.width())
        pass_y_wall = (
            snake.head.ycor() < -SCREEN_HEIGHT / 2 + snake.head.width()
            or snake.head.ycor() > SCREEN_HEIGHT / 2 - snake.head.width())
        wall_collision = pass_x_wall or pass_y_wall
        if wall_collision:
            scoreboard.resetHighestScore()
            snake.resetSnake()

        # TODO 6: Detect collision with tail
        tail_head_collision_distance = snake.head.width() - COLLISION_ERROR
        for segment in snake.tail[1:]:
            if segment.distance(snake.head) < tail_head_collision_distance:
                scoreboard.resetHighestScore()
                snake.resetSnake()

    screen.exitonclick()
Beispiel #13
0
if __name__ == "__main__":
    path = os.getcwd()
    screen = turtle.Screen()
    screen.setup(700,700)
    screen.bgpic(path + "/image/background.png")
    screen.title('Destroyer v1.0')
    # make Heros
    player = Heros(screen)
    turtle.listen()
    turtle.onkey(player.turnleft, 'Left')
    turtle.onkey(player.turnright,'Right')
    turtle.onkey(player.accelerate,'Up')
    turtle.onkey(player.deccelerate,'Down')
    # make Border
    border = Border()
    border.draw_border()
    # Compute Score
    score = Score()
    #Init Monsters
    monsterbox = []
    for i in range(random.randint(6, 12)):
        monsterbox.append(Monsters(screen))
    #Process
    check = False
    while True:
        # t = threading.Thread(target = player.move, args= ())
        player.move()
        # t.start()
        # t.join()
        for qv in monsterbox:
Beispiel #14
0
class Game:
    def __init__(self) -> None:
        self.update_action_depending_on_state = {
            GameState.PLAY: self.update_play_screen,
            GameState.MENU: self.update_menu_screen,
            GameState.PAUSE: self.update_pause_screen,
            GameState.GAME_OVER: self.update_game_over_screen,
        }
        self.state = GameState.MENU

        self.grid = Grid()
        self.menu = Menu()
        self.start_menu = StartMenu()
        self.border = Border()

        self.clock = pygame.time.Clock()
        self.running = True
        self.to_draw = True

        self.player = type(next_indicator.next_one)()
        self.create_new_player()

        self.fps = 0

    def create_new_player(self) -> None:
        self.player = type(next_indicator.next_one)()
        if s.is_shade_enabled:
            shade.shade = type(self.player)()
            shade.update_pos(self.player)
        next_indicator.change()

    def draw(self) -> None:
        if self.to_draw:
            self.to_draw = False
            utils.window_manager.window.fill(s.color_scheme["Background"])
            if (
                self.state == GameState.PLAY
                or self.state == GameState.PAUSE
                or self.state == GameState.GAME_OVER
            ):
                if s.is_shade_enabled:
                    shade.draw()
                self.player.draw()
                self.border.draw()
                next_indicator.draw()
                well.draw()
                interface.draw(self.state)
                if s.grid_enabled:
                    self.grid.draw()
            elif self.state == GameState.MENU:
                self.menu.draw()
            elif self.state == GameState.START_MENU:
                self.start_menu.draw()
            pygame.display.update()

    def run(self) -> None:
        while self.running:
            start = time()
            controller.get_keys()

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

            self.update_action_depending_on_state[self.state]()

            self.draw()
            self.clock.tick(s.FPS_CAP)
            self.fps = int(1 / (time() - start))

    def update_menu_screen(self) -> None:
        status = self.menu.update()

        if status == 9:
            self.running = False
        elif status == 2:
            self.state = GameState.PLAY
            self.player.reset_timers()
            self.to_draw = True
        elif status:
            self.to_draw = True

    def update_game_over_screen(self) -> None:
        if controller.just_pressed["Start"] or controller.just_pressed["Pause"]:
            self.to_draw = True
            self.state = GameState.MENU
            reset_game()
            next_indicator.change()
            self.create_new_player()

    def update_play_screen(self) -> None:
        interface.update_fps(str(self.fps))
        if controller.just_pressed["Pause"]:
            self.to_draw = True
            self.state = GameState.PAUSE
        self.player.update()
        if self.player.moved:
            if s.is_shade_enabled:
                shade.update_pos(self.player)
            self.to_draw = True
        if self.player.landed:
            self.create_new_player()
            if self.is_game_over():
                self.state = GameState.GAME_OVER
                self.save_score()

    def update_pause_screen(self) -> None:
        if controller.just_pressed["Pause"]:
            self.to_draw = True
            self.state = GameState.PLAY

    def is_game_over(self) -> bool:
        for i in self.player.body:
            cell_x = i.position.x // s.CELL_SIZE
            cell_y = i.position.y // s.CELL_SIZE
            if well.cubes_in_well[cell_y][cell_x - 1]:
                return True
        return False

    def save_score(self):
        if stats.high_score.score_list.is_enough(stats.score.score):
            stats.high_score.score_list.add_score(
                stats.score.player_name, stats.score.score
            )
            self.menu.update_score()