Exemplo n.º 1
0
    def __init__(self, flags: Mapping = {}, rng: Optional[RandomState] = None):
        """
        Create a grammar.

        :param flags:
            Flags guiding the text generation process.
            TODO: describe expected flags.
        :param rng:
            Random generator used for sampling tag expansions.
        """
        self.flags = flags
        self.grammar = OrderedDict()
        self.rng = g_rng.next() if rng is None else rng
        self.allowed_variables_numbering = self.flags.get("allowed_variables_numbering", False)
        self.unique_expansion = self.flags.get("unique_expansion", False)
        self.all_expansions = defaultdict(list)

        # The current used symbols
        self.overflow_dict = OrderedDict()
        self.used_names = set(self.flags.get("names_to_exclude", []))

        # Load the grammar associated to the provided theme.
        self.theme = self.flags.get("theme", "house")
        grammar_contents = []

        # Load the object names file
        files = os.listdir(data.get_text_grammars_path())
        files = [f for f in files if f.startswith(self.theme + "_") and f.endswith(".twg")]
        for filename in files:
            with open(pjoin(data.get_text_grammars_path(), filename)) as f:
                grammar_contents.extend(f.readlines())

        self._parse(grammar_contents)
Exemplo n.º 2
0
    def __init__(self, options: Union[GrammarOptions, Mapping] = {}, rng: Optional[RandomState] = None):
        """
        Create a grammar.

        Arguments:
        options:
            For customizing text generation process (see
            :py:class:`textworld.generator.GrammarOptions <textworld.generator.text_grammar.GrammarOptions>`
            for the list of available options).
        :param rng:
            Random generator used for sampling tag expansions.
        """
        self.options = GrammarOptions(options)
        self.grammar = OrderedDict()
        self.rng = g_rng.next() if rng is None else rng
        self.allowed_variables_numbering = self.options.allowed_variables_numbering
        self.unique_expansion = self.options.unique_expansion
        self.all_expansions = defaultdict(list)

        # The current used symbols
        self.overflow_dict = OrderedDict()
        self.used_names = set(self.options.names_to_exclude)

        # Load the grammar associated to the provided theme.
        self.theme = self.options.theme
        grammar_contents = []

        # Load the object names file
        files = os.listdir(data.get_text_grammars_path())
        files = [f for f in files if f.startswith(self.theme + "_") and f.endswith(".twg")]
        for filename in files:
            with open(pjoin(data.get_text_grammars_path(), filename)) as f:
                grammar_contents.extend(f.readlines())

        self._parse(grammar_contents)
Exemplo n.º 3
0
    def generate_name(self, obj_type: str, room_type: str = "",
                      include_adj: bool = True, exclude: Container[str] = []) -> Tuple[str, str, str]:
        """
        Generate a name given an object type and the type room it belongs to.

        Parameters
        ----------
        obj_type :
            Type of the object for which we will generate a name.
        room_type : optional
            Type of the room the object belongs to.
        include_adj : optional
            If True, the name can contain a generated adjective.
            If False, any generated adjective will be discarded.
        exclude : optional
            List of names we should avoid generating.

        Returns
        -------
        name :
            The whole name, i.e. `adj + " " + noun`.
        adj :
            The adjective part of the name.
        noun :
            The noun part of the name.
        """

        # Get room-specialized name, if possible.
        symbol = "#{}_({})#".format(room_type, obj_type)
        if not self.has_tag(symbol):
            # Otherwise, fallback on the generic object names.
            symbol = "#({})#".format(obj_type)

        # We don't want to generate a name that is in `exclude`.
        found_candidate = False
        for i in range(50):  # We default to fifty attempts
            candidate = self.expand(symbol)
            name, adj, noun = self.split_name_adj_noun(candidate, include_adj)

            if name not in exclude:
                found_candidate = True
                break

        if not found_candidate:
            # Not enough variation for the object we want to name.
            # Warn the user and fall back on adding an adjective if we can.
            if not include_adj:
                name, adj, noun = self.generate_name(obj_type, room_type, include_adj=True, exclude=exclude)
                msg = ("Not enough variation for '{}'. Falling back on using adjective '{}'."
                       " To avoid this message you can add more variation in the '{}'"
                       " related grammar files located in '{}'.")
                msg = msg.format(symbol, adj, self.theme, data.get_text_grammars_path())
                warnings.warn(msg, textworld.TextworldGenerationWarning)
                return name, adj, noun

            # Still not enough variation for the object we want to name.
            if not self.allowed_variables_numbering:
                msg = ("Not enough variation for '{}'. You can add more variation"
                       " in the '{}' related grammar files located in '{}'"
                       " or turn on the 'include_adj=True' grammar flag."
                       " In last resort, you could always turn on the"
                       " 'allowed_variables_numbering=True' grammar flag"
                       " to append unique number to object name.")
                msg = msg.format(symbol, self.theme, data.get_text_grammars_path())
                raise ValueError(msg)

            if obj_type not in self.overflow_dict:
                self.overflow_dict[obj_type] = []

            # Append unique (per type) number to the noun.
            suffix = " {}".format(len(self.overflow_dict[obj_type]))
            noun += suffix
            name += suffix
            self.overflow_dict[obj_type].append(name)

        return name, adj, noun