コード例 #1
0
async def main_loop(queue):
    """Processes events from server and display's."""
    global SPRITES, SCREEN

    main_group = pygame.sprite.LayeredUpdates()
    boxes_group = pygame.sprite.OrderedUpdates()

    logging.info("Waiting for map information from server")
    state = await queue.get()  # first state message includes map information
    logging.debug("Initial game status: %s", state)
    newgame_json = json.loads(state)

    GAME_SPEED = newgame_json["fps"]
    try:
        mapa = Map(newgame_json["map"])
    except (KeyError, FileNotFoundError):
        mapa = Map("levels/1.xsb")  # Fallback to initial map
    SCREEN = pygame.display.set_mode(scale(mapa.size))
    SPRITES = pygame.image.load("data/sokoban.png").convert_alpha()

    BACKGROUND = draw_background(mapa)
    SCREEN.blit(BACKGROUND, (0, 0))
    main_group.add(Keeper(pos=mapa.keeper))

    state = {
        "score": 0,
        "player": "player1",
        "keeper": mapa.keeper,
        "boxes": mapa.boxes,
    }

    new_event = True
    while True:
        SCREEN.blit(BACKGROUND, (0, 0))
        pygame.event.pump()
        if pygame.key.get_pressed()[pygame.K_ESCAPE]:
            asyncio.get_event_loop().stop()

        main_group.clear(SCREEN, clear_callback)
        boxes_group.clear(SCREEN, clear_callback)

        if "score" in state and "player" in state:
            text = f"m, p, s: {state['score']}"
            draw_info(SCREEN, text.zfill(6), (5, 1))
            text = str(state["player"]).rjust(32)
            draw_info(SCREEN, text, (4000, 1))

        if "level" in state:
            w, _ = draw_info(SCREEN, "level: ", (SCREEN.get_width() / 2, 1))
            draw_info(
                SCREEN,
                f"{state['level']}",
                (SCREEN.get_width() / 2 + w, 1),
                color=(200, 20, 20),
            )

        if "boxes" in state:
            boxes_group.empty()
            for box in state["boxes"]:
                boxes_group.add(
                    Box(
                        pos=box,
                        stored=mapa.get_tile(box)
                        in [Tiles.GOAL, Tiles.BOX_ON_GOAL],
                    ))

        boxes_group.draw(SCREEN)
        main_group.draw(SCREEN)

        # Highscores Board
        if "highscores" in state and "player" in state:
            if new_event:
                highscores = state["highscores"]
                highscores.append(
                    (f"<{state['player']}>", reduce_score(state["score"])))

                highscores = sorted(highscores, key=lambda s: s[1])
                highscores = highscores[:len(RANKS)]

                HIGHSCORES = pygame.Surface((256, 280))
                HIGHSCORES.fill((30, 30, 30))

                COLS = [20, 80, 150]

                draw_info(HIGHSCORES, "THE 10 BEST PLAYERS", (20, 10),
                          COLORS["white"])
                for value, column in zip(["RANK", "SCORE", "NAME"], COLS):
                    draw_info(HIGHSCORES, value, (column, 30),
                              COLORS["orange"])

                for i, highscore in enumerate(highscores):
                    color = (
                        random.randrange(66, 222),
                        random.randrange(66, 222),
                        random.randrange(66, 222),
                    )
                    for value, column in zip(
                        [RANKS[i + 1],
                         str(highscore[1]), highscore[0]], COLS):
                        draw_info(HIGHSCORES, value, (column, 60 + i * 20),
                                  color)

            SCREEN.blit(
                HIGHSCORES,
                (
                    (SCREEN.get_width() - HIGHSCORES.get_width()) / 2,
                    (SCREEN.get_height() - HIGHSCORES.get_height()) / 2,
                ),
            )

        if "keeper" in state:
            main_group.update(state["keeper"])

        pygame.display.flip()

        try:
            state = json.loads(queue.get_nowait())
            new_event = True
            if "map" in state:
                logger.debug("New Level!")
                # New level! lets clean everything up!
                try:
                    mapa = Map(state["map"])
                except FileNotFoundError:
                    logger.error(
                        "Can't find levels/%s.xsb, means we have a WINNER!",
                        state["level"],
                    )
                    continue
                SCREEN = pygame.display.set_mode(scale(mapa.size))
                BACKGROUND = draw_background(mapa)
                SCREEN.blit(BACKGROUND, (0, 0))

                boxes_group.empty()
                main_group.empty()
                main_group.add(Keeper(pos=mapa.keeper))
                pygame.display.flip()

        except asyncio.queues.QueueEmpty:
            await asyncio.sleep(1.0 / GAME_SPEED)
            new_event = False
            continue
コード例 #2
0
ファイル: game.py プロジェクト: alex-pt01/Sokoban_IA
class Game:
    """Representation of a Game run."""

    def __init__(self, level=1, timeout=TIMEOUT, player=None):
        logger.info("Game(level=%s)", level)
        self.puzzles = 0 #puzzles completed
        self.level = level
        if player:
            self._running = True
            self._player_name = player
        else:
            self._running = False
        self._timeout = timeout
        self._step = 0
        self._total_steps = 0
        self._state = {}
        self._papertrail = ""  # keeps track of all steps made by the player
        self._moves = 0
        self._pushes = 0
        self.map = None
        self._lastkeypress = ""

        self.next_level(self.level)

    def info(self):
        """Initial Static information about the game."""
        return {
            "fps": GAME_SPEED,
            "timeout": self._timeout,
            "map": f"levels/{self.level}.xsb",
        }

    @property
    def papertrail(self):
        """String containing all pressed keys by agent."""
        return self._papertrail

    @property
    def running(self):
        """Status on game."""
        return self._running

    @property
    def score(self):
        """Calculus of the current score."""
        return self.puzzles, self._moves, self._pushes, self._total_steps + self._step, self.map.on_goal

    def stop(self):
        """Stop the game."""
        if self._step:
            logger.info("GAME OVER at %s", self._step)
        self._running = False

    def next_level(self, level):
        """Update all state variables to a new level."""
        self.puzzles += 1
        self._total_steps += self._step
        self._step = 0
        self._lastkeypress = ""
        self._papertrail += "," 
        self.level = level
        try:
            self.map = Map(f"levels/{level}.xsb")
            logger.info("NEXT LEVEL: %s", level)
        except FileNotFoundError:
            logger.info("No more levels... You WIN!")
            self.stop()
            return

    def keypress(self, key):
        """Update locally last key pressed."""
        self._lastkeypress = key

    def move(self, cur, direction):
        """Move an entity in the game."""
        assert direction in "wasd", f"Can't move in {direction} direction"

        cx, cy = cur
        ctile = self.map.get_tile(cur)

        npos = cur
        if direction == "w":
            npos = cx, cy - 1
        if direction == "a":
            npos = cx - 1, cy
        if direction == "s":
            npos = cx, cy + 1
        if direction == "d":
            npos = cx + 1, cy

        # test blocked
        if self.map.is_blocked(npos):
            logger.debug("Blocked ahead")
            return False
        if self.map.get_tile(npos) in [
            Tiles.BOX,
            Tiles.BOX_ON_GOAL,
        ]:  # next position has a box?
            if ctile & Tiles.MAN == Tiles.MAN:  # if you are the keeper you can push
                if not self.move(npos, direction):  # as long as the pushed box can move
                    return False
            else:  # you are not the Keeper, so no pushing
                return False

            self._moves += 1

        # actually update map
        self.map.set_tile(npos, ctile)
        self.map.clear_tile(cur)
        return True

    def update_keeper(self):
        """Update the location of the Keeper."""
        if self._lastkeypress == "":
            return GameStatus.NO_OPERATION
        try:
            # Update position
            self.move(self.map.keeper, self._lastkeypress)
            self._papertrail += self._lastkeypress
        except AssertionError:
            logger.error(
                "Invalid key <%s> pressed. Valid keys: w,a,s,d", self._lastkeypress
            )
        finally:
            self._lastkeypress = ""  # remove inertia

        if self.map.completed:
            logger.info("Level %s completed", self.level)
            self.next_level(self.level + 1)
            return GameStatus.NEW_MAP

        return GameStatus.RUNNING

    async def next_frame(self):
        """Calculate next frame."""
        await asyncio.sleep(1.0 / GAME_SPEED)

        if not self._running:
            logger.info("Waiting for player 1")
            return

        self._step += 1
        if self._step >= self._timeout:
            self.stop()

        if self._step % 100 == 0:
            logger.debug("[%s] SCORE %s", self._step, self.score)

        game_status = self.update_keeper()

        self._state = {
            "player": self._player_name,
            "level": self.level,
            "step": self._step,
            "score": self.score,
            "keeper": self.map.keeper,
            "boxes": self.map.boxes,
        }

        return game_status

    @property
    def state(self):
        """Contains the state of the Game."""
        # logger.debug(self._state)
        return json.dumps(self._state)
コード例 #3
0
class SokobanDomain(SearchDomain):
    def __init__(self, filename):
        self.level = filename
        self.map = Map(filename)
        self.states = []
        self.emptyMap()

    def fillMap(self, state):
        for box in state["boxes"]:
            self.map.set_tile(box, Tiles.BOX)
        self.map.set_tile(state["player"], Tiles.MAN)

    def emptyMap(self):
        self.map.clear_tile(self.map.keeper)
        boxs = self.map.boxes
        for box in boxs:
            self.map.clear_tile(box)

    def actions(self, state):
        self.fillMap(state)
        actions = []
        for direction in ["w", "a", "s", "d"]:
            if (self.can_move(self.map.keeper, direction)):
                actions += [direction]
        self.emptyMap()
        return actions

    def can_move(self, cur, direction):
        """Move an entity in the game."""
        assert direction in "wasd", f"Can't move in {direction} direction"

        cx, cy = cur
        ctile = self.map.get_tile(cur)

        npos = cur
        if direction == "w":
            npos = cx, cy - 1
        if direction == "a":
            npos = cx - 1, cy
        if direction == "s":
            npos = cx, cy + 1
        if direction == "d":
            npos = cx + 1, cy

        # test blocked
        if self.map.is_blocked(npos):
            return False
        if self.map.get_tile(npos) in [
                Tiles.BOX,
                Tiles.BOX_ON_GOAL,
        ]:  # next position has a box?
            if ctile & Tiles.MAN == Tiles.MAN:  # if you are the keeper you can push
                if not self.move(
                        npos, direction):  # as long as the pushed box can move
                    return False
            else:  # you are not the Keeper, so no pushing
                return False

        return True

    def move(self, cur, direction):
        """Move an entity in the game."""
        assert direction in "wasd", f"Can't move in {direction} direction"

        cx, cy = cur
        ctile = self.map.get_tile(cur)

        npos = cur
        if direction == "w":
            npos = cx, cy - 1
        if direction == "a":
            npos = cx - 1, cy
        if direction == "s":
            npos = cx, cy + 1
        if direction == "d":
            npos = cx + 1, cy

        # test blocked
        if self.map.is_blocked(npos):
            return False
        if self.map.get_tile(npos) in [
                Tiles.BOX,
                Tiles.BOX_ON_GOAL,
        ]:  # next position has a box?
            if ctile & Tiles.MAN == Tiles.MAN:  # if you are the keeper you can push
                if not self.move(
                        npos, direction):  # as long as the pushed box can move
                    return False
            else:  # you are not the Keeper, so no pushing
                return False

        # actually update map
        self.map.set_tile(npos, ctile)
        self.map.clear_tile(cur)

        return True

    def result(self, state, action):
        self.fillMap(state)
        self.move(self.map.keeper, action)
        newstate = {}
        newstate["player"] = self.map.keeper
        newstate["boxes"] = self.map.boxes
        self.emptyMap()
        return newstate

    def cost(self, state, action):
        return 1

    def heuristic(self, state, goal):
        sum = 0
        list1 = state["boxes"]
        list2 = goal["boxes"]
        for i in range(len(list1)):
            sum += minimal_distance(list1[i], list2[i])
        return sum

    def satisfies(self, state, goal):
        self.fillMap(state)
        return self.map.completed

    def satisfies_box(self, box, goal):
        boxes = goal["boxes"]
        if box in boxes:
            return True
        return False
コード例 #4
0
async def main_loop(queue):
    """Processes events from server and display's."""
    global SPRITES, SCREEN

    main_group = pygame.sprite.LayeredUpdates()
    boxes_group = pygame.sprite.OrderedUpdates()

    logging.info("Waiting for map information from server")
    state = await queue.get()  # first state message includes map information
    logging.debug("Initial game status: %s", state)
    newgame_json = json.loads(state)

    GAME_SPEED = newgame_json["fps"]
    try:
        mapa = Map(newgame_json["map"])
    except (KeyError, FileNotFoundError):
        mapa = Map("levels/1.xsb")  # Fallback to initial map
    map_x, map_y = mapa.size
    SCREEN = pygame.display.set_mode(scale((map_x+MAP_X_INCREASE, map_y+MAP_Y_INCREASE)))
    SPRITES = pygame.image.load("data/sokoban.png").convert_alpha()

    BACKGROUND = draw_background(mapa)
    SCREEN.blit(BACKGROUND, (0, 0))
    main_group.add(Keeper(pos=mapa.keeper))

    state = {
        "score": 0,
        "player": "player1",
        "keeper": mapa.keeper,
        "boxes": mapa.boxes,
    }

    new_event = True

    player = last_player = state['player']

    hs = HighScoresFetch(name=state['player'])
    best_entry = None

    while True:
        if "player" in state:
            curr_player = state['player']

        SCREEN.blit(BACKGROUND, (0, 0))
        pygame.event.pump()
        if pygame.key.get_pressed()[pygame.K_ESCAPE]:
            asyncio.get_event_loop().stop()

        main_group.clear(SCREEN, clear_callback)
        boxes_group.clear(SCREEN, clear_callback)

        # size of each square
        map_square_size = (SCREEN.get_width()/(map_x+MAP_X_INCREASE), SCREEN.get_height()/(map_y+MAP_Y_INCREASE))
        # width of extra space added to the map, except the separating black wall
        extra_available_space_width = map_square_size[0]*(MAP_X_INCREASE-1)

        if "score" in state and "player" in state:
            if last_player != curr_player:
                hs = HighScoresFetch(name=state['player'])

                if hs.data != []:
                    best_entry = hs.get_best_entry(type="max", key="score")

                    split_timestamp = best_entry["timestamp"].split("T")
                    
                    # adjust best_entry dict
                    best_entry["timestamp"] = split_timestamp[0]
                    best_entry["timestamp2"] = split_timestamp[1]

                    formated_col_l, formated_col_r = [SCORE_INFO[d] for d in DATA_INDEX_BEST_ROUND], [str(best_entry[info]) for info in DATA_INDEX_BEST_ROUND]
                    fixed_width = get_largest_width_for_table(formated_col_l, formated_col_r, BEST_ROUND_TITLE)+RIGHT_INFO_MARGIN_RIGHT

                player = state['player']

                last_player = curr_player
            
            # draw player info
            player_h_from_top = SCREEN.get_height() - RIGHT_INFO_MARGIN_BOTTOM
            player_w, _ = get_draw_size(player)
            draw_info(SCREEN, player, (SCREEN.get_width()-player_w-RIGHT_INFO_MARGIN_RIGHT, player_h_from_top), COLORS["light_blue"])
            draw_info(SCREEN, "Player: ", (SCREEN.get_width()-player_w-get_draw_size("Player: ")[0]-RIGHT_INFO_MARGIN_RIGHT-5, player_h_from_top), COLORS["white"])
   
            current_height = RIGHT_INFO_MARGIN_TOP

            if hs != None and hs.data != []:
                # table for best round
                current_height = draw_table_right_top(SCREEN, extra_available_space_width, (formated_col_l, COLORS["black"]), (formated_col_r, COLORS["white"]), (BEST_ROUND_TITLE, COLORS["yellow"]), fixed_width, (RIGHT_INFO_MARGIN_LEFT, current_height, RIGHT_INFO_MARGIN_RIGHT))
            
            # some conditions to coop with state['score']
            if not isinstance(state['score'], int) and len(state['score']) > len(DATA_INDEX_CURR_ROUND):
                curr_round_data_fetch = [str(state['score'][i+1]) for i in range(len(DATA_INDEX_CURR_ROUND))]

                # if there is no data from best round, adapt the fixed size to the data of current round
                if hs.data == []:
                    fixed_width = get_largest_width_for_table(curr_round_data_fetch, DATA_INDEX_CURR_ROUND, CURR_ROUND_TITLE)+RIGHT_INFO_MARGIN_RIGHT
                else:
                    # if there is best round table, then create a separation with the current round table
                    current_height+= RIGHT_INFO_MARGIN_TOP

                # table for current round
                current_height = draw_table_right_top(SCREEN, extra_available_space_width, (DATA_INDEX_CURR_ROUND, COLORS["black"]), (curr_round_data_fetch, COLORS["white"]), (CURR_ROUND_TITLE, COLORS["red"]), fixed_width, (RIGHT_INFO_MARGIN_LEFT, current_height, RIGHT_INFO_MARGIN_RIGHT))

        if "level" in state:
            draw_info(
                SCREEN,
                f"{state['level']}",
                (SCREEN.get_width()-extra_available_space_width+RIGHT_INFO_MARGIN_LEFT, current_height+RIGHT_INFO_MARGIN_TOP),
                color=COLORS["white"], size=50
            )
        
        if "level" not in state and "highscores" not in state:
            for i, word in enumerate(["Run a client  ", "to see scores!"]):
                word_w, word_h = get_draw_size(word)
                draw_info(SCREEN, word, (SCREEN.get_width()-center_text_margin(extra_available_space_width, word_w), RIGHT_INFO_MARGIN_TOP+word_h+i*20), COLORS["white"])

        if "boxes" in state:
            boxes_group.empty()
            for box in state["boxes"]:
                boxes_group.add(
                    Box(
                        pos=box,
                        stored=mapa.get_tile(box) in [Tiles.GOAL, Tiles.BOX_ON_GOAL],
                    )
                )

        boxes_group.draw(SCREEN)
        main_group.draw(SCREEN)

        # Highscores Board
        if "highscores" in state and "player" in state:
            if new_event:
                highscores = state["highscores"]
                highscores.append(
                    (f"<{state['player']}>", reduce_score(*state["score"]))
                )

                highscores = sorted(highscores, key=lambda s: s[1])
                highscores = highscores[: len(RANKS)]

                HIGHSCORES = pygame.Surface((256, 280))
                HIGHSCORES.fill((30, 30, 30))

                COLS = [20, 80, 150]

                draw_info(HIGHSCORES, "THE 10 BEST PLAYERS", (20, 10), COLORS["white"])
                for value, column in zip(["RANK", "SCORE", "NAME"], COLS):
                    draw_info(HIGHSCORES, value, (column, 30), COLORS["orange"])

                for i, highscore in enumerate(highscores):
                    color = (
                        random.randrange(66, 222),
                        random.randrange(66, 222),
                        random.randrange(66, 222),
                    )
                    for value, column in zip(
                        [RANKS[i + 1], str(highscore[1]), highscore[0]], COLS
                    ):
                        draw_info(HIGHSCORES, value, (column, 60 + i * 20), color)

            SCREEN.blit(
                HIGHSCORES,
                (
                    (SCREEN.get_width() - HIGHSCORES.get_width()) / 2,
                    (SCREEN.get_height() - HIGHSCORES.get_height()) / 2,
                ),
            )

        if "keeper" in state:
            main_group.update(state["keeper"])

        pygame.display.flip()

        try:
            state = json.loads(queue.get_nowait())
            new_event = True
            if "map" in state:
                logger.debug("New Level!")
                # New level! lets clean everything up!
                try:
                    mapa = Map(state["map"])
                except FileNotFoundError:
                    logger.error(
                        "Can't find levels/%s.xsb, means we have a WINNER!",
                        state["level"],
                    )
                    continue
                map_x, map_y = mapa.size
                SCREEN = pygame.display.set_mode(scale((map_x+MAP_X_INCREASE, map_y+MAP_Y_INCREASE)))
                BACKGROUND = draw_background(mapa)
                SCREEN.blit(BACKGROUND, (0, 0))

                boxes_group.empty()
                main_group.empty()
                main_group.add(Keeper(pos=mapa.keeper))
                pygame.display.flip()

        except asyncio.queues.QueueEmpty:
            await asyncio.sleep(1.0 / GAME_SPEED)
            new_event = False
            continue
コード例 #5
0
async def main_loop(queue):
    """Processes events from server and display's."""
    global SPRITES, SCREEN

    main_group = pygame.sprite.LayeredUpdates()
    boxes_group = pygame.sprite.OrderedUpdates()

    logging.info("Waiting for map information from server")
    state = await queue.get()  # first state message includes map information
    logging.debug("Initial game status: %s", state)
    newgame_json = json.loads(state)

    GAME_SPEED = newgame_json["fps"]
    try:
        mapa = Map(newgame_json["map"])
    except (KeyError, FileNotFoundError):
        mapa = Map("levels/1.xsb")  # Fallback to initial map
    map_x, map_y = mapa.size
    SCREEN = pygame.display.set_mode(
        scale((map_x + MAP_X_INCREASE, map_y + MAP_Y_INCREASE)))
    SPRITES = pygame.image.load("data/sokoban.png").convert_alpha()

    BACKGROUND = draw_background(mapa)
    SCREEN.blit(BACKGROUND, (0, 0))
    main_group.add(Keeper(pos=mapa.keeper))

    state = {
        "score": 0,
        "player": "player1",
        "keeper": mapa.keeper,
        "boxes": mapa.boxes,
    }

    new_event = True

    margin_top = 30
    margin_right = 30
    space_between_cols = 5

    last_player = state['player']

    data_index = [
        "level", "timestamp", "", "score", "total_moves", "total_pushes",
        "total_steps"
    ]
    hs = ""
    best_entry = ""

    while True:
        if "player" in state:
            curr_player = state['player']

        SCREEN.blit(BACKGROUND, (0, 0))
        pygame.event.pump()
        if pygame.key.get_pressed()[pygame.K_ESCAPE]:
            asyncio.get_event_loop().stop()

        main_group.clear(SCREEN, clear_callback)
        boxes_group.clear(SCREEN, clear_callback)

        if "score" in state and "player" in state:
            if last_player != curr_player:
                print("here")
                hs = HighScoresFetch(name=state['player'])
                last_player = curr_player

                best_entry = hs.get_best_entry(type="max", key="score")

            player = state['player']

            player_h = SCREEN.get_height() - 40
            player_w, _ = draw_info(SCREEN, player, (-4000, player_h))
            draw_info(SCREEN, player,
                      (SCREEN.get_width() - player_w - margin_right, player_h),
                      (58, 240, 240))
            player_title_w, _ = draw_info(SCREEN, "Player: ",
                                          (-4000, player_h))
            draw_info(SCREEN, "Player: ",
                      (SCREEN.get_width() - player_w - player_title_w -
                       margin_right - space_between_cols, player_h),
                      (255, 255, 255))

            if hs != "" and hs.data != []:
                bestround_pos = margin_top
                bestround_w, _ = draw_info(SCREEN, "Best Round",
                                           (-4000, bestround_pos))
                draw_info(SCREEN, "Best Round",
                          (SCREEN.get_width() - bestround_w - margin_right -
                           22, bestround_pos), (255, 242, 0))

                info_pos = bestround_pos + 35

                splitted = best_entry['timestamp'].split("T")
                info_w, _ = draw_info(SCREEN, splitted[0], (-4000, 0))
                title_info_w, _ = draw_info(SCREEN, "Data: ", (-4000, 0))
                title_fixed_size = info_w + title_info_w + margin_right + space_between_cols

                for i, info in enumerate(data_index):
                    curr_data_index = data_index[i]

                    if curr_data_index == "":
                        continue
                    else:
                        content = best_entry[info]

                    if curr_data_index == "timestamp":
                        splitted = content.split("T")

                        info_w, _ = draw_info(SCREEN, splitted[0],
                                              (-4000, info_pos + i * 20))
                        draw_info(SCREEN, splitted[0],
                                  (SCREEN.get_width() - info_w - margin_right,
                                   info_pos + i * 20), (255, 255, 255))
                        title_info_w, _ = draw_info(SCREEN, "Data: ",
                                                    (-4000, info_pos + i * 20))
                        draw_info(SCREEN, "Data: ",
                                  (SCREEN.get_width() - title_fixed_size,
                                   info_pos + i * 20))
                        info_w, _ = draw_info(SCREEN, splitted[1],
                                              (-4000, info_pos + i * 20))
                        draw_info(SCREEN, splitted[1],
                                  (SCREEN.get_width() - info_w - margin_right,
                                   info_pos + (i + 1) * 20), (255, 255, 255))
                        continue

                    if curr_data_index == "total_moves":
                        curr_data_index = "moves"

                    if curr_data_index == "total_pushes":
                        curr_data_index = "pushes"

                    if curr_data_index == "total_steps":
                        curr_data_index = "steps"

                    info_w, _ = draw_info(SCREEN, str(content),
                                          (-4000, info_pos + i * 20))
                    draw_info(SCREEN, str(content),
                              (SCREEN.get_width() - info_w - margin_right,
                               info_pos + i * 20), (255, 255, 255))
                    title_info_w, _ = draw_info(
                        SCREEN,
                        format_string(curr_data_index) + ": ",
                        (-4000, info_pos + i * 20))
                    draw_info(SCREEN,
                              format_string(curr_data_index) + ": ",
                              (SCREEN.get_width() - title_fixed_size,
                               info_pos + i * 20))

                curr_round_pos = 230
                curr_round_w, _ = draw_info(SCREEN, "Current Round",
                                            (-4000, curr_round_pos))
                draw_info(SCREEN, "Current Round",
                          (SCREEN.get_width() - curr_round_w - margin_right -
                           10, curr_round_pos), (255, 0, 0))

                info_pos = curr_round_pos + 35
                for i, curr_info in enumerate(["Moves", "Pushes", "Steps"]):
                    info_w, _ = draw_info(SCREEN, str(state['score'][i + 1]),
                                          (-4000, info_pos + i * 20))
                    draw_info(SCREEN, str(state['score'][i + 1]),
                              (SCREEN.get_width() - info_w - margin_right,
                               info_pos + i * 20), (255, 255, 255))
                    title_info_w, _ = draw_info(SCREEN, curr_info + ": ",
                                                (-4000, info_pos + i * 20))
                    draw_info(SCREEN, curr_info + ": ",
                              (SCREEN.get_width() - title_fixed_size,
                               info_pos + i * 20))

        if "level" in state:
            draw_info(SCREEN,
                      f"{state['level']}", (SCREEN.get_width() - 162, 335),
                      color=(255, 255, 255),
                      size=50)

        if "boxes" in state:
            boxes_group.empty()
            for box in state["boxes"]:
                boxes_group.add(
                    Box(
                        pos=box,
                        stored=mapa.get_tile(box)
                        in [Tiles.GOAL, Tiles.BOX_ON_GOAL],
                    ))

        boxes_group.draw(SCREEN)
        main_group.draw(SCREEN)

        # Highscores Board
        if "highscores" in state and "player" in state:
            if new_event:
                highscores = state["highscores"]
                highscores.append(
                    (f"<{state['player']}>", reduce_score(*state["score"])))

                highscores = sorted(highscores, key=lambda s: s[1])
                highscores = highscores[:len(RANKS)]

                HIGHSCORES = pygame.Surface((256, 280))
                HIGHSCORES.fill((30, 30, 30))

                COLS = [20, 80, 150]

                draw_info(HIGHSCORES, "THE 10 BEST PLAYERS", (20, 10),
                          COLORS["white"])
                for value, column in zip(["RANK", "SCORE", "NAME"], COLS):
                    draw_info(HIGHSCORES, value, (column, 30),
                              COLORS["orange"])

                for i, highscore in enumerate(highscores):
                    color = (
                        random.randrange(66, 222),
                        random.randrange(66, 222),
                        random.randrange(66, 222),
                    )
                    for value, column in zip(
                        [RANKS[i + 1],
                         str(highscore[1]), highscore[0]], COLS):
                        draw_info(HIGHSCORES, value, (column, 60 + i * 20),
                                  color)

            SCREEN.blit(
                HIGHSCORES,
                (
                    (SCREEN.get_width() - HIGHSCORES.get_width()) / 2,
                    (SCREEN.get_height() - HIGHSCORES.get_height()) / 2,
                ),
            )

        if "keeper" in state:
            main_group.update(state["keeper"])

        pygame.display.flip()

        try:
            state = json.loads(queue.get_nowait())
            new_event = True
            if "map" in state:
                logger.debug("New Level!")
                # New level! lets clean everything up!
                try:
                    mapa = Map(state["map"])
                except FileNotFoundError:
                    logger.error(
                        "Can't find levels/%s.xsb, means we have a WINNER!",
                        state["level"],
                    )
                    continue
                map_x, map_y = mapa.size
                SCREEN = pygame.display.set_mode(
                    scale((map_x + MAP_X_INCREASE, map_y + MAP_Y_INCREASE)))
                BACKGROUND = draw_background(mapa)
                SCREEN.blit(BACKGROUND, (0, 0))

                boxes_group.empty()
                main_group.empty()
                main_group.add(Keeper(pos=mapa.keeper))
                pygame.display.flip()

        except asyncio.queues.QueueEmpty:
            await asyncio.sleep(1.0 / GAME_SPEED)
            new_event = False
            continue