def get_knowledge_base(hero_info, without_restrictions=False): # pylint: disable=R0912 kb = KnowledgeBase() hero_uid = uids.hero(hero_info.id) kb += facts.Hero(uid=hero_uid, externals={'id': hero_info.id}) setup_places(kb, hero_info) setup_persons(kb, hero_info) setup_preferences(kb, hero_info) setup_social_connections(kb) if not without_restrictions: for person in persons_storage.persons.all(): if person.place.id == hero_info.position_place_id and person.id in hero_info.interfered_persons: kb += facts.NotFirstInitiator(person=uids.person(person.id)) kb.validate_consistency(WORLD_RESTRICTIONS) kb += [ facts.UpgradeEquipmentCost( money=QuestPrototype.upgrade_equipment_cost(hero_info)) ] return kb
def get_knowledge_base(hero_info, without_restrictions=False): # pylint: disable=R0912 kb = KnowledgeBase() hero_uid = uids.hero(hero_info.id) kb += facts.Hero(uid=hero_uid, externals={'id': hero_info.id}) setup_places(kb, hero_info) setup_persons(kb, hero_info) setup_preferences(kb, hero_info) setup_social_connections(kb) if not without_restrictions: for person in persons_storage.persons_storage.filter(state=PERSON_STATE.IN_GAME): if person.place.id == hero_info.position_place_id and person.id in hero_info.interfered_persons: kb += facts.NotFirstInitiator(person=uids.person(person.id)) kb.validate_consistency(WORLD_RESTRICTIONS) kb += [facts.UpgradeEquipmentCost(money=QuestPrototype.upgrade_equipment_cost(hero_info))] return kb
facts.Mob(uid='mob_1', terrains=(0,)), facts.PreferenceMob(object='hero', mob='mob_1'), facts.PreferenceHometown(object='hero', place='place_2'), facts.PreferenceFriend(object='hero', person='person_4'), facts.PreferenceEnemy(object='hero', person='person_5'), facts.UpgradeEquipmentCost(money=777) ] selector = Selector(kb, qb) kb += Quest.construct_from_place(nesting=0, selector=selector, start_place=selector.new_place(candidates=('place_1',))) try: kb.validate_consistency([restrictions.SingleStartStateWithNoEnters(), restrictions.FinishStateExists(), restrictions.AllStatesHasJumps(), restrictions.SingleLocationForObject(), restrictions.ReferencesIntegrity(), restrictions.ConnectedStateJumpGraph(), restrictions.NoCirclesInStateJumpGraph(), # restrictions.MultipleJumpsFromNormalState(), restrictions.ChoicesConsistency(), # restrictions.QuestionsConsistency(), restrictions.FinishResultsConsistency()]) pass except Exception: print 'quesr %s is invalid' % Quest.TYPE raise drawer = Drawer(knowledge_base=kb) drawer.draw('./svgs/%s.svg' % Quest.TYPE)
class KnowledgeBaseTests(unittest.TestCase): def setUp(self): self.kb = KnowledgeBase() self.fact = Fact(uid='fact') self.fact_2 = Fact(uid='fact_2', description='cba') self.kb += [self.fact, self.fact_2] def test_serialize(self): self.assertEqual( self.kb.serialize(), KnowledgeBase.deserialize(self.kb.serialize(), FACTS).serialize()) self.assertEqual( self.kb.serialize(short=True), KnowledgeBase.deserialize(self.kb.serialize(short=True), FACTS).serialize()) self.assertNotEqual( self.kb.serialize(), KnowledgeBase.deserialize(self.kb.serialize(short=True), FACTS).serialize()) def test_contains__for_child(self): self.assertTrue('fact' in self.kb) self.assertFalse('wrong uid' in self.kb) def test_getitem__for_child(self): self.assertEqual(self.kb['fact'].uid, 'fact') self.assertRaises(exceptions.NoFactError, self.kb.__getitem__, 'wrong uid') def test_get__for_child(self): self.assertEqual(self.kb.get('fact').uid, 'fact') self.assertEqual(self.kb.get('wrong uid'), None) def test_delitem__no_item(self): self.assertRaises(exceptions.NoFactError, self.kb.__delitem__, 'wrong_fact') def test_delitem(self): del self.kb['fact'] self.assertFalse('fact' in self.kb) def test_add_fact__list(self): self.kb += [Fact(uid='fact 1'), Fact(uid='fact 2')] self.assertTrue('fact 1' in self.kb) self.assertTrue('fact 2' in self.kb) def test_add_fact__duplicate_fact(self): self.assertRaises(exceptions.DuplicatedFactError, self.kb.__iadd__, self.fact) def test_add_fact__wrong_type(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__iadd__, 'some string') def test_add_fact__wrong_type_for_nested_lists(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__iadd__, [[Fact(uid='some fact')]]) def test_remove_fact__no_fact(self): self.assertRaises(exceptions.NoFactError, self.kb.__isub__, Fact(uid='some fact')) def test_remove_fact__wrong_type(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__isub__, 'some string') def test_remove_fact__wrong_type_for_nested_lists(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__isub__, [[self.fact]]) def test_validate_consistency__success(self): self.kb.validate_consistency([]) self.kb.validate_consistency([restrictions.AlwaysSuccess()]) def test_validate_consistency__error(self): self.assertRaises(restrictions.AlwaysError.Error, self.kb.validate_consistency, [restrictions.AlwaysError()]) def test_uids(self): self.assertEqual(self.kb.uids(), set(self.kb._facts.keys())) def test_facts(self): self.assertEqual(set(fact.uid for fact in self.kb.facts()), set(self.kb._facts.keys())) def test_filter__no_facts(self): self.assertEqual(list(self.kb.filter(Person)), []) def test_filter(self): self.assertEqual(len(list(self.kb.filter(Fact))), 2) person_1 = Person(uid='person_1') person_2 = Person(uid='person_2') place_1 = Place(uid='place_1') self.kb += [person_1, person_2, place_1] self.assertEqual(len(list(self.kb.filter(Fact))), 5) self.assertEqual(set(fact.uid for fact in self.kb.filter(Person)), set([person_1.uid, person_2.uid])) self.assertEqual(set(fact.uid for fact in self.kb.filter(Place)), set([place_1.uid]))
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
facts.UpgradeEquipmentCost(money=777) ] selector = Selector(kb, qb) kb += Quest.construct_from_place( nesting=0, selector=selector, start_place=selector.new_place(candidates=('place_1', ))) try: kb.validate_consistency([ restrictions.SingleStartStateWithNoEnters(), restrictions.FinishStateExists(), restrictions.AllStatesHasJumps(), restrictions.SingleLocationForObject(), restrictions.ReferencesIntegrity(), restrictions.ConnectedStateJumpGraph(), restrictions.NoCirclesInStateJumpGraph(), # restrictions.MultipleJumpsFromNormalState(), restrictions.ChoicesConsistency(), # restrictions.QuestionsConsistency(), restrictions.FinishResultsConsistency() ]) pass except Exception: print('quesr %s is invalid' % Quest.TYPE) raise drawer = Drawer(knowledge_base=kb) drawer.draw('./svgs/%s.svg' % Quest.TYPE)
class QuestsTests(unittest.TestCase): def setUp(self): self.qb = QuestsBase() self.qb += [Simple] self.kb = KnowledgeBase() self.kb += [ facts.Hero(uid='hero'), facts.Place(uid='place_1', terrains=(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), facts.Person(uid='person_2', profession=PROFESSION.BLACKSMITH), facts.Person(uid='person_3', profession=PROFESSION.NONE), 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'), 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'), facts.Mob(uid='mob_1', terrains=(0,)), facts.PreferenceMob(object='hero', mob='mob_1'), facts.PreferenceHometown(object='hero', place='place_2'), facts.PreferenceFriend(object='hero', person='person_4'), facts.PreferenceEnemy(object='hero', person='person_5'), facts.UpgradeEquipmentCost(money=777) ] self.selector = Selector(self.kb, self.qb) def check_quest(self, quest_class): self.kb += quest_class.construct_from_place(nesting=0, selector=self.selector, start_place=self.selector.new_place(candidates=('place_1',))) self.kb.validate_consistency([restrictions.SingleStartStateWithNoEnters(), restrictions.FinishStateExists(), restrictions.AllStatesHasJumps(), restrictions.SingleLocationForObject(), restrictions.ReferencesIntegrity(), restrictions.ConnectedStateJumpGraph(), restrictions.NoCirclesInStateJumpGraph(), # restrictions.MultipleJumpsFromNormalState(), restrictions.ChoicesConsistency(), restrictions.QuestionsConsistency(), restrictions.FinishResultsConsistency(), restrictions.RequirementsConsistency(), restrictions.ActionsConsistency()]) def check_linked_options_has_similar_markers(self, quest_class): self.kb += quest_class.construct_from_place(nesting=0, selector=self.selector, start_place=self.selector.new_place(candidates=('place_1',))) for options_link in self.kb.filter(facts.OptionsLink): makrers = None for option_uid in options_link.options: option = self.kb[option_uid] if makrers is None: makrers = set(option.markers) self.assertEqual(makrers, set(option.markers))
class KnowledgeBaseTests(unittest.TestCase): def setUp(self): self.kb = KnowledgeBase() self.fact = Fact(uid='fact') self.fact_2 = Fact(uid='fact_2', description='cba') self.kb += [ self.fact, self.fact_2 ] def test_serialize(self): self.assertEqual(self.kb.serialize(), KnowledgeBase.deserialize(self.kb.serialize(), FACTS).serialize()) self.assertEqual(self.kb.serialize(short=True), KnowledgeBase.deserialize(self.kb.serialize(short=True), FACTS).serialize()) self.assertNotEqual(self.kb.serialize(), KnowledgeBase.deserialize(self.kb.serialize(short=True), FACTS).serialize()) def test_contains__for_child(self): self.assertTrue('fact' in self.kb) self.assertFalse('wrong uid' in self.kb) def test_getitem__for_child(self): self.assertEqual(self.kb['fact'].uid, 'fact') self.assertRaises(exceptions.NoFactError, self.kb.__getitem__, 'wrong uid') def test_get__for_child(self): self.assertEqual(self.kb.get('fact').uid, 'fact') self.assertEqual(self.kb.get('wrong uid'), None) def test_delitem__no_item(self): self.assertRaises(exceptions.NoFactError, self.kb.__delitem__, 'wrong_fact') def test_delitem(self): del self.kb['fact'] self.assertFalse('fact' in self.kb) def test_add_fact__list(self): self.kb += [Fact(uid='fact 1'), Fact(uid='fact 2')] self.assertTrue('fact 1' in self.kb) self.assertTrue('fact 2' in self.kb) def test_add_fact__duplicate_fact(self): self.assertRaises(exceptions.DuplicatedFactError, self.kb.__iadd__, self.fact) def test_add_fact__wrong_type(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__iadd__, 'some string') def test_add_fact__wrong_type_for_nested_lists(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__iadd__, [[Fact(uid='some fact')]]) def test_remove_fact__no_fact(self): self.assertRaises(exceptions.NoFactError, self.kb.__isub__, Fact(uid='some fact')) def test_remove_fact__wrong_type(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__isub__, 'some string') def test_remove_fact__wrong_type_for_nested_lists(self): self.assertRaises(exceptions.WrongFactTypeError, self.kb.__isub__, [[self.fact]]) def test_validate_consistency__success(self): self.kb.validate_consistency([]) self.kb.validate_consistency([restrictions.AlwaysSuccess()]) def test_validate_consistency__error(self): self.assertRaises(restrictions.AlwaysError.Error, self.kb.validate_consistency, [restrictions.AlwaysError()]) def test_uids(self): self.assertEqual(self.kb.uids(), set(self.kb._facts.keys())) def test_facts(self): self.assertEqual(set(fact.uid for fact in self.kb.facts()), set(self.kb._facts.keys())) def test_filter__no_facts(self): self.assertEqual(list(self.kb.filter(Person)), []) def test_filter(self): self.assertEqual(len(list(self.kb.filter(Fact))), 2) person_1 = Person(uid='person_1') person_2 = Person(uid='person_2') place_1 = Place(uid='place_1') self.kb += [ person_1, person_2, place_1] self.assertEqual(len(list(self.kb.filter(Fact))), 5) self.assertEqual(set(fact.uid for fact in self.kb.filter(Person)), set([person_1.uid, person_2.uid])) self.assertEqual(set(fact.uid for fact in self.kb.filter(Place)), set([place_1.uid]))
class SimpleQuestTests(unittest.TestCase): def setUp(self): self.kb = KnowledgeBase() # world self.kb += [ Place(uid='place_from'), Person(uid='person_from'), Place(uid='place_thought'), Place(uid='place_to'), Person(uid='person_to'), LocatedIn(object='person_from', place='place_from'), LocatedIn(object='person_to', place='place_to')] # quest self.kb += [ Start(uid='start', nesting=0, type='simple_test', require=(requirements.LocatedIn(object='person_from', place='place_from'), requirements.LocatedIn(object='person_to', place='place_to'), requirements.LocatedIn(object='hero', place='place_from'))), State(uid='st_throught_place', require=(requirements.LocatedIn(object='hero', place='place_thought'),)), Finish(uid='st_finish', start='start', results={}, nesting=0, require=(requirements.LocatedIn(object='hero', place='place_to'),)), Jump(state_from='start', state_to='st_throught_place'), Jump(state_from='st_throught_place', state_to='st_finish') ] self.kb += [ Hero(uid='hero') ] self.kb.validate_consistency([restrictions.SingleStartStateWithNoEnters(), restrictions.FinishStateExists(), restrictions.AllStatesHasJumps(), restrictions.SingleLocationForObject(), restrictions.ReferencesIntegrity(), restrictions.ConnectedStateJumpGraph(), restrictions.NoCirclesInStateJumpGraph(), restrictions.MultipleJumpsFromNormalState(), restrictions.ChoicesConsistency()]) self.machine = machine.Machine(knowledge_base=self.kb, interpreter=FakeInterpreter()) def test_initialized(self): pass def test_full_story_forced(self): self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='start')) self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='st_throught_place')) self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='st_throught_place', jump=Jump(state_from='st_throught_place', state_to='st_finish').uid)) self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='st_finish', jump=None)) def test_full_story_real(self): # no move, since hero not in right place self.assertEqual(self.machine.pointer, Pointer(state=None, jump=None) ) def check_located_in_place_from(requirement): return requirement.place == 'place_from' def check_located_in_place_to(requirement): return requirement.place == 'place_to' def check_located_in_place_thought(requirement): return requirement.place == 'place_thought' with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_from)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid) ) with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_from)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) # no move, since hero not in right place with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_from)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_thought)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='st_throught_place', jump=Jump(state_from='st_throught_place', state_to='st_finish').uid)) # no move, since hero not in right place with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_thought)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='st_throught_place', jump=Jump(state_from='st_throught_place', state_to='st_finish').uid)) with mock.patch('questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_to)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='st_finish', jump=None))
class QuestsTests(unittest.TestCase): def setUp(self): self.qb = QuestsBase() self.qb += [Simple] self.kb = KnowledgeBase() self.kb += [ facts.Hero(uid='hero'), facts.Place(uid='place_1', terrains=(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), facts.Person(uid='person_2', profession=PROFESSION.BLACKSMITH), facts.Person(uid='person_3', profession=PROFESSION.NONE), 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'), 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'), facts.Mob(uid='mob_1', terrains=(0, )), facts.PreferenceMob(object='hero', mob='mob_1'), facts.PreferenceHometown(object='hero', place='place_2'), facts.PreferenceFriend(object='hero', person='person_4'), facts.PreferenceEnemy(object='hero', person='person_5'), facts.UpgradeEquipmentCost(money=777) ] self.selector = Selector(self.kb, self.qb) def check_quest(self, quest_class): self.kb += quest_class.construct_from_place( nesting=0, selector=self.selector, start_place=self.selector.new_place(candidates=('place_1', ))) self.kb.validate_consistency([ restrictions.SingleStartStateWithNoEnters(), restrictions.FinishStateExists(), restrictions.AllStatesHasJumps(), restrictions.SingleLocationForObject(), restrictions.ReferencesIntegrity(), restrictions.ConnectedStateJumpGraph(), restrictions.NoCirclesInStateJumpGraph(), # restrictions.MultipleJumpsFromNormalState(), restrictions.ChoicesConsistency(), restrictions.QuestionsConsistency(), restrictions.FinishResultsConsistency(), restrictions.RequirementsConsistency(), restrictions.ActionsConsistency() ]) def check_linked_options_has_similar_markers(self, quest_class): self.kb += quest_class.construct_from_place( nesting=0, selector=self.selector, start_place=self.selector.new_place(candidates=('place_1', ))) for options_link in self.kb.filter(facts.OptionsLink): makrers = None for option_uid in options_link.options: option = self.kb[option_uid] if makrers is None: makrers = set(option.markers) self.assertEqual(makrers, set(option.markers))
class SimpleQuestTests(unittest.TestCase): def setUp(self): self.kb = KnowledgeBase() # world self.kb += [ Place(uid='place_from'), Person(uid='person_from'), Place(uid='place_thought'), Place(uid='place_to'), Person(uid='person_to'), LocatedIn(object='person_from', place='place_from'), LocatedIn(object='person_to', place='place_to') ] # quest self.kb += [ Start(uid='start', nesting=0, type='simple_test', require=(requirements.LocatedIn(object='person_from', place='place_from'), requirements.LocatedIn(object='person_to', place='place_to'), requirements.LocatedIn(object='hero', place='place_from'))), State(uid='st_throught_place', require=(requirements.LocatedIn(object='hero', place='place_thought'), )), Finish(uid='st_finish', start='start', results={}, nesting=0, require=(requirements.LocatedIn(object='hero', place='place_to'), )), Jump(state_from='start', state_to='st_throught_place'), Jump(state_from='st_throught_place', state_to='st_finish') ] self.kb += [Hero(uid='hero')] self.kb.validate_consistency([ restrictions.SingleStartStateWithNoEnters(), restrictions.FinishStateExists(), restrictions.AllStatesHasJumps(), restrictions.SingleLocationForObject(), restrictions.ReferencesIntegrity(), restrictions.ConnectedStateJumpGraph(), restrictions.NoCirclesInStateJumpGraph(), restrictions.MultipleJumpsFromNormalState(), restrictions.ChoicesConsistency() ]) self.machine = machine.Machine(knowledge_base=self.kb, interpreter=FakeInterpreter()) def test_initialized(self): pass def test_full_story_forced(self): self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='start')) self.machine.step() self.assertEqual( self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='st_throught_place')) self.machine.step() self.assertEqual( self.machine.pointer, Pointer(state='st_throught_place', jump=Jump(state_from='st_throught_place', state_to='st_finish').uid)) self.machine.step() self.assertEqual(self.machine.pointer, Pointer(state='st_finish', jump=None)) def test_full_story_real(self): # no move, since hero not in right place self.assertEqual(self.machine.pointer, Pointer(state=None, jump=None)) def check_located_in_place_from(requirement): return requirement.place == 'place_from' def check_located_in_place_to(requirement): return requirement.place == 'place_to' def check_located_in_place_thought(requirement): return requirement.place == 'place_thought' with mock.patch( 'questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_from)): self.machine.step_until_can() self.assertEqual( self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) with mock.patch( 'questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_from)): self.machine.step_until_can() self.assertEqual( self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) # no move, since hero not in right place with mock.patch( 'questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_from)): self.machine.step_until_can() self.assertEqual( self.machine.pointer, Pointer(state='start', jump=Jump(state_from='start', state_to='st_throught_place').uid)) with mock.patch( 'questgen.machine.Machine.interpreter', FakeInterpreter( check_located_in=check_located_in_place_thought)): self.machine.step_until_can() self.assertEqual( self.machine.pointer, Pointer(state='st_throught_place', jump=Jump(state_from='st_throught_place', state_to='st_finish').uid)) # no move, since hero not in right place with mock.patch( 'questgen.machine.Machine.interpreter', FakeInterpreter( check_located_in=check_located_in_place_thought)): self.machine.step_until_can() self.assertEqual( self.machine.pointer, Pointer(state='st_throught_place', jump=Jump(state_from='st_throught_place', state_to='st_finish').uid)) with mock.patch( 'questgen.machine.Machine.interpreter', FakeInterpreter(check_located_in=check_located_in_place_to)): self.machine.step_until_can() self.assertEqual(self.machine.pointer, Pointer(state='st_finish', jump=None))
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