gameboy_worlds.interface.harvest_moon.controllers

 1from gameboy_worlds.utils import log_error, log_info
 2from gameboy_worlds.interface.harvest_moon.actions import (
 3    MoveStepsAction,
 4    InteractAction,
 5    PassDialogueAction,
 6    MoveGridAction,
 7)
 8from gameboy_worlds.interface.controller import Controller
 9from gameboy_worlds.interface.action import HighLevelAction
10from gameboy_worlds.emulation.harvest_moon.parsers import AgentState
11from typing import Dict, Any
12
13
14class HarvestMoonStateWiseController(Controller):
15    """
16    High Level Actions for the Harvest Moon Environment:
17
18    - In Free Roam:
19        - MoveStepsAction(direction: str, steps: int): Move in a particular direction by a specified number of grid steps.
20        - InteractAction(): Interact with cell directly in front of you. Only works if there is something to interact with.
21
22    - In Dialogue:
23        - PassDialogueAction(): Advance the dialogue by one step.
24    """
25
26    ACTIONS = [
27        MoveStepsAction,
28        InteractAction,
29        PassDialogueAction,
30    ]
31
32    def string_to_high_level_action(self, input_str):
33        input_str = input_str.lower().strip()
34        if "(" not in input_str or ")" not in input_str:
35            return None, None  # Invalid format
36        action_name = input_str.split("(")[0].strip()
37        action_args_str = input_str.split("(")[1].split(")")[0].strip()
38        # First handle the no arg actions
39        if action_name == "interact":
40            return InteractAction, {}
41        if action_name == "passdialogue":
42            return PassDialogueAction, {}
43        
44        if action_name == "move":
45            cardinal = None
46            if "up" in action_args_str:
47                cardinal = "up"
48            if "down" in action_args_str:
49                if cardinal is not None:
50                    return None, None
51                cardinal = "down"
52            if "left" in action_args_str:
53                if cardinal is not None:
54                    return None, None
55                cardinal = "left"
56            if "right" in action_args_str:
57                if cardinal is not None:
58                    return None, None
59                cardinal = "right"
60            if cardinal is None:
61                return None, None
62            steps_part = action_args_str.replace(cardinal, "").strip()
63            if not steps_part.isnumeric():
64                return None, None
65            steps = int(steps_part)
66            return MoveStepsAction, {"direction": cardinal, "steps": steps}
67        return None, None
68
69    def get_action_strings(
70        self, return_all: bool = False
71    ) -> Dict[HighLevelAction, str]:
72        current_state = self._emulator.state_parser.get_agent_state(
73            self._emulator.get_current_frame()
74        )
75        free_roam_action_strings = {
76            MoveStepsAction: "move(<up, down, right or left> <steps: int>): Move in a particular direction by a specified number of grid steps.",
77            InteractAction: "interact(): Interact with cell directly in front of you. Only works if there is something to interact with.",
78        }
79        dialogue_action_strings = {
80            PassDialogueAction: "passdialogue(): Advance the dialogue by one step.",
81        }
82        if return_all:
83            actions = {
84                **free_roam_action_strings,
85                **dialogue_action_strings,
86            }
87        else:
88            if current_state == AgentState.FREE_ROAM:
89                actions = free_roam_action_strings
90            elif current_state == AgentState.IN_DIALOGUE:
91                actions = dialogue_action_strings
92            else:
93                log_error(
94                    f"Unknown agent state {current_state} when getting action strings."
95                )
96                actions = {}
97        return actions
class HarvestMoonStateWiseController(gameboy_worlds.interface.controller.Controller):
15class HarvestMoonStateWiseController(Controller):
16    """
17    High Level Actions for the Harvest Moon Environment:
18
19    - In Free Roam:
20        - MoveStepsAction(direction: str, steps: int): Move in a particular direction by a specified number of grid steps.
21        - InteractAction(): Interact with cell directly in front of you. Only works if there is something to interact with.
22
23    - In Dialogue:
24        - PassDialogueAction(): Advance the dialogue by one step.
25    """
26
27    ACTIONS = [
28        MoveStepsAction,
29        InteractAction,
30        PassDialogueAction,
31    ]
32
33    def string_to_high_level_action(self, input_str):
34        input_str = input_str.lower().strip()
35        if "(" not in input_str or ")" not in input_str:
36            return None, None  # Invalid format
37        action_name = input_str.split("(")[0].strip()
38        action_args_str = input_str.split("(")[1].split(")")[0].strip()
39        # First handle the no arg actions
40        if action_name == "interact":
41            return InteractAction, {}
42        if action_name == "passdialogue":
43            return PassDialogueAction, {}
44        
45        if action_name == "move":
46            cardinal = None
47            if "up" in action_args_str:
48                cardinal = "up"
49            if "down" in action_args_str:
50                if cardinal is not None:
51                    return None, None
52                cardinal = "down"
53            if "left" in action_args_str:
54                if cardinal is not None:
55                    return None, None
56                cardinal = "left"
57            if "right" in action_args_str:
58                if cardinal is not None:
59                    return None, None
60                cardinal = "right"
61            if cardinal is None:
62                return None, None
63            steps_part = action_args_str.replace(cardinal, "").strip()
64            if not steps_part.isnumeric():
65                return None, None
66            steps = int(steps_part)
67            return MoveStepsAction, {"direction": cardinal, "steps": steps}
68        return None, None
69
70    def get_action_strings(
71        self, return_all: bool = False
72    ) -> Dict[HighLevelAction, str]:
73        current_state = self._emulator.state_parser.get_agent_state(
74            self._emulator.get_current_frame()
75        )
76        free_roam_action_strings = {
77            MoveStepsAction: "move(<up, down, right or left> <steps: int>): Move in a particular direction by a specified number of grid steps.",
78            InteractAction: "interact(): Interact with cell directly in front of you. Only works if there is something to interact with.",
79        }
80        dialogue_action_strings = {
81            PassDialogueAction: "passdialogue(): Advance the dialogue by one step.",
82        }
83        if return_all:
84            actions = {
85                **free_roam_action_strings,
86                **dialogue_action_strings,
87            }
88        else:
89            if current_state == AgentState.FREE_ROAM:
90                actions = free_roam_action_strings
91            elif current_state == AgentState.IN_DIALOGUE:
92                actions = dialogue_action_strings
93            else:
94                log_error(
95                    f"Unknown agent state {current_state} when getting action strings."
96                )
97                actions = {}
98        return actions

High Level Actions for the Harvest Moon Environment:

  • In Free Roam:

    • MoveStepsAction(direction: str, steps: int): Move in a particular direction by a specified number of grid steps.
    • InteractAction(): Interact with cell directly in front of you. Only works if there is something to interact with.
  • In Dialogue:

    • PassDialogueAction(): Advance the dialogue by one step.

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.

def string_to_high_level_action(self, input_str):
33    def string_to_high_level_action(self, input_str):
34        input_str = input_str.lower().strip()
35        if "(" not in input_str or ")" not in input_str:
36            return None, None  # Invalid format
37        action_name = input_str.split("(")[0].strip()
38        action_args_str = input_str.split("(")[1].split(")")[0].strip()
39        # First handle the no arg actions
40        if action_name == "interact":
41            return InteractAction, {}
42        if action_name == "passdialogue":
43            return PassDialogueAction, {}
44        
45        if action_name == "move":
46            cardinal = None
47            if "up" in action_args_str:
48                cardinal = "up"
49            if "down" in action_args_str:
50                if cardinal is not None:
51                    return None, None
52                cardinal = "down"
53            if "left" in action_args_str:
54                if cardinal is not None:
55                    return None, None
56                cardinal = "left"
57            if "right" in action_args_str:
58                if cardinal is not None:
59                    return None, None
60                cardinal = "right"
61            if cardinal is None:
62                return None, None
63            steps_part = action_args_str.replace(cardinal, "").strip()
64            if not steps_part.isnumeric():
65                return None, None
66            steps = int(steps_part)
67            return MoveStepsAction, {"direction": cardinal, "steps": steps}
68        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.

def get_action_strings( self, return_all: bool = False) -> Dict[gameboy_worlds.interface.action.HighLevelAction, str]:
70    def get_action_strings(
71        self, return_all: bool = False
72    ) -> Dict[HighLevelAction, str]:
73        current_state = self._emulator.state_parser.get_agent_state(
74            self._emulator.get_current_frame()
75        )
76        free_roam_action_strings = {
77            MoveStepsAction: "move(<up, down, right or left> <steps: int>): Move in a particular direction by a specified number of grid steps.",
78            InteractAction: "interact(): Interact with cell directly in front of you. Only works if there is something to interact with.",
79        }
80        dialogue_action_strings = {
81            PassDialogueAction: "passdialogue(): Advance the dialogue by one step.",
82        }
83        if return_all:
84            actions = {
85                **free_roam_action_strings,
86                **dialogue_action_strings,
87            }
88        else:
89            if current_state == AgentState.FREE_ROAM:
90                actions = free_roam_action_strings
91            elif current_state == AgentState.IN_DIALOGUE:
92                actions = dialogue_action_strings
93            else:
94                log_error(
95                    f"Unknown agent state {current_state} when getting action strings."
96                )
97                actions = {}
98        return actions

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.