diff --git a/jericho/jericho.py b/jericho/jericho.py index 0b3c4743..38e14ec3 100644 --- a/jericho/jericho.py +++ b/jericho/jericho.py @@ -36,6 +36,9 @@ JERICHO_PATH = importlib.resources.files("jericho") FROTZ_LIB_PATH = os.path.join(JERICHO_PATH, 'libfrotz.so') +# The buffer size for actions in frotz. -2 to allow for newline and null terminator. +INPUT_BUFFER_SIZE = 200 - 2 + # Function to unload a shared library. dlclose_func = CDLL(None).dlclose # This WON'T work on Win dlclose_func.argtypes = [c_void_p] @@ -361,6 +364,10 @@ class UnsupportedGameWarning(UserWarning): pass +class TruncatedInputActionWarning(UserWarning): + pass + + class FrotzEnv(): """ The Frotz Environment is a fast interface to Z-Machine games. @@ -465,9 +472,19 @@ def step(self, action): the immediate reward, a boolean indicating whether the game is over,\ and a dictionary of info. :rtype: string, float, boolean, dictionary + + Note: + - The action is converted to bytes and truncated to 198 characters. ''' + action_bytes = action.encode('utf-8') + if len(action_bytes) > INPUT_BUFFER_SIZE: + action_bytes = action_bytes[:INPUT_BUFFER_SIZE] + msg = ("Once converted to bytes, actions should have less than 198 characters." + " Action '{}' was truncated to '{}'.".format(action, action_bytes.decode())) + warnings.warn(msg, TruncatedInputActionWarning) + old_score = self.frotz_lib.get_score() - next_state = self.frotz_lib.step((action+'\n').encode('utf-8')).decode('cp1252') + next_state = self.frotz_lib.step(action_bytes + b'\n').decode('cp1252') score = self.frotz_lib.get_score() reward = score - old_score return next_state, reward, (self.game_over() or self.victory()),\ diff --git a/jericho/version.py b/jericho/version.py index 573cf70b..6a157dcb 100644 --- a/jericho/version.py +++ b/jericho/version.py @@ -1 +1 @@ -__version__ = '3.2.0' +__version__ = '3.3.0' diff --git a/tests/test_jericho.py b/tests/test_jericho.py index 58a3afc6..e011c5f9 100644 --- a/tests/test_jericho.py +++ b/tests/test_jericho.py @@ -127,3 +127,19 @@ def test_saving_opcode_in_state(): else: obs, rew, done, info = env.step(cmd) assert not env._emulator_halted() + + +def test_very_long_action(): + rom = pjoin(DATA_PATH, "905.z5") + env = jericho.FrotzEnv(rom) + env.reset() + + long_command = "It's a " + "very " * 36 + "long action!" + assert len(long_command) == 199 + env.step(long_command) + env.step(long_command * 2) + + long_command = "It's a " + "très " * 36 + "long action!" + assert len(long_command) == 199 + env.step(long_command) + env.step(long_command * 2)