def test_one_choice__marked(self): start = facts.Start(uid="start", type="test", nesting=0) choice_1 = facts.Choice(uid="choice_1") finish_1 = facts.Finish(uid="finish_1", results={}, nesting=0, start="start") finish_2 = facts.Finish(uid="finish_2", results={}, nesting=0, start="start") marked_option = facts.Option( state_from=choice_1.uid, state_to=finish_2.uid, type="opt_2", markers=[relations.OPTION_MARKERS.HONORABLE] ) facts_list = [ start, choice_1, finish_1, finish_2, facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type="opt_1", markers=()), marked_option, ] self.kb += facts_list for i in xrange(100): transformators.determine_default_choices(self.kb, preferred_markers=[relations.OPTION_MARKERS.HONORABLE]) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.OptionsLink))), 0) self.assertEqual(len(list(self.kb.filter(facts.ChoicePath))), 1) self.assertEqual(self.kb.filter(facts.ChoicePath).next().option, marked_option.uid) self.kb -= self.kb.filter(facts.ChoicePath)
def test_two_choices(self): start = facts.Start(uid="start", type="test", nesting=0) choice_1 = facts.Choice(uid="choice_1") choice_2 = facts.Choice(uid="choice_2") finish_1 = facts.Finish(uid="finish_1", results={}, nesting=0, start="start") finish_2 = facts.Finish(uid="finish_2", results={}, nesting=0, start="start") option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type="opt_1", markers=()) option_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type="opt_2", markers=()) option_2_1 = facts.Option(state_from=choice_2.uid, state_to=finish_1.uid, type="opt_2_1", markers=()) option_2_2 = facts.Option(state_from=choice_2.uid, state_to=finish_2.uid, type="opt_2_2", markers=()) facts_list = [start, choice_1, choice_2, finish_1, finish_2, option_1, option_2, option_2_1, option_2_2] self.kb += facts_list for i in xrange(100): transformators.determine_default_choices(self.kb) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.OptionsLink))), 0) self.assertEqual(len(list(self.kb.filter(facts.ChoicePath))), 2) self.assertEqual(len(set([path.choice for path in self.kb.filter(facts.ChoicePath)])), 2) self.kb -= self.kb.filter(facts.ChoicePath)
def _create_random_quest_for_hero(hero_info, start_quests, without_restrictions=False): knowledge_base = get_knowledge_base( hero_info, without_restrictions=without_restrictions) selector = Selector(knowledge_base, QUESTS_BASE, social_connection_probability=0) hero_uid = uids.hero(hero_info.id) quests_facts = selector.create_quest_from_place( nesting=0, initiator_position=selector.place_for(objects=(hero_uid, )), allowed=start_quests, excluded=[], tags=('can_start', )) knowledge_base += quests_facts transformators.activate_events( knowledge_base) # TODO: after remove restricted states transformators.remove_restricted_states(knowledge_base) transformators.remove_broken_states( knowledge_base) # MUST be called after all graph changes transformators.determine_default_choices( knowledge_base, preferred_markers=hero_info.prefered_quest_markers ) # MUST be called after all graph changes and on valid graph transformators.remove_unused_actors(knowledge_base) knowledge_base.validate_consistency(WORLD_RESTRICTIONS) knowledge_base.validate_consistency(QUEST_RESTRICTIONS) return knowledge_base
def _create_random_quest_for_hero(hero_info, start_quests, without_restrictions=False): knowledge_base = get_knowledge_base(hero_info, without_restrictions=without_restrictions) selector = Selector(knowledge_base, QUESTS_BASE, social_connection_probability=c.QUESTS_SOCIAL_CONNECTIONS_FRACTION) hero_uid = uids.hero(hero_info.id) quests_facts = selector.create_quest_from_place(nesting=0, initiator_position=selector.place_for(objects=(hero_uid,)), allowed=start_quests, excluded=[], tags=('can_start', )) knowledge_base += quests_facts transformators.activate_events(knowledge_base) # TODO: after remove restricted states transformators.remove_restricted_states(knowledge_base) transformators.remove_broken_states(knowledge_base) # MUST be called after all graph changes transformators.determine_default_choices(knowledge_base, preferred_markers=hero_info.prefered_quest_markers) # MUST be called after all graph changes and on valid graph transformators.remove_unused_actors(knowledge_base) knowledge_base.validate_consistency(WORLD_RESTRICTIONS) knowledge_base.validate_consistency(QUEST_RESTRICTIONS) return knowledge_base
def test_one_choice(self): start = facts.Start(uid='start', type='test', nesting=0) choice_1 = facts.Choice(uid='choice_1') finish_1 = facts.Finish(uid='finish_1', results={}, nesting=0, start='start') finish_2 = facts.Finish(uid='finish_2', results={}, nesting=0, start='start') option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type='opt_1', markers=()) option_2 = facts.Option(state_from=choice_1.uid, state_to=finish_2.uid, type='opt_2', markers=()) facts_list = [start, choice_1, finish_1, finish_2, option_1, option_2] self.kb += facts_list transformators.determine_default_choices(self.kb) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.OptionsLink))), 0) self.assertEqual(len(list(self.kb.filter(facts.ChoicePath))), 1) self.assertEqual( len(set([path.choice for path in self.kb.filter(facts.ChoicePath)])), 1) self.assertTrue( self.kb.filter(facts.ChoicePath).next().option in set( [option_1.uid, option_2.uid]))
def test_linked_choices(self): start = facts.Start(uid='start', type='test', nesting=0) choice_1 = facts.Choice(uid='choice_1') choice_2 = facts.Choice(uid='choice_2') finish_1 = facts.Finish(uid='finish_1', results={}, nesting=0, start='start') finish_2 = facts.Finish(uid='finish_2', results={}, nesting=0, start='start') option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type='opt_1', markers=()) option_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type='opt_2', markers=()) option_2_1 = facts.Option(state_from=choice_2.uid, state_to=finish_1.uid, type='opt_2_1', markers=()) option_2_2 = facts.Option(state_from=choice_2.uid, state_to=finish_2.uid, type='opt_2_2', markers=()) facts_list = [ start, choice_1, choice_2, finish_1, finish_2, option_1, option_2, option_2_1, option_2_2, facts.OptionsLink(options=(option_1.uid, option_2_1.uid)), facts.OptionsLink(options=(option_2.uid, option_2_2.uid))] self.kb += facts_list transformators.determine_default_choices(self.kb) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.ChoicePath))), 2) self.assertEqual(len(set([path.choice for path in self.kb.filter(facts.ChoicePath)])), 2) chosen_options = set([path.option for path in self.kb.filter(facts.ChoicePath)]) self.assertTrue(chosen_options == set([option_1.uid, option_2_1.uid]) or chosen_options == set([option_2.uid, option_2_2.uid]) )
def test_one_choice__no_markers(self): start = facts.Start(uid='start', type='test', nesting=0) choice_1 = facts.Choice(uid='choice_1') finish_1 = facts.Finish(uid='finish_1', results={}, nesting=0, start='start') finish_2 = facts.Finish(uid='finish_2', results={}, nesting=0, start='start') option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type='opt_1', markers=[relations.OPTION_MARKERS.DISHONORABLE]) option_2 = facts.Option(state_from=choice_1.uid, state_to=finish_2.uid, type='opt_2', markers=[relations.OPTION_MARKERS.AGGRESSIVE]) facts_list = [ start, choice_1, finish_1, finish_2, option_1, option_2 ] self.kb += facts_list for i in xrange(100): transformators.determine_default_choices(self.kb, preferred_markers=[relations.OPTION_MARKERS.HONORABLE]) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.OptionsLink))), 0) self.assertEqual(len(list(self.kb.filter(facts.ChoicePath))), 1) self.assertEqual(len(set([path.choice for path in self.kb.filter(facts.ChoicePath)])), 1) self.assertTrue(self.kb.filter(facts.ChoicePath).next().option in set([option_1.uid, option_2.uid])) self.kb -= self.kb.filter(facts.ChoicePath)
def test_linked_choices__linked_option_with_processed_choice(self): is_raised = False for i in xrange(100): kb = KnowledgeBase() start = facts.Start(uid='start', type='test', nesting=0) choice_1 = facts.Choice(uid='choice_1') choice_2 = facts.Choice(uid='choice_2') finish_1 = facts.Finish(uid='finish_1', results={}, nesting=0, start='start') finish_2 = facts.Finish(uid='finish_2', results={}, nesting=0, start='start') option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type='opt_1', markers=()) option_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type='opt_2', markers=()) option_2_1 = facts.Option(state_from=choice_2.uid, state_to=finish_1.uid, type='opt_2_1', markers=()) option_2_2 = facts.Option(state_from=choice_2.uid, state_to=finish_2.uid, type='opt_2_2', markers=()) facts_list = [ start, facts.Jump(state_from=start.uid, state_to=choice_1.uid), choice_1, choice_2, finish_1, finish_2, option_1, option_2, option_2_1, option_2_2, facts.OptionsLink(options=(option_2.uid, option_2_2.uid)) ] kb += facts_list try: transformators.determine_default_choices(kb) except exceptions.LinkedOptionWithProcessedChoiceError: is_raised = True self.assertEqual(len(list(kb.filter(facts.ChoicePath))), 1) self.assertEqual( [path.choice for path in kb.filter(facts.ChoicePath)], [choice_2.uid]) self.assertEqual( [path.option for path in kb.filter(facts.ChoicePath)], [option_2_1.uid]) break self.assertFalse(is_raised)
def test_no_choices(self): facts_list = [ facts.Start(uid='start', type='test', nesting=0), facts.Finish(uid='st_finish', results={}, nesting=0, start='start'), facts.Jump(state_from='start', state_to='st_finish') ] self.kb += facts_list transformators.determine_default_choices(self.kb) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.OptionsLink))), 0)
def test_one_choice__no_markers(self): start = facts.Start(uid='start', type='test', nesting=0) choice_1 = facts.Choice(uid='choice_1') finish_1 = facts.Finish(uid='finish_1', results={}, nesting=0, start='start') finish_2 = facts.Finish(uid='finish_2', results={}, nesting=0, start='start') option_1 = facts.Option( state_from=choice_1.uid, state_to=finish_1.uid, type='opt_1', markers=[relations.OPTION_MARKERS.DISHONORABLE]) option_2 = facts.Option(state_from=choice_1.uid, state_to=finish_2.uid, type='opt_2', markers=[relations.OPTION_MARKERS.AGGRESSIVE]) facts_list = [start, choice_1, finish_1, finish_2, option_1, option_2] self.kb += facts_list for i in xrange(100): transformators.determine_default_choices( self.kb, preferred_markers=[relations.OPTION_MARKERS.HONORABLE]) self.check_in_knowledge_base(self.kb, facts_list) self.assertEqual(len(list(self.kb.filter(facts.OptionsLink))), 0) self.assertEqual(len(list(self.kb.filter(facts.ChoicePath))), 1) self.assertEqual( len( set([ path.choice for path in self.kb.filter(facts.ChoicePath) ])), 1) self.assertTrue( self.kb.filter(facts.ChoicePath).next().option in set( [option_1.uid, option_2.uid])) self.kb -= self.kb.filter(facts.ChoicePath)
def test_linked_choices__linked_option_with_processed_choice(self): is_raised = False for i in xrange(100): kb = KnowledgeBase() start = facts.Start(uid="start", type="test", nesting=0) choice_1 = facts.Choice(uid="choice_1") choice_2 = facts.Choice(uid="choice_2") finish_1 = facts.Finish(uid="finish_1", results={}, nesting=0, start="start") finish_2 = facts.Finish(uid="finish_2", results={}, nesting=0, start="start") option_1 = facts.Option(state_from=choice_1.uid, state_to=finish_1.uid, type="opt_1", markers=()) option_2 = facts.Option(state_from=choice_1.uid, state_to=choice_2.uid, type="opt_2", markers=()) option_2_1 = facts.Option(state_from=choice_2.uid, state_to=finish_1.uid, type="opt_2_1", markers=()) option_2_2 = facts.Option(state_from=choice_2.uid, state_to=finish_2.uid, type="opt_2_2", markers=()) facts_list = [ start, facts.Jump(state_from=start.uid, state_to=choice_1.uid), choice_1, choice_2, finish_1, finish_2, option_1, option_2, option_2_1, option_2_2, facts.OptionsLink(options=(option_2.uid, option_2_2.uid)), ] kb += facts_list try: transformators.determine_default_choices(kb) except exceptions.LinkedOptionWithProcessedChoiceError: is_raised = True self.assertEqual(len(list(kb.filter(facts.ChoicePath))), 1) self.assertEqual([path.choice for path in kb.filter(facts.ChoicePath)], [choice_2.uid]) self.assertEqual([path.option for path in kb.filter(facts.ChoicePath)], [option_2_1.uid]) break self.assertFalse(is_raised)
def create_quest(): # формируем список заданий для генерации qb = QuestsBase() qb += [ Spying, Hunt, Hometown, SearchSmith, Delivery, Caravan, CollectDebt, HelpFriend, InterfereEnemy, Help ] kb = KnowledgeBase() # описываем мир kb += [ facts.Hero(uid='hero'), # наш герой facts.Place(uid='place_1', terrains=( 1, )), # есть место с идентификатором place_1 и типами ландшафта 1, facts.Place(uid='place_2', terrains=(0, )), facts.Place(uid='place_3', terrains=(0, )), facts.Place(uid='place_4', terrains=(1, )), facts.Place(uid='place_5', terrains=(2, )), facts.Place(uid='place_6', terrains=(1, )), facts.Place(uid='place_7', terrains=(2, )), facts.Place(uid='place_8', terrains=(2, )), facts.Place(uid='place_9', terrains=(1, )), facts.Place(uid='place_10', terrains=(2, )), facts.Person( uid='person_1', profession=PROFESSION.NONE ), # есть персонаж с идентификатором perons_1 и без профессии facts.Person(uid='person_2', profession=PROFESSION.BLACKSMITH), facts.Person(uid='person_3', profession=PROFESSION.ROGUE), facts.Person(uid='person_4', profession=PROFESSION.NONE), facts.Person(uid='person_5', profession=PROFESSION.NONE), facts.Person(uid='person_6', profession=PROFESSION.NONE), facts.Person(uid='person_7', profession=PROFESSION.NONE), facts.Person(uid='person_8', profession=PROFESSION.NONE), facts.Person(uid='person_9', profession=PROFESSION.NONE), facts.Person(uid='person_10', profession=PROFESSION.NONE), facts.LocatedIn( object='person_1', place='place_1'), # персонаж person_1 находится в place_1 facts.LocatedIn(object='person_2', place='place_2'), facts.LocatedIn(object='person_3', place='place_3'), facts.LocatedIn(object='person_4', place='place_4'), facts.LocatedIn(object='person_5', place='place_5'), facts.LocatedIn(object='person_6', place='place_6'), facts.LocatedIn(object='person_7', place='place_7'), facts.LocatedIn(object='person_8', place='place_8'), facts.LocatedIn(object='person_9', place='place_9'), facts.LocatedIn(object='person_10', place='place_10'), facts.LocatedIn(object='hero', place='place_1'), # герой находится в place_1 facts.Mob( uid='mob_1', terrains=(0, ) ), # есть монстр, обитающий на территориях с идентификатором 0 (для задания на охоту) facts.PreferenceMob( object='hero', mob='mob_1'), # герой любит охотиться на монстра mob_1 facts.PreferenceHometown( object='hero', place='place_2'), # герой считате родным место place_2 facts.PreferenceFriend(object='hero', person='person_4'), # герой дружит с person_4 facts.PreferenceEnemy(object='hero', person='person_5'), # герой враждует с person_5 # указываем, что обновление экипировки стоит 777 монет (для задания SearchSmith) # facts.HasMoney(object='hero', money=888), # если этот факт раскоментировать то в этом задании герой купит экипировку, а не пойдёт делать задание кузнеца facts.UpgradeEquipmentCost(money=777), facts.OnlyGoodBranches(object='place_2'), # не вредить месту place_2 facts.OnlyGoodBranches( object='person_4'), # не вредить персонажу person_4 facts.OnlyBadBranches(object='person_5') ] # не помогать персонажу person_5 kb.validate_consistency( WORLD_RESTRICTIONS) # проверяем ограничения на мир, selector = Selector(kb, qb) # создаём квест (получаем список фактов) quests_facts = selector.create_quest_from_place( nesting=0, initiator_position=kb['place_1'], tags=('can_start', )) kb += quests_facts transformators.activate_events( kb ) # активируем события (из нескольких вершин графа оставляем одну, остальные удаляем) transformators.remove_restricted_states( kb ) # удаляем состояния, в которые нельзя переходить (например, которые вредят тому, кому вредить нельщя) transformators.remove_broken_states( kb ) # чистим граф задания от разрушений, вызванных предыдущими действиями transformators.determine_default_choices( kb) # определяем выборы по умолчанию на развилках kb.validate_consistency(WORLD_RESTRICTIONS) # ещё раз проверяем мир kb.validate_consistency( QUEST_RESTRICTIONS ) # проверяем граф задания (вдруг полностью разрушен) return kb
def create_quest(): # формируем список заданий для генерации qb = QuestsBase() qb += [Spying, Hunt, Hometown, SearchSmith, Delivery, Caravan, CollectDebt, HelpFriend, InterfereEnemy, Help] kb = KnowledgeBase() # описываем мир kb += [ facts.Hero(uid='hero'), # наш герой facts.Place(uid='place_1', terrains=(1,)), # есть место с идентификатором place_1 и типами ландшафта 1, facts.Place(uid='place_2', terrains=(0,)), facts.Place(uid='place_3', terrains=(0,)), facts.Place(uid='place_4', terrains=(1,)), facts.Place(uid='place_5', terrains=(2,)), facts.Place(uid='place_6', terrains=(1,)), facts.Place(uid='place_7', terrains=(2,)), facts.Place(uid='place_8', terrains=(2,)), facts.Place(uid='place_9', terrains=(1,)), facts.Place(uid='place_10', terrains=(2,)), facts.Person(uid='person_1', profession=PROFESSION.NONE), # есть персонаж с идентификатором perons_1 и без профессии facts.Person(uid='person_2', profession=PROFESSION.BLACKSMITH), facts.Person(uid='person_3', profession=PROFESSION.ROGUE), facts.Person(uid='person_4', profession=PROFESSION.NONE), facts.Person(uid='person_5', profession=PROFESSION.NONE), facts.Person(uid='person_6', profession=PROFESSION.NONE), facts.Person(uid='person_7', profession=PROFESSION.NONE), facts.Person(uid='person_8', profession=PROFESSION.NONE), facts.Person(uid='person_9', profession=PROFESSION.NONE), facts.Person(uid='person_10', profession=PROFESSION.NONE), facts.LocatedIn(object='person_1', place='place_1'), # персонаж person_1 находится в place_1 facts.LocatedIn(object='person_2', place='place_2'), facts.LocatedIn(object='person_3', place='place_3'), facts.LocatedIn(object='person_4', place='place_4'), facts.LocatedIn(object='person_5', place='place_5'), facts.LocatedIn(object='person_6', place='place_6'), facts.LocatedIn(object='person_7', place='place_7'), facts.LocatedIn(object='person_8', place='place_8'), facts.LocatedIn(object='person_9', place='place_9'), facts.LocatedIn(object='person_10', place='place_10'), facts.LocatedIn(object='hero', place='place_1'), # герой находится в place_1 facts.Mob(uid='mob_1', terrains=(0,)), # есть монстр, обитающий на территориях с идентификатором 0 (для задания на охоту) facts.PreferenceMob(object='hero', mob='mob_1'), # герой любит охотиться на монстра mob_1 facts.PreferenceHometown(object='hero', place='place_2'), # герой считате родным место place_2 facts.PreferenceFriend(object='hero', person='person_4'), # герой дружит с person_4 facts.PreferenceEnemy(object='hero', person='person_5'), # герой враждует с person_5 # указываем, что обновление экипировки стоит 777 монет (для задания SearchSmith) # facts.HasMoney(object='hero', money=888), # если этот факт раскоментировать то в этом задании герой купит экипировку, а не пойдёт делать задание кузнеца facts.UpgradeEquipmentCost(money=777), facts.OnlyGoodBranches(object='place_2'), # не вредить месту place_2 facts.OnlyGoodBranches(object='person_4'), # не вредить персонажу person_4 facts.OnlyBadBranches(object='person_5') ] # не помогать персонажу person_5 kb.validate_consistency(WORLD_RESTRICTIONS) # проверяем ограничения на мир, selector = Selector(kb, qb) # создаём квест (получаем список фактов) quests_facts = selector.create_quest_from_place(nesting=0, initiator_position=kb['place_1'], tags=('can_start', )) kb += quests_facts transformators.activate_events(kb) # активируем события (из нескольких вершин графа оставляем одну, остальные удаляем) transformators.remove_restricted_states(kb) # удаляем состояния, в которые нельзя переходить (например, которые вредят тому, кому вредить нельщя) transformators.remove_broken_states(kb) # чистим граф задания от разрушений, вызванных предыдущими действиями transformators.determine_default_choices(kb) # определяем выборы по умолчанию на развилках kb.validate_consistency(WORLD_RESTRICTIONS) # ещё раз проверяем мир kb.validate_consistency(QUEST_RESTRICTIONS) # проверяем граф задания (вдруг полностью разрушен) return kb