gameboy_worlds.interface.legend_of_zelda.controllers
1from typing import Dict, Type 2 3from gameboy_worlds.interface.controller import Controller 4from gameboy_worlds.interface.action import HighLevelAction 5from gameboy_worlds.interface.legend_of_zelda.actions import ( 6 MoveAction, 7 OpenInventoryAction, 8 CloseInventoryAction, 9 SkipDialogueAction, 10 InteractAction, 11 UseOtherInventoryItemAction, 12) 13 14 15class LegendOfZeldaStateWiseController(Controller): 16 ACTIONS = [ 17 MoveAction, 18 OpenInventoryAction, 19 CloseInventoryAction, 20 SkipDialogueAction, 21 InteractAction, 22 UseOtherInventoryItemAction, 23 ] 24 25 def string_to_high_level_action(self, input_str): 26 text = input_str.lower().strip() 27 if "(" not in text or ")" not in text: 28 return None, None 29 action_name = text.split("(")[0].strip() 30 action_args_str = text.split("(")[1].split(")")[0].strip() 31 if action_name == "openinventory": 32 return OpenInventoryAction, {} 33 if action_name == "closeinventory": 34 return CloseInventoryAction, {} 35 if action_name == "skipdialogue": 36 return SkipDialogueAction, {} 37 if action_name == "interact": 38 return InteractAction, {} 39 if action_name == "useotherinventoryitem": 40 return UseOtherInventoryItemAction, {} 41 if action_name == "move": 42 parts = [ 43 x.strip() 44 for x in action_args_str.replace(",", " ").split(" ") 45 if x.strip() 46 ] 47 if len(parts) != 2: 48 return None, None 49 direction, steps_str = parts 50 if ( 51 direction not in ["up", "down", "left", "right"] 52 or not steps_str.isdigit() 53 ): 54 return None, None 55 return MoveAction, {"direction": direction, "steps": int(steps_str)} 56 return None, None 57 58 def get_action_strings( 59 self, return_all: bool = False 60 ) -> Dict[Type[HighLevelAction], str]: 61 free_roam_action_strings = { 62 MoveAction: "move(<up/down/left/right> <steps>): Move in a direction for N steps.", 63 OpenInventoryAction: "openinventory(): Open inventory.", 64 InteractAction: "interact(): Interact using A button.", 65 UseOtherInventoryItemAction: "useotherinventoryitem(): Use the secondary equipped item (B button).", 66 } 67 inventory_action_strings = { 68 CloseInventoryAction: "closeinventory(): Close inventory.", 69 } 70 dialogue_action_strings = { 71 SkipDialogueAction: "skipdialogue(): Progress dialogue.", 72 } 73 if return_all: 74 return { 75 **free_roam_action_strings, 76 **inventory_action_strings, 77 **dialogue_action_strings, 78 } 79 current_state = self._emulator.state_parser.get_agent_state( 80 self._emulator.get_current_frame() 81 ) 82 if current_state == "free_roam": 83 return free_roam_action_strings 84 if current_state == "in_inventory": 85 return inventory_action_strings 86 if current_state == "in_dialogue": 87 return dialogue_action_strings 88 if current_state in ["scene_transition", "in_cutscene"]: 89 return {} 90 return { 91 **free_roam_action_strings, 92 **inventory_action_strings, 93 **dialogue_action_strings, 94 }
16class LegendOfZeldaStateWiseController(Controller): 17 ACTIONS = [ 18 MoveAction, 19 OpenInventoryAction, 20 CloseInventoryAction, 21 SkipDialogueAction, 22 InteractAction, 23 UseOtherInventoryItemAction, 24 ] 25 26 def string_to_high_level_action(self, input_str): 27 text = input_str.lower().strip() 28 if "(" not in text or ")" not in text: 29 return None, None 30 action_name = text.split("(")[0].strip() 31 action_args_str = text.split("(")[1].split(")")[0].strip() 32 if action_name == "openinventory": 33 return OpenInventoryAction, {} 34 if action_name == "closeinventory": 35 return CloseInventoryAction, {} 36 if action_name == "skipdialogue": 37 return SkipDialogueAction, {} 38 if action_name == "interact": 39 return InteractAction, {} 40 if action_name == "useotherinventoryitem": 41 return UseOtherInventoryItemAction, {} 42 if action_name == "move": 43 parts = [ 44 x.strip() 45 for x in action_args_str.replace(",", " ").split(" ") 46 if x.strip() 47 ] 48 if len(parts) != 2: 49 return None, None 50 direction, steps_str = parts 51 if ( 52 direction not in ["up", "down", "left", "right"] 53 or not steps_str.isdigit() 54 ): 55 return None, None 56 return MoveAction, {"direction": direction, "steps": int(steps_str)} 57 return None, None 58 59 def get_action_strings( 60 self, return_all: bool = False 61 ) -> Dict[Type[HighLevelAction], str]: 62 free_roam_action_strings = { 63 MoveAction: "move(<up/down/left/right> <steps>): Move in a direction for N steps.", 64 OpenInventoryAction: "openinventory(): Open inventory.", 65 InteractAction: "interact(): Interact using A button.", 66 UseOtherInventoryItemAction: "useotherinventoryitem(): Use the secondary equipped item (B button).", 67 } 68 inventory_action_strings = { 69 CloseInventoryAction: "closeinventory(): Close inventory.", 70 } 71 dialogue_action_strings = { 72 SkipDialogueAction: "skipdialogue(): Progress dialogue.", 73 } 74 if return_all: 75 return { 76 **free_roam_action_strings, 77 **inventory_action_strings, 78 **dialogue_action_strings, 79 } 80 current_state = self._emulator.state_parser.get_agent_state( 81 self._emulator.get_current_frame() 82 ) 83 if current_state == "free_roam": 84 return free_roam_action_strings 85 if current_state == "in_inventory": 86 return inventory_action_strings 87 if current_state == "in_dialogue": 88 return dialogue_action_strings 89 if current_state in ["scene_transition", "in_cutscene"]: 90 return {} 91 return { 92 **free_roam_action_strings, 93 **inventory_action_strings, 94 **dialogue_action_strings, 95 }
Abstract base class for controllers interfacing with the emulator. Handles conversion between high level actions and Gym action spaces.
A list of HighLevelAction classes that define the possible high level actions. This is (almost) always, the only part that must be customized in subclasses.
26 def string_to_high_level_action(self, input_str): 27 text = input_str.lower().strip() 28 if "(" not in text or ")" not in text: 29 return None, None 30 action_name = text.split("(")[0].strip() 31 action_args_str = text.split("(")[1].split(")")[0].strip() 32 if action_name == "openinventory": 33 return OpenInventoryAction, {} 34 if action_name == "closeinventory": 35 return CloseInventoryAction, {} 36 if action_name == "skipdialogue": 37 return SkipDialogueAction, {} 38 if action_name == "interact": 39 return InteractAction, {} 40 if action_name == "useotherinventoryitem": 41 return UseOtherInventoryItemAction, {} 42 if action_name == "move": 43 parts = [ 44 x.strip() 45 for x in action_args_str.replace(",", " ").split(" ") 46 if x.strip() 47 ] 48 if len(parts) != 2: 49 return None, None 50 direction, steps_str = parts 51 if ( 52 direction not in ["up", "down", "left", "right"] 53 or not steps_str.isdigit() 54 ): 55 return None, None 56 return MoveAction, {"direction": direction, "steps": int(steps_str)} 57 return None, None
Provide a way to map a string input to a HighLevelAction and parameters.
Implement if you want to use the human_step_play method, or if you want to allow a LM based agent to give its actions in text. Must return None, None if the input_str does not map to an action.
59 def get_action_strings( 60 self, return_all: bool = False 61 ) -> Dict[Type[HighLevelAction], str]: 62 free_roam_action_strings = { 63 MoveAction: "move(<up/down/left/right> <steps>): Move in a direction for N steps.", 64 OpenInventoryAction: "openinventory(): Open inventory.", 65 InteractAction: "interact(): Interact using A button.", 66 UseOtherInventoryItemAction: "useotherinventoryitem(): Use the secondary equipped item (B button).", 67 } 68 inventory_action_strings = { 69 CloseInventoryAction: "closeinventory(): Close inventory.", 70 } 71 dialogue_action_strings = { 72 SkipDialogueAction: "skipdialogue(): Progress dialogue.", 73 } 74 if return_all: 75 return { 76 **free_roam_action_strings, 77 **inventory_action_strings, 78 **dialogue_action_strings, 79 } 80 current_state = self._emulator.state_parser.get_agent_state( 81 self._emulator.get_current_frame() 82 ) 83 if current_state == "free_roam": 84 return free_roam_action_strings 85 if current_state == "in_inventory": 86 return inventory_action_strings 87 if current_state == "in_dialogue": 88 return dialogue_action_strings 89 if current_state in ["scene_transition", "in_cutscene"]: 90 return {} 91 return { 92 **free_roam_action_strings, 93 **inventory_action_strings, 94 **dialogue_action_strings, 95 }
Provide a way to verbalize the allowed high level actions, along with the format of the input parameters. Useful for prompting a VLM to choose an action.
This should match the mapping in string_to_high_level_action
Parameters
- return_all: If True, returns all possible actions and parameter formats. If False, returns only the actions that are valid in the current state.
Returns
A dictionary mapping high level actions to their verbalizations and input formats.
Inherited Members
- gameboy_worlds.interface.controller.Controller
- Controller
- actions
- REQUIRED_STATE_TRACKER
- action_space
- seed
- unassign_emulator
- assign_emulator
- get_action_space
- sample
- is_valid
- get_valid_high_level_actions
- get_valid_space_actions
- get_possibly_valid_high_level_actions
- execute_space_action
- execute
- string_to_space_action
- execute_string