def request_infos_for_eval() -> EnvInfos: request_infos = EnvInfos() request_infos.admissible_commands = True request_infos.description = True request_infos.location = True request_infos.facts = True request_infos.last_action = True request_infos.game = True return request_infos
def __init__(self, gamefiles: List[str], request_infos: Optional[EnvInfos] = None, batch_size: int = 1, asynchronous: bool = True, auto_reset: bool = False, max_episode_steps: Optional[int] = None, action_space: Optional[gym.Space] = None, observation_space: Optional[gym.Space] = None) -> None: """ Environment for playing text-based games in batch. Arguments: gamefiles: Paths of every game composing the pool (`*.ulx|*.z[1-8]|*.json`). request_infos: For customizing the information returned by this environment (see :py:class:`textworld.EnvInfos <textworld.envs.wrappers.filter.EnvInfos>` for the list of available information). .. warning:: Only supported for TextWorld games (i.e., that have a corresponding `*.json` file). batch_size: If provided, it indicates the number of games to play at the same time. By default, a single game is played at once. .. warning:: When `batch_size` is provided (even for batch_size=1), `env.step` expects a list of commands as input and outputs a list of states. `env.reset` also outputs a list of states. asynchronous: If `True`, wraps the environments in an `AsyncBatchEnv` (which uses `multiprocessing` to run the environments in parallel). If `False`, wraps the environments in a `SyncBatchEnv`. Default: `True`. auto_reset: If `True`, each game *independently* resets once it is done (i.e., reset happens on the next `env.step` call). Otherwise, once a game is done, subsequent calls to `env.step` won't have any effects. max_episode_steps: Number of steps allocated to play each game. Once exhausted, the game is done. action_space: The action space be used with OpenAI baselines. (see :py:class:`textworld.gym.spaces.Word <textworld.gym.spaces.text_spaces.Word>`). observation_space: The observation space be used with OpenAI baselines (see :py:class:`textworld.gym.spaces.Word <textworld.gym.spaces.text_spaces.Word>`). """ self.gamefiles = gamefiles self.batch_size = batch_size self.request_infos = request_infos or EnvInfos() self.seed(1234) env_fns = [ partial(_make_env, self.request_infos, max_episode_steps) for _ in range(self.batch_size) ] BatchEnvType = AsyncBatchEnv if self.batch_size > 1 and asynchronous else SyncBatchEnv self.batch_env = BatchEnvType(env_fns, auto_reset) self.action_space = action_space self.observation_space = observation_space
def select_additional_infos(self) -> EnvInfos: """ Returns what additional information should be made available at each game step. Requested information will be included within the `infos` dictionary passed to `CustomAgent.act()`. To request specific information, create a :py:class:`textworld.EnvInfos <textworld.envs.wrappers.filter.EnvInfos>` and set the appropriate attributes to `True`. The possible choices are: * `description`: text description of the current room, i.e. output of the `look` command; * `inventory`: text listing of the player's inventory, i.e. output of the `inventory` command; * `max_score`: maximum reachable score of the game; * `objective`: objective of the game described in text; * `entities`: names of all entities in the game; * `verbs`: verbs understood by the the game; * `command_templates`: templates for commands understood by the the game; * `admissible_commands`: all commands relevant to the current state; In addition to the standard information, game specific information can be requested by appending corresponding strings to the `extras` attribute. For this competition, the possible extras are: * `'recipe'`: description of the cookbook; * `'walkthrough'`: one possible solution to the game (not guaranteed to be optimal); Example: Here is an example of how to request information and retrieve it. >>> from textworld import EnvInfos >>> request_infos = EnvInfos(description=True, inventory=True, extras=["recipe"]) ... >>> env = gym.make(env_id) >>> ob, infos = env.reset() >>> print(infos["description"]) >>> print(infos["inventory"]) >>> print(infos["extra.recipe"]) Notes: The following information *won't* be available at test time: * 'walkthrough', 'facts' """ request_infos = EnvInfos() request_infos.description = True request_infos.inventory = True request_infos.entities = True request_infos.verbs = True request_infos.extras = ["recipe"] request_infos.facts = True request_infos.location = True return request_infos
def select_additional_infos(self) -> EnvInfos: request_infos = EnvInfos() request_infos.description = True request_infos.inventory = True request_infos.entities = True request_infos.verbs = True request_infos.extras = ["recipe", "walkthrough"] request_infos.admissible_commands = True return request_infos
def request_infos() -> Optional[EnvInfos]: """Request the infos the agent expects from the environment Returns: request_infos: EnvInfos""" request_infos = EnvInfos() request_infos.description = True request_infos.inventory = True request_infos.entities = True request_infos.verbs = True request_infos.admissible_commands = True request_infos.command_templates = True request_infos.max_score = True return request_infos
def infos_to_request(self) -> EnvInfos: request_infos = EnvInfos() request_infos.description = True request_infos.inventory = True request_infos.entities = True request_infos.verbs = True request_infos.extras = ["recipe"] return request_infos
def __init__(self, gamefiles: List[str], request_infos: Optional[EnvInfos] = None, batch_size: int = 1, asynchronous: bool = True, action_space: Optional[gym.Space] = None, observation_space: Optional[gym.Space] = None) -> None: """ Environment for playing text-based games in batch. Arguments: gamefiles: Paths of every game composing the pool (`*.ulx|*.z[1-8]`). request_infos: For customizing the information returned by this environment (see :py:class:`textworld.EnvInfos <textworld.envs.wrappers.filter.EnvInfos>` for the list of available information). .. warning:: Only supported for TextWorld games (i.e., that have a corresponding `*.json` file). batch_size: If provided, it indicates the number of games to play at the same time. By default, a single game is played at once. .. warning:: When `batch_size` is provided (even for batch_size=1), `env.step` expects a list of commands as input and outputs a list of states. `env.reset` also outputs a list of states. asynchronous: If `True`, wraps the environments in an `AsyncBatchEnv` (which uses `multiprocessing` to run the environments in parallel). If `False`, wraps the environments in a `SyncBatchEnv`. Default: `True`. action_space: The action space be used with OpenAI baselines. (see :py:class:`textworld.gym.spaces.Word <textworld.gym.spaces.text_spaces.Word>`). observation_space: The observation space be used with OpenAI baselines (see :py:class:`textworld.gym.spaces.Word <textworld.gym.spaces.text_spaces.Word>`). """ self.gamefiles = gamefiles self.batch_size = batch_size self.request_infos = request_infos or EnvInfos() self.seed(1234) def _make_env(): env = GenericEnvironment(self.request_infos) env = Filter(env) return env env_fns = [_make_env for _ in range(self.batch_size)] self.batch_env = AsyncBatchEnv( env_fns) if self.batch_size > 1 and asynchronous else SyncBatchEnv( env_fns) self.action_space = action_space self.observation_space = observation_space
def infos_to_request(self) -> EnvInfos: return EnvInfos( description=True, inventory=True, admissible_commands=True, won=True, lost=True, location=True, last_action=True, game=True, facts=True, entities=True) # Last line needed for ground truth local graph
def select_additional_infos() -> EnvInfos: """ Returns what additional information should be made available at each game step. """ return EnvInfos( max_score=True, description=True, inventory=True, extras=["walkthrough", "recipe"], admissible_commands=True, )
def __init__(self, game_files: List[str], request_infos: Optional[EnvInfos] = None, action_space: Optional[gym.Space] = None, observation_space: Optional[gym.Space] = None) -> None: """ Environment for playing text-based games. Each time `TextworldGamesEnv.reset()` is called, a new game from the pool starts. Each game of the pool is guaranteed to be played exactly once before a same game is played for a second time. Arguments: game_files: Paths of every game composing the pool (`*.ulx` + `*.json`, `*.z[1-8]`). request_infos: For customizing the information returned by this environment (see :py:class:`textworld.EnvInfos <textworld.envs.wrappers.filter.EnvInfos>` for the list of available information). .. warning:: This is only supported for `*.ulx` games generated with TextWorld. action_space: The action space of this TextWorld environment. By default, a :py:class:`textworld.gym.spaces.Word <textworld.gym.spaces.text_spaces.Word>` instance is used with a `max_length` of 8 and a vocabulary extracted from the TextWorld game. observation_space: The observation space of this TextWorld environment. By default, a :py:class:`textworld.gym.spaces.Word <textworld.gym.spaces.text_spaces.Word>` instance is used with a `max_length` of 200 and a vocabulary extracted from the TextWorld game. """ self.gamefiles = game_files self.request_infos = request_infos or EnvInfos() self.ob = None self.last_command = None self.textworld_env = None self.current_gamefile = None self.seed(1234) if action_space is None or observation_space is None: # Extract vocabulary from all games. vocab = sorted( textworld.text_utils.extract_vocab_from_gamefiles( self.gamefiles)) self.action_space = action_space or text_spaces.Word(max_length=8, vocab=vocab) self.observation_space = observation_space or text_spaces.Word( max_length=200, vocab=vocab)
def test_auto_reset(self): batch_size = 4 max_episode_steps = 13 env_options = EnvInfos(inventory=True, description=True, admissible_commands=True) env_id = textworld.gym.register_games( [ self.gamefile1, self.gamefile1_z8, self.gamefile2, self.gamefile2 ], request_infos=env_options, batch_size=batch_size, max_episode_steps=max_episode_steps, name="test-auto-reset", asynchronous=True, auto_reset=True) env = gym.make(env_id) init_obs, init_infos = env.reset() dones = [False] * batch_size for cmd in self.game1.metadata["walkthrough"]: assert sum(dones) == 0 obs, scores, dones, infos = env.step([cmd] * batch_size) # Two of the envs should be done. assert sum(dones) == 2 assert sum(scores) == 2 # The two envs should auto-reset on the next action. obs, scores, dones, infos = env.step(["wait"] * batch_size) assert sum(dones) == 0 assert sum(scores) == 0 # Score should auto reset. assert obs[0] == init_obs[0] and obs[1] == init_obs[1] assert all(v[0] == init_infos[k][0] and v[1] == init_infos[k][1] for k, v in infos.items()) for cmd in self.game1.metadata["walkthrough"]: assert sum(dones) == 0 obs, scores, dones, infos = env.step([cmd] * batch_size) assert sum(dones) == 2 obs, infos = env.reset() for _ in range(max_episode_steps): obs, scores, dones, infos = env.step(["wait"] * batch_size) assert sum(dones) == 4 # All env have played maximum number of steps. env.close()
def setUpClass(cls): g_rng.set_seed(201809) cls.tmpdir = tempfile.mkdtemp() cls.options = textworld.GameOptions() cls.options.path = pjoin(cls.tmpdir, "tw-game.ulx") cls.game, cls.gamefile_ulx = testing.build_and_compile_game( cls.options) cls.options.path = pjoin(cls.tmpdir, "tw-game.z8") cls.gamefile_z8 = textworld.generator.compile_game( cls.game, cls.options) cls.infos = EnvInfos( max_score=True, objective=True, )
def setUpClass(cls): g_rng.set_seed(201809) cls.tmpdir = tempfile.mkdtemp() cls.options = textworld.GameOptions() cls.options.path = pjoin(cls.tmpdir, "tw-game.ulx") cls.game, cls.gamefile_ulx = testing.build_and_compile_game( cls.options) cls.options.path = pjoin(cls.tmpdir, "tw-game.z8") cls.gamefile_z8 = textworld.generator.compile_game( cls.game, cls.options) cls.infos = EnvInfos(facts=True, policy_commands=True, admissible_commands=True, intermediate_reward=True)
def setUpClass(cls): g_rng.set_seed(201809) cls.tmpdir = tempfile.mkdtemp() cls.options = textworld.GameOptions() cls.options.path = pjoin(cls.tmpdir, "tw-game.ulx") cls.game, cls.gamefile_ulx = testing.build_and_compile_game(cls.options) cls.options.path = pjoin(cls.tmpdir, "tw-game.z8") cls.gamefile_z8 = textworld.generator.compile_game(cls.game, cls.options) cls.infos = EnvInfos( inventory=True, description=True, score=True, moves=True, won=True, lost=True, )
def setup(self) -> EnvInfos: requested_infos = EnvInfos() requested_infos.description = True requested_infos.inventory = True requested_infos.entities = True requested_infos.verbs = True requested_infos.extras = ["recipe", "walkthrough"] requested_infos.admissible_commands = True env_id = textworld.gym.register_games( self.games, requested_infos, max_episode_steps=self.max_nb_steps, name="training") env_id = textworld.gym.make_batch(env_id, batch_size=self.batch_size, parallel=True) return gym.make(env_id)
def __init__(self, games, max_episode_length=100, query_mode=False): infos_to_request = EnvInfos(description=True, inventory=True, admissible_commands=True, has_won=True, has_lost=True, max_score=True) env_id = textworld.gym.register_games( games, request_infos=infos_to_request, max_episode_steps=max_episode_length) self.env = gym.make(env_id) self.last_score = 0 self.query_mode = query_mode self.query_commands = [] # ["look", "inventory", "score", "goal"] self.admissible_commands = None self.info = None
def test_register_game(): with make_temp_directory() as tmpdir: options = textworld.GameOptions() options.path = tmpdir options.seeds = 1234 gamefile, game = textworld.make(options) env_options = EnvInfos(inventory=True, description=True, admissible_commands=True, extras=["walkthrough"]) env_id = textworld.gym.register_game(gamefile, env_options, name="test-single") env = gym.make(env_id) obs, infos = env.reset() assert len(infos) == len(env_options) for cmd in infos.get("extra.walkthrough"): obs, score, done, infos = env.step(cmd) assert done assert score == 1
def test_register_game(self): env_options = EnvInfos(inventory=True, description=True, admissible_commands=True, extras=["walkthrough"]) env_id = textworld.gym.register_game(self.gamefile1, env_options, name="test-single") env = gym.make(env_id) obs, infos = env.reset() assert len(infos) == len(env_options) for cmd in infos.get("extra.walkthrough"): obs, score, done, infos = env.step(cmd) assert done assert score == 1 env.close()
def test_register_zmachine_game(): with make_temp_directory() as tmpdir: options = textworld.GameOptions() options.path = tmpdir options.seeds = 1234 options.file_ext = ".z8" gamefile, game = textworld.make(options) os.remove(gamefile.replace(".z8", ".json")) # Simulate an existing Z-Machine game. env_options = EnvInfos(extras=["walkthrough"]) env_id = textworld.gym.register_game(gamefile, env_options, name="test-zmachine") env = gym.make(env_id) obs, infos = env.reset() assert len(infos) == len(env_options) for cmd in game.metadata["walkthrough"]: obs, score, done, infos = env.step(cmd) assert done assert score == 1
def get_infos(eval=True, recipe=True, walkthrough=True): request_infos = \ EnvInfos(verbs=True, moves=True, inventory=True, description=True, objective=True, intermediate_reward=True, policy_commands=True, max_score=True, admissible_commands=True, last_action=True, game=True, facts=True, entities=True, won=True, lost=True, location=True) request_infos.verbs = True request_infos.extras = [] if recipe: request_infos.extras += ['recipe'] if walkthrough: request_infos.extras += ['walkthrough'] if eval: request_infos.max_score = True request_infos.admissible_commands = True request_infos.command_templates = True return request_infos
def test_VisualHints(): request_infos = EnvInfos(verbs=True, moves=True, inventory=True, description=True, objective=True, feedback=True, intermediate_reward=True, facts=True, policy_commands=True) path = './tests/tw_games/tw-cooking-test-take+cook+cut+open+go6-JrmLfNyMcErjF6LD.ulx' env = VisualHints(path=path, request_infos=request_infos, batch_size=1, asynchronous=True, mask=False, distance_of_puzzle=4, add_death_room=False, clue_first_room=True, max_number_inaccessible_rooms=2, room_name=True, color_way=True, upgradable_color_way=True, name_type='literal', draw_passages=True, draw_player=True, level_clue='easy', random_place=True, name='cooking_game') obs, rewards, dones, infos, im, partial_pic, hint, indication_deathroom = env.reset( ) actions = [ "examine hint", "look", "open glass door", "go west", "go south", "open door", "go south", "go west", "examine cookbook", "inventory" ] for action in actions: obs, rewards, dones, infos, im, partial_pic, hint, indication_deathroom = env.step( [action])
def main(): with open(CONFIG) as reader: config = yaml.safe_load(reader) gamefiles = glob(join(config['main']['games_path'], '*.ulx')) print('Found {} games.'.format(len(gamefiles))) # pprint(gamefiles) # Pick a game. gamefile = gamefiles[1] requested_infos = EnvInfos( admissible_commands=True, command_templates=True, description=True, entities=True, has_lost=True, has_won=True, inventory=True, max_score=True, objective=True, verbs=True, extras=[ "recipe", ], ) env_id = textworld.gym.register_games([gamefile], requested_infos) env_id = textworld.gym.make_batch( env_id, batch_size=config['main']['environment_batch_size'], parallel=True) env = gym.make(env_id) agent = CustomizableAgent(config, *get_embeddings(config['main'])) play(env, agent, config['main']) play(env, agent, config['main'], evaluation=True) agent.cleanup() return
def test_register_games(): with make_temp_directory() as tmpdir: options = textworld.GameOptions() options.path = tmpdir options.seeds = 1234 gamefile1, game1 = textworld.make(options) options.seeds = 4321 gamefile2, game2 = textworld.make(options) env_options = EnvInfos(inventory=True, description=True, admissible_commands=True) env_id = textworld.gym.register_games([gamefile1, gamefile2], env_options, name="test-multi") env = gym.make(env_id) env.seed(2) # Make game2 starts on the first reset call. obs, infos = env.reset() assert len(infos) == len(env_options) for cmd in game2.main_quest.commands: obs, score, done, infos = env.step(cmd) assert done assert score == 1 obs, infos = env.reset() assert len(infos) == len(env_options) for cmd in game1.main_quest.commands: obs, score, done, infos = env.step(cmd) assert done assert score == 1 obs1, infos = env.reset() obs2, infos = env.reset() assert obs1 != obs2
help="Count of game indices to use during training, default=1") parser.add_argument("-v", "--validation", default='-val', help="Suffix for game used for validation, default=-val") parser.add_argument("--cuda", default=False, action='store_true', help="Use cuda for training") parser.add_argument("-r", "--run", required=True, help="Run name") args = parser.parse_args() device = torch.device("cuda" if args.cuda else "cpu") params = common.PARAMS[args.params] game_files = ["games/%s%s.ulx" % (args.game, s) for s in range(1, args.suffices+1)] val_game_file = "games/%s%s.ulx" % (args.game, args.validation) if not all(map(lambda p: pathlib.Path(p).exists(), game_files)): raise RuntimeError(f"Some game files from {game_files} not found! Probably you need to run make_games.sh") action_space, observation_space = common.get_games_spaces(game_files + [val_game_file]) env_id = register_games(game_files, request_infos=EnvInfos(**EXTRA_GAME_INFO), name=args.game, action_space=action_space, observation_space=observation_space) print("Registered env %s for game files %s" % (env_id, game_files)) val_env_id = register_games([val_game_file], request_infos=EnvInfos(**EXTRA_GAME_INFO), name=args.game, action_space=action_space, observation_space=observation_space) print("Game %s, with file %s will be used for validation" % (val_env_id, val_game_file)) env = gym.make(env_id) env = preproc.TextWorldPreproc(env) val_env = gym.make(val_env_id) val_env = preproc.TextWorldPreproc(val_env) prep = preproc.Preprocessor( dict_size=env.observation_space.vocab_size, emb_size=params.embeddings, num_sequences=env.num_fields,
def infos_to_request(self) -> EnvInfos: return EnvInfos(description=True, inventory=True, admissible_commands=True, won=True, lost=True)
from textworld import EnvInfos REQUIRED_INFOS = EnvInfos( max_score=True, description=True, inventory=True, extras=["walkthrough", "recipe"], admissible_commands=True, )
# # location_adjs=True, # !QAIT-SPECIFIC # object_names=True, # !QAIT-SPECIFIC # object_nouns=True, # !QAIT-SPECIFIC # object_adjs=True, # !QAIT-SPECIFIC # extras=[ # the extras come from challenge.py # "object_locations", # !QAIT-SPECIFIC # "object_attributes", # !QAIT-SPECIFIC # "uuid"] # !QAIT-SPECIFIC # ) request_step_infos = EnvInfos( description=True, inventory=True, feedback=True, # location=True, # not actually used by qait agent facts=True, last_action=True, admissible_commands=True, # static infos, don't change during the game: game=True, # verbs=True, ) # info_sample is a skeletal version of info struct returned from gym env, for use with RLPyT (currently not used) info_sample = { "description": "-= Somewhere =-\\nYou are somewhere. There is not much here.", "inventory": 'You are carrying nothing.\\n\\n\\n', # "location": "somewhere", "facts": [('at', ('P', 'P'), ('somewhere', 'r')), ('at', ('not much', 's'), ('somewhere', 'r'))],
from tqdm import tqdm import gym import textworld.gym from textworld import EnvInfos from custom_agent import CustomAgent # List of additional information available during evaluation. AVAILABLE_INFORMATION = EnvInfos(description=True, inventory=True, max_score=True, objective=True, entities=True, verbs=True, command_templates=True, admissible_commands=True, has_won=True, has_lost=True, extras=["recipe"]) def _validate_requested_infos(infos: EnvInfos): msg = "The following information cannot be requested: {}" for key in infos.basics: if not getattr(AVAILABLE_INFORMATION, key): raise ValueError(msg.format(key)) for key in infos.extras: if key not in AVAILABLE_INFORMATION.extras:
def select_additional_infos(self) -> EnvInfos: request_infos = EnvInfos() request_infos.description = True request_infos.inventory = True if self.config['general']['hcp'] >= 2: request_infos.entities = True request_infos.verbs = True if self.config['general']['hcp'] >= 4: request_infos.extras = ["recipe"] if self.config['general']['hcp'] >= 5: request_infos.admissible_commands = True # TEST request_infos.entities = True request_infos.verbs = True request_infos.extras = ["recipe", "walkthrough"] request_infos.admissible_commands = True return request_infos
args = parser.parse_args() device = torch.device("cuda" if args.cuda else "cpu") params = common.PARAMS[args.params] game_files = [ "games/%s%s.ulx" % (args.game, s) for s in range(1, args.suffices + 1) ] val_game_file = "games/%s%s.ulx" % (args.game, args.validation) if not all(map(lambda p: pathlib.Path(p).exists(), game_files)): raise RuntimeError( f"Some game files from {game_files} not found! Probably you need to run make_games.sh" ) action_space, observation_space = common.get_games_spaces(game_files + [val_game_file]) env_id = register_games(game_files, request_infos=EnvInfos(**EXTRA_GAME_INFO), name=args.game, action_space=action_space, observation_space=observation_space) print("Registered env %s for game files %s" % (env_id, game_files)) val_env_id = register_games([val_game_file], request_infos=EnvInfos(**EXTRA_GAME_INFO), name=args.game, action_space=action_space, observation_space=observation_space) print("Game %s, with file %s will be used for validation" % (val_env_id, val_game_file)) env = gym.make(env_id) env = preproc.TextWorldPreproc(env, use_admissible_commands=False,