Source code for rbgame.menu

from typing import Any
import os
from pathlib import Path

import pygame
import pygame_menu
import pygame_menu.events
pygame.init()

from rbgame.game.game import RoboticBoardGame
from rbgame.game.consts import CELL_SIZE, COLOR2STR

def selection_placeholder_format(items: list[str]) -> str:
    """
    A function to specify what display in robot colors selector.

    :param items: List of selected items.
    :return: Formated text.
    """
    text = ', '.join(items) + ' selected'
    if len(items) <= 1:
        text += '. Too little selected colors.'
    return text

[docs] class RoboticBoardGameMenu: """ A simple menu to custom game parameters and animate the game process with these parameters. :param agent_fn: Parameter - agent's type, argument - a function with the signature :code:`f(num_robots: int, with_battery: bool) -> BaseAgent`. For example: .. code-block:: python RoboticBoardGameMenu(astar=astar_constructor, dqn=dqn_constuctor) """ def __init__( self, **agent_fn, ): self.agent_fn = dict(human=lambda num_robots, with_battery: None) self.agent_fn.update(agent_fn) self.surface = pygame.display.set_mode((15*CELL_SIZE[0], 11*CELL_SIZE[1])) pygame.display.set_caption('Robotics Board Game') self.main_menu = pygame_menu.Menu( 'Welcome', 15*CELL_SIZE[0], 11*CELL_SIZE[1], theme=pygame_menu.themes.THEME_BLUE, onclose=pygame_menu.events.EXIT, ) self.setting_menu = pygame_menu.Menu( 'Setting', 15*CELL_SIZE[0], 11*CELL_SIZE[1], theme=pygame_menu.themes.THEME_BLUE, ) self.result_menu = pygame_menu.Menu( 'Result', 15*CELL_SIZE[0], 11*CELL_SIZE[1], theme=pygame_menu.themes.THEME_BLUE, onclose=pygame_menu.events.CLOSE, ) self.error_menu = pygame_menu.Menu( 'Error', 15*CELL_SIZE[0], 11*CELL_SIZE[1], theme=pygame_menu.themes.THEME_BLUE, onclose=pygame_menu.events.CLOSE, ) parent_dir = os.path.dirname(__file__) self.env_args = { 'colors_map': os.path.join(parent_dir, 'assets', 'csv_files', 'colors_map.csv'), 'targets_map': os.path.join(parent_dir, 'assets', 'csv_files', 'targets_map.csv'), 'required_mail': 10, 'robot_colors': ['r', 'b'], 'num_robots_per_player': 1, 'with_battery': False, 'random_num_steps': False, 'max_step': 1000, 'render_mode': 'human', } self.player_types = { 'player1': 'human', 'player2': 'human', 'player3': 'human', 'player4': 'human', } self.setting_menu.add.range_slider( 'Required mail', range_values=list(range(1, 21)), default=10, onchange=self.__set_required_mail, font_size=20, range_text_value_enabled=False, range_line_height=5, slider_thickness=8, slider_height_factor=0.5 ) self.setting_menu.add.dropselect_multiple( 'Player colors', items=[('Red', 'r'), ('Blue', 'b'), ('Purple', 'p'), ('Green', 'gr'), ('Pink', 'pi'), ('Orange', 'o')], default=[0, 1], onchange=self.__set_player_colors, font_size=20, max_selected=4, placeholder_selected='{}', selection_placeholder_format=selection_placeholder_format, selection_box_width = 400, ) self.setting_menu.add.dropselect( 'Number robots per player', items=[(str(num), num) for num in range(1, 4)], default=0, onchange=self.__set_num_robots_per_player, font_size=20, ) self.setting_menu.add.toggle_switch( 'With battery', default=False, onchange=self.__set_with_battery, font_size=20, state_color=('#e8e3e7', '#34c0eb'), ) self.setting_menu.add.toggle_switch( 'Random step per turn', default=False, onchange=self.__set_random_num_step, font_size=20, state_color=('#e8e3e7', '#34c0eb'), ) self.setting_menu.add.text_input( 'Max step: ', default=1000, onchange=self.__set_max_step, input_type=pygame_menu.locals.INPUT_INT, font_size=20, ) for i in range(4): self.setting_menu.add.dropselect( f'Player {i+1}', items=[(agent_type, agent_type, i+1) for agent_type in self.agent_fn.keys()], default=0, onchange=self.__set_player_type, font_size=20, ) self.setting_menu.add.button( 'OK', action=pygame_menu.events.BACK, font_size=20, ) self.error_menu.add.label('Please chose more colors for player!' , max_char=-1, font_size=20) self.error_menu.add.button('OK', pygame_menu.events.CLOSE) self.main_menu.add.button('Play', self.__run_game) self.main_menu.add.button('Setting', self.setting_menu) self.main_menu.add.button('Quit', pygame_menu.events.EXIT) self.main_menu.mainloop(self.surface) def __set_required_mail(self, required_mail: int) -> None: self.env_args['required_mail'] = required_mail def __set_player_colors(self, items: tuple[Any, list[int]]) -> None: item_values, _ = items self.env_args['robot_colors'] = [item_value[1] for item_value in item_values] def __set_num_robots_per_player(self, items: tuple[Any, int], num_robots_per_player: int) -> None: self.env_args['num_robots_per_player'] = num_robots_per_player def __set_max_step(self, max_step: int) -> None: self.env_args['max_step'] = max_step def __set_with_battery(self, with_battery: bool) -> None: self.env_args['with_battery'] = with_battery def __set_random_num_step(self, random_num_steps: bool) -> None: self.env_args['random_num_steps'] = random_num_steps def __set_player_type(self, items: tuple[Any, int], player_type: int, player_index: int) -> None: self.player_types[f'player{player_index}'] = player_type def __run_game(self) -> None: if len(self.env_args['robot_colors']) <= 1: self.error_menu.enable() self.error_menu.mainloop(self.surface) return agents = [] for i, _ in enumerate(self.env_args['robot_colors']): agent_type = self.player_types[f'player{i+1}'] agents.extend(self.env_args['num_robots_per_player']* [self.agent_fn[agent_type]( self.env_args['num_robots_per_player']*len(self.env_args['robot_colors']), self.env_args['with_battery'], )]) game = RoboticBoardGame(**self.env_args) winner, _ = game.run(agents) self.result_menu.enable() self.result_menu.clear() if winner: self.result_menu.add.label(f'Congratulate {COLOR2STR[winner].lower()} player to win!', max_char=-1, font_size=20) else: self.result_menu.add.label(f'DRAW!', max_char=-1, font_size=20) self.result_menu.add.button('OK', pygame_menu.events.CLOSE) self.result_menu.mainloop(self.surface)