Esempio n. 1
0
    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"]
Esempio n. 2
0
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)
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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()))