def generate_name_fail(self): grammar = Grammar() try: grammar.generate_name('object', 'vault', False, exclude=ContainsEveryObjectContainer()) self.assertTrue(False, "We should have errored about an impossible object name") except ValueError: pass
def describe_event(event: Event, game: Game, grammar: Grammar) -> str: """ Assign a descripton to a quest. """ # We have to "count" all the adj/noun/types in the world # This is important for using "unique" but abstracted references to objects counts = OrderedDict() counts["adj"] = CountOrderedDict() counts["noun"] = CountOrderedDict() counts["type"] = CountOrderedDict() # Assign name and description to objects. for obj in game.world.objects: if obj.type in ["I", "P"]: continue obj_infos = game.infos[obj.id] counts['adj'][obj_infos.adj] += 1 counts['noun'][obj_infos.noun] += 1 counts['type'][obj.type] += 1 if len(event.actions) == 0: # We don't need to say anything if the quest is empty event_desc = "" else: # Generate a description for either the last, or all commands if grammar.options.only_last_action: actions_desc, _ = generate_instruction(event.actions[-1], grammar, game.infos, game.world, counts) only_one_action = True else: actions_desc_list = [] # Decide if we blend instructions together or not if grammar.options.blend_instructions: instructions = get_action_chains(event.actions, grammar, game.infos) else: instructions = event.actions only_one_action = len(instructions) < 2 for c in instructions: desc, separator = generate_instruction(c, grammar, game.infos, game.world, counts) actions_desc_list.append(desc) if c != instructions[-1] and len(separator) > 0: actions_desc_list.append(separator) actions_desc = " ".join(actions_desc_list) if only_one_action: quest_tag = grammar.get_random_expansion("#quest_one_action#") quest_tag = quest_tag.replace("(action)", actions_desc.strip()) else: quest_tag = grammar.get_random_expansion("#quest#") quest_tag = quest_tag.replace("(list_of_actions)", actions_desc.strip()) event_desc = grammar.expand(quest_tag) event_desc = re.sub(r"(^|(?<=[?!.]))\s*([a-z])", lambda pat: pat.group(1) + ' ' + pat.group(2).upper(), event_desc) return event_desc
def generate_name_force_numbered(self): suffix = '_1' grammar = Grammar(flags={'allowed_variables_numbering': True}) name, adj, noun = grammar.generate_name('object', 'vault', False, exclude=ContainsEveryObjectContainer()) self.assertTrue(name.endswith(suffix), 'Checking name ends with suffix') self.assertTrue(adj.endswith(suffix), 'Checking adj ends with suffix') self.assertTrue(noun.endswith(suffix), 'Checking noun ends with suffix')
def generate_text_from_grammar(game, grammar: Grammar): include_adj = grammar.flags.get("include_adj", False) only_last_action = grammar.flags.get("only_last_action", False) blend_instructions = grammar.flags.get("blend_instructions", False) blend_descriptions = grammar.flags.get("blend_descriptions", False) ambiguous_instructions = grammar.flags.get("ambiguous_instructions", False) # Assign a specific room type and name to our rooms for room in game.world.rooms: # First, generate a unique roomtype and name from the grammar if game.infos[room.id].room_type is None and grammar.has_tag( "#room_type#"): game.infos[room.id].room_type = grammar.expand("#room_type#") assign_name_to_object(room, grammar, game.infos, include_adj) # Next, assure objects contained in a room must have the same room type for obj in game.world.get_all_objects_in(room): if game.infos[obj.id].room_type is None: game.infos[obj.id].room_type = game.infos[room.id].room_type # Objects in inventory can be of any room type. for obj in game.world.get_objects_in_inventory(): if game.infos[obj.id].room_type is None and grammar.has_tag( "#room_type#"): game.infos[obj.id].room_type = grammar.expand("#room_type#") # We have to "count" all the adj/noun/types in the world # This is important for using "unique" but abstracted references to objects counts = OrderedDict() counts["adj"] = CountOrderedDict() counts["noun"] = CountOrderedDict() counts["type"] = CountOrderedDict() # Assign name and description to objects. for obj in game.world.objects: if obj.type in ["I", "P"]: continue obj_infos = game.infos[obj.id] assign_name_to_object(obj, grammar, game.infos, include_adj) assign_description_to_object(obj, grammar, game.infos) counts['adj'][obj_infos.adj] += 1 counts['noun'][obj_infos.noun] += 1 counts['type'][obj.type] += 1 # Generate the room descriptions. for room in game.world.rooms: assign_description_to_room(room, game, grammar, blend_descriptions) # Generate the instructions. for quest in game.quests: assign_description_to_quest(quest, game, grammar, counts, only_last_action, blend_instructions, ambiguous_instructions) return game
def split_name_adj_noun_fail(self): """ What happens if we have too many separators? """ grammar = Grammar() try: grammar.split_name_adj_noun('A|B|C', True) self.assertTrue(False, "We should have errored about too many separators") except ValueError: pass
def test_grammar_get_random_expansion_fail(self): """ Tests failure when getting a non-existent flag (unsuccess used in names as _fail is a special flag in nosetests) """ grammar = Grammar() bad_tag_name = 'fahawagads' try: grammar.get_random_expansion(tag=bad_tag_name) self.assertTrue(False, "We should have errored with a value error about a non-existent tag") except ValueError as e: self.assertTrue(bad_tag_name in str(e), "Tag name does not occur in error message")
def generate_text_from_grammar(game, grammar: Grammar): # Assign a specific room type and name to our rooms for room in game.world.rooms: # First, generate a unique roomtype and name from the grammar if game.infos[room.id].room_type is None and grammar.has_tag( "#room_type#"): game.infos[room.id].room_type = grammar.expand("#room_type#") assign_name_to_object(room, grammar, game.infos) # Next, assure objects contained in a room must have the same room type for obj in game.world.get_all_objects_in(room): if game.infos[obj.id].room_type is None: game.infos[obj.id].room_type = game.infos[room.id].room_type # Objects in inventory can be of any room type. for obj in game.world.get_objects_in_inventory(): if game.infos[obj.id].room_type is None and grammar.has_tag( "#room_type#"): game.infos[obj.id].room_type = grammar.expand("#room_type#") # Assign name and description to objects. for obj in game.world.objects: if obj.type in ["I", "P"]: continue assign_name_to_object(obj, grammar, game.infos) assign_description_to_object(obj, grammar, game.infos) # Generate the room descriptions. for room in game.world.rooms: if game.infos[ room. id].desc is None: # Skip rooms which already have a description. game.infos[room.id].desc = assign_description_to_room( room, game, grammar) # Generate the instructions. for quest in game.quests: if quest.desc is None: # Skip quests which already have a description. quest.desc = assign_description_to_quest(quest, game, grammar) if grammar.options.only_last_action and len(game.quests) > 1: main_quest = Quest( actions=[quest.actions[-1] for quest in game.quests]) only_last_action_bkp = grammar.options.only_last_action grammar.options.only_last_action = False game.objective = assign_description_to_quest(main_quest, game, grammar) grammar.options.only_last_action = only_last_action_bkp return game
def deserialize(cls, data: Mapping) -> "Game": """ Creates a `Game` from serialized data. Args: data: Serialized data with the needed information to build a `Game` object. """ version = data.get("version", cls._SERIAL_VERSION) if version != cls._SERIAL_VERSION: raise ValueError( "Cannot deserialize a TextWorld version {} game, expected version {}" .format(version, cls._SERIAL_VERSION)) world = World.deserialize(data["world"]) game = cls(world) game.grammar = Grammar(data["grammar"]) game.quests = tuple([Quest.deserialize(d) for d in data["quests"]]) game._infos = {k: EntityInfo.deserialize(v) for k, v in data["infos"]} game.kb = KnowledgeBase.deserialize(data["KB"]) game.metadata = data.get("metadata", {}) game._objective = data.get("objective", None) game.extras = data.get("extras", {}) if "main_quest" in data: game.main_quest = Quest.deserialize(data["main_quest"]) return game
def extract_vocab(grammar_options: GrammarOptions, kb: Optional[KnowledgeBase] = None) -> List[str]: kb = kb or KnowledgeBase.default() # Extract words from logic. text = kb.logic.serialize() # Extract words from text grammar. rng_grammar = np.random.RandomState( 1234) # Fix generator. #XXX really needed? grammar = Grammar(grammar_options, rng=rng_grammar) grammar_words = grammar.get_vocabulary() text += " ".join(set(grammar_words)).lower() # Strip out all non-alphanumeric characters. text = re.sub(r"[^a-z0-9\-_ ']", " ", text) words = text.split() vocab = sorted(set(words)) return vocab
def extract_vocab(games: Iterable[Game]) -> List[str]: i7_pattern = re.compile(r'\[[^]]*\]') # Found in object descriptions. text = "" seen = set() for game in games: if game.kb not in seen: seen.add(game.kb) # Extract words from logic (only stuff related to Inform7). text += game.kb.inform7_addons_code + "\n" text += " ".join(game.kb.inform7_commands.values()) + "\n" text += " ".join(game.kb.inform7_events.values()) + "\n" text += " ".join(game.kb.inform7_variables.values()) + "\n" text += " ".join(game.kb.inform7_variables.values()) + "\n" text += " ".join( t for t in game.kb.inform7_variables_description.values() if t) + "\n" if game.grammar.options.uuid not in seen: seen.add(game.grammar.options.uuid) # Extract words from text grammar. grammar = Grammar(game.grammar.options) grammar_words = grammar.get_vocabulary() text += " ".join(set(grammar_words)).lower() + "\n" # Parse game specific entity names and descriptions. text += game.objective + "\n" for infos in game.infos.values(): if infos.name: text += infos.name + " " if infos.desc: text += i7_pattern.sub(" ", infos.desc) + "\n" # Next strip out all non-alphabetic characters text = re.sub(r"[^a-z0-9\-_ ']", " ", text.lower()) words = text.split() vocab = sorted(set(word.strip("-'_") for word in words)) return vocab
def deserialize(cls, data: Mapping) -> "Game": """ Creates a `Game` from serialized data. Args: data: Serialized data with the needed information to build a `Game` object. """ world = World.deserialize(data["world"]) game = cls(world) game.grammar = Grammar(data["grammar"]) game.quests = tuple([Quest.deserialize(d) for d in data["quests"]]) game._infos = {k: EntityInfo.deserialize(v) for k, v in data["infos"]} game.kb = KnowledgeBase.deserialize(data["KB"]) game.metadata = data.get("metadata", {}) game._objective = data.get("objective", None) return game
def deserialize(cls, data: Mapping) -> "Game": """ Creates a `Game` from serialized data. Args: data: Serialized data with the needed information to build a `Game` object. """ world = World.deserialize(data["world"]) grammar = None if "grammar" in data: grammar = Grammar(data["grammar"]) quests = [Quest.deserialize(d) for d in data["quests"]] game = cls(world, grammar, quests) game._infos = {k: EntityInfo.deserialize(v) for k, v in data["infos"]} game.state = State.deserialize(data["state"]) game._rules = {k: Rule.deserialize(v) for k, v in data["rules"]} game._types = VariableTypeTree.deserialize(data["types"]) game.metadata = data.get("metadata", {}) return game
def make_grammar(options: Mapping = {}, rng: Optional[RandomState] = None) -> Grammar: rng = g_rng.next() if rng is None else rng grammar = Grammar(options, rng) grammar.check() return grammar
def test_grammar_eq2(self): grammar = Grammar(options={'theme': 'house'}) grammar2 = Grammar(options={'theme': 'basic'}) self.assertNotEqual( grammar, grammar2, "Testing two different grammar files are not equal")
def test_grammar_eq(self): grammar = Grammar() grammar2 = Grammar() self.assertEqual(grammar, grammar2, "Testing two grammar files are equivalent")
def test_get_all_nouns_for_type(self): grammar = Grammar() result = grammar.get_all_nouns_for_type('d') self.assertNotEqual(len(result), 0, 'No nouns for door type found')
def test_get_all_adj_for_type(self): grammar = Grammar() result = grammar.get_all_adjective_for_type('d') self.assertNotEqual(len(result), 0, 'No adjectives for door type found')
def test_get_all_expansions_for_tag(self): grammar = Grammar() result = grammar.get_all_expansions_for_tag('#clean_(r)#') self.assertNotEqual(len(result), 0, 'No expansions for library tag found')
def test_get_all_expansions_for_tag_not_existing(self): grammar = Grammar() result = grammar.get_all_expansions_for_tag('fahawagads') self.assertEqual(len(result), 0, 'Result is not empty')
def test_grammar_eq2(self): grammar = Grammar() grammar2 = Grammar(flags={'unused': 'flag'}) self.assertNotEqual(grammar, grammar2, "Testing two different grammar files are not equal")