def test_iots_traces(self): """ 测试标记迁移系统 s0 -?act0-> s1, s0 -!act1> s2, s1 -act2-> s3 是否可以正常变成图对象 """ state0 = State("s0") state1 = State("s1") state2 = State("s2") state3 = State("s3") action0 = Action("act0") action1 = Action("act1") action2 = Action("act2") transition0 = Transition(state0, action0, state1) transition1 = Transition(state0, action1, state2) transition2 = Transition(state1, action2, state3) iots = IOTS(state0, [state0, state1, state2, state3], [action0, action1, action2], [action0], [action1], [transition0, transition1, transition2]) ts_graph = iots_to_graph(iots) traces = iots_traces(ts_graph) print(traces) self.assertEqual(True, True)
def test_lts_print(self): """ 用来验证lts格式化输出时是否正常 :return: """ state_a = State("a") state_b = State("b") state_c = State("c") init_state = state_a states = [state_a, state_b, state_c] act1 = Action("act1") act2 = Action("act2") actions = [act1, act2] hide_actions = [] transitions = [ Transition(state_a, act1, state_b), Transition(state_a, act2, state_c) ] lts = LTS(init_state, states, actions, hide_actions, transitions) print(lts) self.assertEqual(True, True)
def social_actions(self) -> List[Action]: return [ Action( f'Interagisci con {person.description.far if direction else person.description.oneof}', do=(lambda person: lambda character: [ Action(f'Attacca', do=lambda character: character.war_actions(person), event=EventMessages(), time=1, fatigue=0) ] * bool(character.war_actions(person)) + [ Action(f'Dai oggetti', do=lambda character: character.give_actions(person), event=EventMessages(), time=1, fatigue=0) ] * bool(self.give_actions(person) and not direction) + [ Action(f'Indietro', do=lambda character: None, event=EventMessages(), time=0, fatigue=0) ])(person), event=EventMessages(), time=0, fatigue=0) for person, direction in self.place.objects_around( self.visibility, all=False).items() if isinstance(person, Character) and (person is not self) and ( self.war_actions(person) or (self.give_actions(person) and not direction)) ]
def sts_parser(file_name: str) -> STS: """ 根据*.ts文件中描述的输入输出迁移系统,生成对应的STS对象 :param file_name: .ts结尾的文件 :return: STS对象 """ init_s = parse_initial_state(file_name) s = parse_states(file_name) a = parse_actions(file_name) t = parse_transitions(file_name) # 构造所有状态对象 states = [State(name) for name in s] init_state = [s for s in states if s.state_name == init_s][0] in_actions = a[0] out_actions = a[1] hide_actions = a[2] # 输入动作、输出动作、内部动作对象 outs = [Action(name) for name in out_actions] ins = [Action(name) for name in in_actions] hides = [Action(name) for name in hide_actions] # 所有动作的对象 all_actions = outs + ins + hides # 动作名到动作的一个映射 act_map = dict() for act in all_actions: act_map[act.action_name] = act # 状态名到状态对象的一个映射 state_map = dict() for s in states: state_map[s.state_name] = s # 构造所有迁移对象集合 transitions = list() for first_state, act, second_state in t: transitions.append( Transition(state_map[first_state], act_map[act], state_map[second_state])) secure_level = parse_secure_level_with_sts(file_name) return STS(init_state, states, all_actions, ins, outs, transitions, secure_level)
class States: Normal = State(modifier=Modifier(thirst=95 / 1440, hunger=50 / 1440, sleepiness=105 / 1440, fatigue=250 / 1440, bloodlost=-70 / 1440, each_tick=True)) Sleeping = State(ending=Ending('che dorme', 'che dormono', 'che dormono'), can_see=False, can_act=False, modifier=Modifier(thirst=100 / 1440, hunger=50 / 1440, fatigue=-250 / 1440, sleepiness=-400 / 1440, bloodlost=-70 / 1440, each_tick=True)) Unconscious = State(ending=Ending('che ha perso i sensi', 'che ha perso i sensi', 'che ha perso i sensi'), can_act=False, can_see=False, modifier=Modifier(thirst=100 / 1440, hunger=50 / 1440, fatigue=-300 / 1440, sleepiness=-400 / 1440, bloodlost=-70 / 1440, each_tick=True)) Lying = State( ending=Ending('a terra', 'a terra', 'a terra'), actions=[ Action('Alzati', EventMessages(subject='ti alzi', close='{subject} si alza da terra', far='{subject} si alza da terra'), do=lambda char: setattr(char, 'state', States.Normal), time=2, fatigue=0.5) ], defenses=[ Defense( name='Rotola a terra', tags={'arretra'}, chances=15, success_event=EventMessages( subject='riesci a rotolare via', object='{subject} riesce a rotolare di lato', close='{subject} rotola via da {object}', far='vedi {subject} rotolare a terra in lontananza'), fail_event=EventMessages( subject='non riesci a rotolare via', object='{subject} prova a rotolare via ma non ci riesce', close= '{subject} cerca di rotolare via da {object} ma fallisce')) ], modifier=Modifier(thirst=95 / 1440, hunger=50 / 1440, sleepiness=105 / 1440, bloodlost=-70 / 1440, each_tick=True) + Modifier(agility=-30))
def drop_action(self): return Action( f'{self.drop_verb} {self.description.close}'.capitalize(), EventMessages( subject=f'posi a terra {self.description.close}', close=f'{{subject}} posa a terra {self.description.nclose}', far=f'{{subject}} posa a terra qualcosa'), lambda player: player.inventory.drop(self, player))
def actions(self): return [ Action( f'Conta {value[0].description.close.plural}', EventMessages( subject= f'Conti {value[0].description.close.plural} e sono {len(value)}' ), lambda player: 0, 0, 0) for key, value in self.d.items() if len(value) > 2 ]
def picked_actions(self): return [Action( f'Mangia {self.description}', EventMessages( subject=f'mangi {self.description}', close=f'{{subject}} mangia {self.description}', far=f'{{subject}} mangia qualcosa' ), lambda char: setattr(char, 'hunger', char.hunger - self.nutrition) or \ char.inventory.remove(self) )]
def picked_actions(self): return [Action( f'Bevi {self.description}', EventMessages( subject=f'bevi {self.description}', close=f'{{subject}} beve {self.description}', far=f'{{subject}} beve qualcosa' ), lambda char: setattr(char, 'thirst', char.thirst - self.water) or \ setattr(self, 'water', 0) or \ char.inventory.contained.remove(self) )]
def lts_parser(file_name: str) -> LTS: """ 根据*.ts文件中描述的输入输出迁移系统,生成对应的LTS对象 :param file_name: .ts结尾的文件 :return: LTS对象 """ init_s = parse_initial_state(file_name) s = parse_states(file_name) a = parse_actions(file_name) t = parse_transitions(file_name) # 构造所有状态对象 states = [State(name) for name in s] init_state = [s for s in states if s.state_name == init_s][0] actions = a[0] + a[1] hide_actions = a[-1] # 所有可观察动作的对象 acts = [Action(name) for name in actions] hide_acts = [Action(name) for name in hide_actions] # 动作名到动作的一个映射 act_map = dict() for act in (acts + hide_acts): act_map[act.action_name] = act # 状态名到状态对象的一个映射 state_map = dict() for s in states: state_map[s.state_name] = s # 构造所有迁移对象集合 transitions = list() for first_state, act, second_state in t: transitions.append( Transition(state_map[first_state], act_map[act], state_map[second_state])) return LTS(init_state, states, acts, hide_acts, transitions)
def war_actions(self, target) -> List[Action]: return [ Action(name=attack.name.format( target=target.description.oneof).capitalize(), event=EventMessages(), time=1, fatigue=1, do=(lambda attack: lambda char: attack.do(char, target) )(attack)) for attack in self.inventory.attacks + self.place.attacks if target in self.place.objects_around(attack.range) and attack.condition(self, target) ]
def picked_actions(self): return [ Action( f'Cura {self.wound.name} con {self.description.oneof}', EventMessages( subject=f'Curi {self.wound.name}', close= f'{{subject}} cura {self.wound.name} con {self.description.oneof}' ), lambda char: self.wound.unaffect( char) or char.inventory.remove(self), condition=lambda char: self.wound in char.wounds) ]
def test_lts_to_tsgrah(self): """ 测试标记迁移系统 s0 -act0-> s1, s0 -act1> s2, s1 -act2-> s3 是否可以正常变成图对象 """ state0 = State("s0") state1 = State("s1") state2 = State("s2") state3 = State("s3") action0 = Action("act0") action1 = Action("act1") action2 = Action("act2") transition0 = Transition(state0, action0, state1) transition1 = Transition(state0, action1, state2) transition2 = Transition(state1, action2, state3) lts = LTS(state0, [state0, state1, state2, state3], [action0, action1, action2], [transition0, transition1, transition2]) lts_graph = lts_to_graph(lts) self.assertEqual(True, True)
def check_inventory(self, player) -> List[Action]: actions = [] for obj in self.objects.all: player.events.append(Format('hai {obj}', obj=obj.description.close)) for obj in self.objects: actions.append(obj.drop_action) actions.extend(obj.picked_actions) actions.extend(self.objects.actions) if self.left_hand and self.backpack and self.backpack.occupied + self.left_hand.volume <= self.backpack.volume: actions.append( Action( f'Metti {self.left_hand.description.close} nello zaino', EventMessages( subject= f'Metti {self.left_hand.description.close} nello zaino', close= f'{{subject}} mette {self.left_hand.description.close} nello zaino' ), lambda player: self.backpack.objects.add(self.left_hand) or setattr(self, 'left_hand', None))) if self.right_hand and self.backpack and \ self.backpack.occupied + self.right_hand.volume <= self.backpack.volume and \ not self.right_hand.description.grouped: actions.append( Action( f'Metti {self.right_hand.description.close} nello zaino', EventMessages( subject= f'Metti {self.right_hand.description.close} nello zaino', close= f'{{subject}} mette {self.right_hand.description.close} nello zaino' ), lambda player: self.backpack.objects.add( self.right_hand) or setattr(self, 'right_hand', None))) actions.append( Action('Indietro', EventMessages(), lambda player: '', 0, 0)) actions = [a for a in actions if a.condition(player)] return actions
def equip(self, obj): can_left = lambda player: self.occupied - obj.volume + player.inventory.left_hand.volume > self.volume can_right = lambda player: self.occupied - obj.volume + player.inventory.right_hand.volume > self.volume left_action = Action( f'Prendi nella mano sinistra {obj.description.close}', EventMessages( subject=f'prendi nella mano sinistra {obj.description.close}', close=f'{{subject}} afferra in mano {obj.description.close}'), lambda player: actual_equip(player, 'left_hand'), 0, 0, condition=can_left) right_action = Action( f'Prendi nella mano destra {obj.description.close}', EventMessages( subject=f'prendi nella mano destra {obj.description.close}', close=f'{{subject}} afferra in mano {obj.description.close}'), lambda player: actual_equip(player, 'right_hand'), 0, 0, condition=can_right) choose_action = Action( f'Prendi in mano {obj.description.close}', EventMessages(subject='si, ma in che mano?'), lambda p: [left_action, right_action], 0, 0, condition=lambda p: can_left(p) and can_right(p)) def actual_equip(player, hand): if getattr(player.inventory, hand): self.objects.add(getattr(player.inventory, hand)) self.objects.remove(obj) setattr(player.inventory, hand, obj) return [left_action, right_action, choose_action]
def actions(self) -> List[Action]: return self._user_actions + \ [a for exit in self.exits for a in exit.actions] + \ self.contained.actions + \ [Action( (f'{obj.pick_verb} {obj.description.oneof}').capitalize(), EventMessages( subject=f'{obj.pick_verb} {obj.description.oneof}', close=f'{{subject}} prende {obj.description.oneof}', far=f'{{subject}} prende in mano qualcosa', ), (lambda obj: lambda char: char.inventory.pick(obj, char, self.contained))(obj), condition=(lambda obj: lambda char: char.inventory.pick_message(obj))(obj) ) for obj in self.contained if isinstance(obj, Object) and not obj.visible] + \ [a for obj in self.contained for a in getattr(obj, 'ground_actions', []) if isinstance(obj, Object)]
def check_backpack(self, player): actions = [] for obj in self.objects.all: player.events.append( Format('nello zaino hai {obj}', obj=obj.description.close)) for obj in self.objects: actions.append(obj.drop_action) actions.extend(self.equip(obj)) actions.extend(obj.picked_actions) actions.extend(self.objects.actions) if not self.objects: player.events.append('...è vuoto') actions.append( Action('Indietro', EventMessages(), lambda p: None, 0, 0)) actions = [a for a in actions if a.condition(player)] return actions
def give_actions(self, target) -> List[Action]: return [ Action( name=f'Dai {obj.description.oneof}', event=EventMessages( subject=f'Dai {obj.description.oneof} a {{subject}}', object=f'{{subject}} ti da {obj.description.oneof}', close= f'{{subject}} da {obj.description.oneof} a {{object}}', far=f'{{subject}} da qualcosa a {{object}}'), time=1, fatigue=0, target=target, do=(lambda obj: lambda char: char.inventory.remove(obj) and target.inventory.add(obj, target))(obj), condition=( lambda obj: lambda char: char.inventory.pick_message(obj))) for obj in self.inventory.all_objects ]
def actions(self) -> List[Action]: a = Action( time=self.distance, fatigue=self.distance, sound=Sound(event=EventMessages( far='{direction} senti qualcuno che cammina', )), name=f'Vai {self.description}{self.direction.objects_description}', event=EventMessages(), visibility_event=EventMessages( close_to_far='dietro di te vedi ancora {object}', close_to_none='dietro di te non vedi più {object}', far_to_close='arrivi da {object}', far_to_closer= 'ti avvicini verso {object}, che vedi {direction}', far_to_farer='dietro di te vedi ancora {object}', far_to_none='dietro di te non vedi più {object}', none_to_close='come arrivi vedi {object}', none_to_far='ora {direction} vedi {object}'), post_event=EventMessages( subject=f'arrivi {self.direction.description}', close= f'{{subject}} si allontana {self.description} ma la strada curva e riporta da te', close_to_far=f'{{subject}} si allontana {self.description}', close_to_none= f'{{subject}} si allontana {self.description} e scompare dalla tua vista', far='distante, {direction}, vedi {subject} spostarsi', far_to_close= f'{self.inverse.description} da te arriva {{subject}}', far_to_closer= 'ancora distante, {direction} vedi avvicinarsi {subject}', far_to_farer= 'già distante, {direction} vedi allontanarsi {subject}', far_to_none= '{direction} vedi {subject} allontanarsi e scomparire dalla tua vista', none_to_close= f'improvvisamente {{subject}} arriva da te {self.description.inverse}', none_to_far='improvvisamente vedi {subject} {direction}'), do=lambda c: c.move_to(self), condition=lambda c: c.last_exit is not self) b = copy(a) # Same, but with 'Torna verso' instead of 'Vai verso' b.name = f'Torna {self.description}{self.direction.objects_description}' b.condition = lambda c: c.last_exit is self return [a, b]
def raid(self, character) -> List[Action]: for obj in self.objects.all: character.events.append( Format('vedi {obj}', obj=obj.description.close)) return [ Action( (f'{obj.pick_verb} {obj.description.oneof}').capitalize(), EventMessages( subject= f'{obj.pick_verb} {obj.description.oneof} dal cadavere', close= f'{{subject}} prende {obj.description.oneof} dal cadavere', far=f'{{subject}} prende in mano qualcosa dal cadavere', ), (lambda obj: lambda char: char.inventory.pick( obj, char, self.contained))(obj), condition=(lambda obj: lambda char: char.inventory. pick_message(obj))(obj)) for obj in self.objects ]
def _transition_list_iots(trans_list: List) -> IOTS: if not trans_list: return old_init_state = trans_list[0][0] ins = set() outs = set() acts = set() states = set() for s1, act, s2 in trans_list: if act.action_type == ActionEnum.INPUT: ins.add(act.action_name) elif act.action_type == ActionEnum.OUTPUT: outs.add(act.action_name) acts.add(act.action_name) states.add(s1.state_name) states.add(s2.state_name) acts_map = dict() states_map = dict() states = [State(s) for s in list(states)] acts = [Action(a) for a in list(acts)] for s in states: states_map[s.state_name] = s for a in acts: acts_map[a.action_name] = acts new_init_state = states_map[old_init_state.state_name] outs = [acts_map[a] for a in list(outs)] ins = [acts_map[a] for a in list(ins)] transitions = list() for s1, act, s2 in trans_list: t = Transition(states_map[s1.state_name], acts_map[act.action_name], states_map[s2.state_name]) transitions.append(t) return IOTS(new_init_state, states, acts, ins, outs, transitions)
def die(self): self.place.contained.remove(self) self.place.contained.append( Object( self.description, default_state=Ending(*['a terra, cadavere'] * 3), volume=100, visible=True, ground_actions=[ Action( f'Esamina il cadavere di {self.description.nclose}', EventMessages( subject='esamini il cadavere', close= f'{{subject}} esamina il cadavere di {self.description.nclose}', far= f'{{subject}} esamina il cadavere di {self.description.nclose}', ), do=lambda character: self.inventory.raid(character), time=2, ) ])) self.instances.remove(self) return v
class VitalParameters: thirst = lambda: VitalParameter( 'inizi ad avere sete', 'hai molta sete, ti senti più debole', 'stai morendo di sete, ti senti debolissimo', 'non hai più sete', 'hai meno sete di prima', '', EventMessages(subject='muori di sete', close='{subject} muore di sete', far='{subject} crolla a terra'), modifier=lambda p: Modifier(strenght=-.4 * p), wound=Wounds.Nausea) hunger = lambda: VitalParameter( 'inizi ad avere fame', 'hai molta fame, ti senti più debole', 'stai morendo di fame, ti senti debolissimo', 'non hai più fame', 'hai meno fame di prima', '', EventMessages(subject='muori di fame', close='{subject} muore di fame', far='{subject} crolla a terra'), modifier=lambda p: Modifier(strenght=-.4 * p), wound=Wounds.Febbre) sleepiness = lambda: VitalParameter( 'inizi ad avere sonno', 'hai molto sonno', 'stai morendo di sonno', 'non hai più sonno', 'hai meno sonno di prima', '', EventMessages(subject='muori di sonno', close='{subject} muore di sonno', far='{subject} crolla a terra'), modifier=lambda p: Modifier(strenght=-.35 * p, agility=-.35 * p), wound=Wounds.Febbre, action=Action('Mettiti a dormire per terra', event=EventMessages( subject='ti addormenti velocemente', close='{subject} si mette a dormire a terra', far='{subject} si sdraia a terra'), do=lambda char: char.sleep(), condition=lambda char: char.world.hour > 22 or char.world .hour < 4)) fatigue = lambda: VitalParameter( 'inizi a essere stanco', 'sei molto stanco', 'stai morendo di stanchezza', 'non sei più stanco', 'sei meno stanco di prima', '', EventMessages(subject='muori di stanchezza', close='{subject} muore di stanchezza', far='{subject} crolla a terra'), modifier=lambda p: Modifier(strenght=-.35 * p, agility=-.35 * p), action=Action('Riposati qui qualche minuto', time=7, fatigue=-30, event=EventMessages(subject='riposi qualche minuto', close= '{subject} si ferma per riposarsi', far='{subject} si siede brevemente'), do=lambda char: None, condition=lambda char: char.world.hour > 22 or char.world .hour < 4)) bloodlost = lambda: VitalParameter( 'stai perdendo sangue', 'inizi a impallidire da quanto sangue perdi', 'sei praticamente dissanguato', 'senti di essere di nuovo in forze', 'inizi a sentirti meglio', 'non stai più perdendo sangue', EventMessages(subject='muori dissanguato', close='{subject} muore dissanguato', far='{subject} crolla a terra in una pozza di sangue'), modifier=lambda p: Modifier(strenght=-.5 * p)) cold = lambda: VitalParameter( 'inizi ad avere freddo', 'hai molto freddo ora', 'stai gelando', 'non hai più freddo', 'inizi a scaldarti', 'la temperatura sembra aumentare', EventMessages(subject='muori di freddo', close='{subject} muore di freddo', far='{subject} crolla a terra congelato'), wound=Wounds.Ipotermia) hot = lambda: VitalParameter('inizi ad avere caldo', 'hai molto caldo ora', 'stai evaporando', 'non hai più caldo', 'inizi a stare meglio', 'la temperatura sembra diminuire', EventMessages(subject='muori di caldo', close= '{subject} muore di caldo', far='{subject} crolla a terra'), modifier=lambda p: Modifier(thrist=-.4 * p, ), wound=Wounds.HeatStroke)
def actions(self) -> List[Action]: return [ Action('Controlla cosa hai', EventMessages(), self.check_inventory, 0, 0) ] * bool(self.objects)
def picked_actions(self) -> List[Action]: return [ Action(f'Guarda cosa hai dentro {self.description.close}', EventMessages(), self.check_backpack, 0, 0) ]
], "exits": { "Grotta-outer": [ ExitDescription("verso ", "da ", "un uscita"), ExitDescription("verso ", "dal", "la luce") ], "Grotta-inner": [ ExitDescription("verso ", "da ", "un tunnel più buio"), ExitDescription("verso ", "da ", "un tunnel più stretto") ] }, "variants": { "acqua": { "actions": [Action('Bevi', EventMessages( subject='bevi un po\' d\'acqua', close="{subject} beve un po' d'acqua"), lambda player: setattr(player, 'thirst', player.thirst-40), 2.5, 0,) ] } } }, "Montagna-outer": { "chances": 5, "descriptions": [ "in un sentiero di montagna", "in un piccolo sentierino che prosegue per una montagna" ], "exits": { "Grotta-outer": [
#!/usr/bin/env python3 """ 该模块用来构建一些简单的迁移系统对象常量,方便进行测试程序的正确性 """ from core import Action from core import State from core import Transition from ts import IOTS """ SIMPLE_IOTS 表示如下迁移系统: s0->act1?->s1 s1->act2!->s2 s1->act3!->s3 """ s0, s1, s2, s3 = (State(s) for s in ("s0", "s1", "s2", "s3")) act1, act2, act3 = (Action(a) for a in ("act1", "act2", "act3")) states = [s0, s1, s2, s3] actions = [act1, act2, act3] ins = [act1] outs = [act2, act3] transitions = [ Transition(s0, act1, s1), Transition(s1, act2, s2), Transition(s1, act3, s3) ] SIMPLE_IOTS_TEST = IOTS(s0, states, actions, ins, outs, transitions)