def save_highscores(self, score): """Update highscores, storing to file.""" logger.debug("Save highscores") logger.info( "FINAL SCORE <%s>: %s moves and %s pushes in %s steps", "FINAL SCORE <%s>: %s puzzles with %s moves and %s pushes in %s steps, currently %s boxes on goal", self.current_player.name, *score, ) self._highscores.append(( self.current_player.name, reduce_score(score), )) self._highscores.append(( self.current_player.name, reduce_score(*score), )) self._highscores = sorted(self._highscores, key=lambda s: s[1])[:MAX_HIGHSCORES] with open(HIGHSCORE_FILE, "w") as outfile: json.dump(self._highscores, outfile)
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
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
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