def step(self, command: str): self.state, score, done = self._wrapped_env.step(command) if not self.tracking: return self.state, score, done # State tracking not needed. # Detect what events just happened in the game. i7_events, self.state["feedback"] = _detect_i7_events_debug_tags( self.state["feedback"]) if str2bool(os.environ.get("TEXTWORLD_DEBUG", False)): print("[DEBUG] Detected Inform7 events:\n{}\n".format(i7_events)) self._previous_winning_policy = self._current_winning_policy for i7_event in i7_events: valid_actions = self._game_progression.valid_actions self._last_action = self._inform7.detect_action( i7_event, valid_actions) if self._last_action is not None: # An action that affects the state of the game. self._game_progression.update(self._last_action) self._current_winning_policy = self._game_progression.winning_policy self._moves += 1 self._gather_infos() self.state["done"] = self.state["won"] or self.state["lost"] return self.state, score, self.state["done"]
def test_show_graph(): game = _make_game() renderer = None if str2bool(os.environ.get("TEXTWORLD_DEBUG", False)): renderer = "browser" show_graph(game.world.facts, renderer=renderer)
def compile_game(game: Game, game_name: Optional[str] = None, metadata: Mapping = {}, game_logger: Optional[GameLogger] = None, games_folder: str = "./gen_games", force_recompile: bool = False, file_type: str = ".ulx") -> str: """ Compile a game. Arguments: game: Game object to compile. game_name: Name of the compiled file (without extension). If `None`, a unique name will be infered from the game object. metadata: (Deprecated) contains information about how the game object was generated. game_logger: Object used to log stats about generated games. games_folder: Path to the folder where the compiled game will be saved. force_recompile: If `True`, recompile game even if it already exists. file_type: Either .z8 (Z-Machine) or .ulx (Glulx). Returns: The path to compiled game. """ game_name = game_name or game.metadata["uuid"] source = generate_inform7_source(game) maybe_mkdir(games_folder) if str2bool(os.environ.get("TEXTWORLD_FORCE_ZFILE", False)): file_type = ".z8" game_json = pjoin(games_folder, game_name + ".json") meta_json = pjoin(games_folder, game_name + ".meta") game_file = pjoin(games_folder, game_name + file_type) already_compiled = False # Check if game is already compiled. if not force_recompile and os.path.isfile(game_file) and os.path.isfile( game_json): already_compiled = game == Game.load(game_json) msg = ( "It's highly unprobable that two games with the same id have different structures." " That would mean the generator has been modified." " Please clean already generated games found in '{}'.".format( games_folder)) assert already_compiled, msg if not already_compiled or force_recompile: json.dump(metadata, open(meta_json, 'w')) game.save(game_json) compile_inform7_game(source, game_file) if game_logger is not None: game_logger.collect(game) return game_file
def compile_game(game: Game, path: str, force_recompile: bool = False): """ Compile a game. Arguments: game: Game object to compile. path: Path of the compiled game (.ulx or .z8). Also, the source (.ni) and metadata (.json) files will be saved along with it. force_recompile: If `True`, recompile game even if it already exists. Returns: The path to compiled game. """ folder, filename = os.path.split(path) if not filename: filename = game.metadata.get("uuid", str(uuid.uuid4())) filename, ext = os.path.splitext(filename) if not ext: ext = ".ulx" # Add default extension, if needed. if str2bool(os.environ.get("TEXTWORLD_FORCE_ZFILE", False)): ext = ".z8" source = generate_inform7_source(game) maybe_mkdir(folder) game_json = pjoin(folder, filename + ".json") game_file = pjoin(folder, filename + ext) already_compiled = False # Check if game is already compiled. if not force_recompile and os.path.isfile(game_file) and os.path.isfile( game_json): already_compiled = game == Game.load(game_json) msg = ( "It's highly unprobable that two games with the same id have different structures." " That would mean the generator has been modified." " Please clean already generated games found in '{}'.".format( folder)) assert already_compiled, msg if not already_compiled or force_recompile: game.save(game_json) compile_inform7_game(source, game_file) return game_file
def compile_inform7_game(source, output, verbose=False): with make_temp_directory(prefix="tmp_inform") as project_folder: filename, ext = os.path.splitext(output) story_filename = filename + ".ni" # Save story file. with open(story_filename, 'w') as f: f.write(source) # Create the file structure needed by Inform7. source_folder = pjoin(project_folder, "Source") build_folder = pjoin(project_folder, "Build") if not os.path.isdir(source_folder): os.makedirs(source_folder) shutil.copy(story_filename, pjoin(source_folder, "story.ni")) # Write mandatory uuid.txt file open(pjoin(project_folder, "uuid.txt"), 'w').close() # Build Inform7 -> Inform6 -> game INFORM_HOME = os.environ.get("INFORM_HOME", I7_DEFAULT_PATH) ni = pjoin(INFORM_HOME, "share", "inform7", "Compilers", "ni") i6 = pjoin(INFORM_HOME, "share", "inform7", "Compilers", "inform6") i7_internal = pjoin(INFORM_HOME, "share", "inform7", "Internal") # Compile story file. cmd = [ ni, "--internal", i7_internal, "--format={}".format(ext), "--project", project_folder ] if verbose: print("Running: {}".format(" ".join(cmd))) try: stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: msg = "" msg += "\n-== ni =-\nFAIL: {}\n{}========\n".format( exc.returncode, exc.output.decode()) msg += "*** Usually this means a compilation error.\n" if ext == ".z8": msg += "*** Maybe the game is too big for a .z8 file. Try using .ulx instead.\n" msg += "*** See {} for more information.\n".format(story_filename) raise CouldNotCompileGameError(msg) else: if verbose: print("-= ni =-\n{}========\n".format(stdout.decode())) # Compile inform6 code. i6_input_filename = pjoin(build_folder, "auto.inf") i6_options = "-" # i6_options += "k" # Debug file, maybe useful to extract vocab? if str2bool(os.environ.get("TEXTWORLD_I6_DEBUG", True)): i6_options += "D" # Debug mode, so we can do "actions on" and get Inform7 action events. i6_options += "E2wS" i6_options += "G" if ext == ".ulx" else "v8" i6_options += "F0" # Use extra memory rather than temporary files. cmd = [i6, i6_options, i6_input_filename, output] if verbose: print("Running: {}".format(" ".join(cmd))) try: stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: msg = "" msg += "\n-= i6 =-\nFAIL: {}\n{}========\n".format( exc.returncode, exc.output.decode()) msg += "*** Usually this means a compilation error.\n" if ext == ".z8": msg += "*** Maybe the game is too big for a .z8 file. Try using .ulx instead.\n" msg += "*** See {} for more information.\n".format(story_filename) raise CouldNotCompileGameError(msg) else: if verbose: print("-= i6 =-\n{}========\n".format(stdout.decode()))