Skip to content

Commit e4c6812

Browse files
committed
Some updates on Traceable controling process, removed redundant element of proposition.activate, etc.
1 parent acf2275 commit e4c6812

4 files changed

Lines changed: 81 additions & 58 deletions

File tree

textworld/challenges/spaceship/content_check_game.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ def make_game(settings: Mapping[str, str], options: Optional[GameOptions] = None
129129

130130
from textworld.challenges.spaceship.maker import test_commands
131131
test_commands(gm, [
132+
'open Blue box',
132133
'open Red box',
134+
'look',
133135
'close Red box',
134136
# 'open Red box',
135137
# 'open Blue box',
@@ -179,7 +181,8 @@ def quest_design(game):
179181
game._entities['r_0'],
180182
game._entities['s_0'],
181183
game._entities['c_0'],
182-
game._entities['cpu_0'])})
184+
game._entities['cpu_0'])},
185+
output_verb_tense_postcond={'closed': 'has been'})
183186
quests.append(Quest(win_events=[win_quest], fail_events=[], reward=1))
184187

185188
# win_quest1 = EventCondition(conditions={game.new_fact("has_been__closed", game._entities['c_0'])})

textworld/generator/game.py

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -104,26 +104,23 @@ def set_events(self):
104104
@classmethod
105105
def add_propositions(cls, props: Iterable[Proposition]) -> Iterable[Proposition]:
106106
for prop in props:
107-
if not prop.name.startswith("is__"):
108-
prop.activate[0] = True
109-
110-
if prop.verb == "has been":
111-
prop.activate[1] = 1
107+
if not prop.name.startswith("is__") and (prop.verb == "has been"):
108+
prop.activate = 1
112109

113110
return props
114111

115112
@classmethod
116113
def set_activated(cls, prop: Proposition):
117-
if prop.activate[0] and not prop.activate[1]:
118-
prop.activate[1] = 1
114+
if not prop.activate:
115+
prop.activate = 1
119116

120117
@classmethod
121118
def remove(cls, prop: Proposition, state: State):
122-
if prop.name.startswith('is__'):
119+
if not prop.name.startswith('was__'):
123120
return
124121

125-
if (prop.activate[0] and prop.activate[1]) and (prop in state.get_facts()):
126-
if Proposition(prop.definition, prop.arguments) not in state.get_facts():
122+
if prop.activate and (prop in state.facts):
123+
if Proposition(prop.definition, prop.arguments) not in state.facts:
127124
state.remove_fact(prop)
128125

129126

@@ -185,6 +182,11 @@ def set_conditions(self, conditions: Iterable[Proposition]) -> Action:
185182
event = PropositionControl(conditions, self.verb_tense)
186183
traceable = event.traceable_propositions
187184
condition = Action("trigger", preconditions=conditions, postconditions=list(conditions) + [event.addon])
185+
186+
# The corresponding traceable(s) should be active in state set to be considered for the event.
187+
if condition.has_traceable():
188+
condition.activate_traceable()
189+
188190
return condition, traceable
189191

190192
def __hash__(self) -> int:
@@ -946,6 +948,15 @@ def _find_shorter_policy(policy):
946948

947949
return compressed
948950

951+
def will_trigger(self, state: State, action: Action):
952+
if isinstance(self.event, EventCondition):
953+
triggered = self.event.is_triggering(state)
954+
955+
if isinstance(self.event, EventAction):
956+
triggered = self.event.is_triggering(action)
957+
958+
return triggered
959+
949960

950961
class QuestProgression:
951962
""" QuestProgression keeps track of the completion of a quest.
@@ -1048,20 +1059,7 @@ def __init__(self, game: Game, track_quests: bool = True) -> None:
10481059
def valid_actions_gen(self):
10491060
potential_actions = list(self.state.all_applicable_actions(self.game.kb.rules.values(),
10501061
self.game.kb.types.constants_mapping))
1051-
a = []
1052-
for act in potential_actions:
1053-
k = []
1054-
for prop in [list(act.preconditions) + list(act.added)][0]:
1055-
if not prop.name.startswith('is__'):
1056-
w = [p for p in self.state.get_facts() if not p.name.startswith('is__') and (p.name == prop.name)][0]
1057-
k.append(w.activate[0] and (w.activate[1] == 1))
1058-
else:
1059-
k.append(prop.activate[0] and (prop.activate[1] == 1))
1060-
1061-
if all(k):
1062-
a.append(act)
1063-
1064-
return a
1062+
return [act for act in potential_actions if act.is_valid()]
10651063

10661064
@property
10671065
def done(self) -> bool:
@@ -1126,14 +1124,19 @@ def winning_policy(self) -> Optional[List[Action]]:
11261124
# Discard all "trigger" actions.
11271125
return tuple(a for a in master_quest_tree.flatten() if a.name != "trigger")
11281126

1129-
def add_traceables(self):
1127+
def add_traceables(self, action):
1128+
s = self.state.facts
11301129
for quest_progression in self.quest_progressions:
1131-
if quest_progression.quest.reward >= 0:
1130+
if not quest_progression.completed and (quest_progression.quest.reward >= 0):
11321131
for win_event in quest_progression.win_events:
1133-
if win_event.event.traceable:
1134-
self.state.add_facts(PropositionControl.add_propositions(win_event.event.traceable))
1132+
if win_event.event.traceable and not (win_event.event.traceable in s):
1133+
if win_event.will_trigger(self.state, action):
1134+
self.state.add_facts(PropositionControl.add_propositions(win_event.event.traceable))
11351135

11361136
def traceable_manager(self):
1137+
if not self.state.has_traceable():
1138+
return
1139+
11371140
for prop in self.state.get_facts():
11381141
if not prop.name.startswith('is__'):
11391142
PropositionControl.set_activated(prop)
@@ -1145,9 +1148,9 @@ def update(self, action: Action) -> None:
11451148
Args:
11461149
action: Action affecting the state of the game.
11471150
"""
1148-
# Update world facts.
1149-
self.state.apply(self.state.state_action_valisate(action))
1150-
self.add_traceables()
1151+
# Update world facts
1152+
self.state.apply(action)
1153+
self.add_traceables(action)
11511154

11521155
# Update all quest progressions given the last action and new state.
11531156
for quest_progression in self.quest_progressions:

textworld/generator/maker.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -687,14 +687,7 @@ def new_fact(self, name: str, *entities: List["WorldEntity"]) -> Proposition:
687687
*entities: A list of entities as arguments to the new fact.
688688
"""
689689
args = [entity.var for entity in entities]
690-
# if name.count('__') == 0:
691-
# verb = 'is'
692-
# definition = name
693-
# name = verb + '__' + definition
694-
# else:
695-
# verb = name[:name.find('__')].replace('_', ' ')
696-
# definition = name[name.find('__')+2:]
697-
# return Proposition(name, arguments=args, verb=verb, definition=definition)
690+
698691
return Proposition(name, args)
699692

700693
def new_rule_fact(self, name: str, *entities: List["WorldEntity"]) -> Union[None, Action]:
@@ -719,7 +712,12 @@ def new_conditions(conditions, args):
719712
precond = new_conditions(rule.preconditions, args)
720713
postcond = new_conditions(rule.postconditions, args)
721714

722-
return Action(rule.name, precond, postcond)
715+
action = Action(rule.name, precond, postcond)
716+
717+
if action.has_traceable():
718+
action.activate_traceable()
719+
720+
return action
723721

724722
return None
725723

textworld/logic/__init__.py

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,8 @@ class Proposition:
619619

620620
__slots__ = ("name", "arguments", "signature", "_hash", "verb", "definition", "activate")
621621

622-
def __init__(self, name: str, arguments: Iterable[Variable] = [], verb: str = None, definition: str = None):
622+
def __init__(self, name: str, arguments: Iterable[Variable] = [], verb: str = None, definition: str = None,
623+
activate: int = 0):
623624
"""
624625
Create a Proposition.
625626
@@ -650,9 +651,9 @@ def __init__(self, name: str, arguments: Iterable[Variable] = [], verb: str = No
650651
self._hash = hash((self.name, self.arguments, self.verb, self.definition))
651652

652653
if self.verb == 'is':
653-
self.activate = [True, 1]
654-
else:
655-
self.activate = [False, 0]
654+
activate = 1
655+
656+
self.activate = activate
656657

657658
@property
658659
def names(self) -> Collection[str]:
@@ -676,7 +677,8 @@ def __repr__(self):
676677

677678
def __eq__(self, other):
678679
if isinstance(other, Proposition):
679-
return (self.name, self.arguments, self.verb, self.definition) == (other.name, other.arguments, other.verb, other.definition)
680+
return (self.name, self.arguments, self.verb, self.definition, self.activate) == \
681+
(other.name, other.arguments, other.verb, other.definition, other.activate)
680682
else:
681683
return NotImplemented
682684

@@ -706,7 +708,8 @@ def serialize(self) -> Mapping:
706708
"name": self.name,
707709
"arguments": [var.serialize() for var in self.arguments],
708710
"verb": self.verb,
709-
"definition": self.definition
711+
"definition": self.definition,
712+
"activate": self.activate
710713
}
711714

712715
@classmethod
@@ -715,7 +718,8 @@ def deserialize(cls, data: Mapping) -> "Proposition":
715718
args = [Variable.deserialize(arg) for arg in data["arguments"]]
716719
verb = data["verb"]
717720
definition = data["definition"]
718-
return cls(name, args, verb, definition)
721+
activate = data["activate"]
722+
return cls(name, args, verb, definition, activate)
719723

720724

721725
@total_ordering
@@ -1090,6 +1094,20 @@ def inverse(self, name=None) -> "Action":
10901094
name = self.name
10911095
return Action(name, self.postconditions, self.preconditions)
10921096

1097+
def has_traceable(self):
1098+
for prop in self.all_propositions:
1099+
if not prop.name.startswith('is__'):
1100+
return True
1101+
return False
1102+
1103+
def activate_traceable(self):
1104+
for prop in self.all_propositions:
1105+
if not prop.name.startswith('is__'):
1106+
prop.activate = 1
1107+
1108+
def is_valid(self):
1109+
return all([prop.activate == 1 for prop in self.all_propositions])
1110+
10931111

10941112
class Rule:
10951113
"""
@@ -1208,7 +1226,10 @@ def instantiate(self, mapping: Mapping[Placeholder, Variable]) -> Action:
12081226
"""
12091227
pre_inst = [pred.instantiate(mapping) for pred in self.preconditions]
12101228
post_inst = [pred.instantiate(mapping) for pred in self.postconditions]
1211-
return Action(self.name, pre_inst, post_inst)
1229+
action = Action(self.name, pre_inst, post_inst)
1230+
if action.has_traceable():
1231+
action.activate_traceable()
1232+
return action
12121233

12131234
def match(self, action: Action) -> Optional[Mapping[Placeholder, Variable]]:
12141235
"""
@@ -1600,7 +1621,7 @@ def are_facts(self, props: Iterable[Proposition]) -> bool:
16001621
if not self.is_fact(prop):
16011622
return False
16021623

1603-
if not prop.activate[0] or not (prop.activate[1]):
1624+
if not prop.activate:
16041625
return False
16051626

16061627
return True
@@ -1671,14 +1692,6 @@ def is_sequence_applicable(self, actions: Iterable[Action]) -> bool:
16711692

16721693
return True
16731694

1674-
def state_action_valisate(self, action: Action):
1675-
for prop in action.all_propositions:
1676-
if not prop.name.startswith('is__'):
1677-
w = [p for p in self.get_facts() if not p.name.startswith('is__') and (p.name == prop.name)][0]
1678-
prop.activate[0], prop.activate[1] = w.activate[0], w.activate[1]
1679-
1680-
return action
1681-
16821695
def apply(self, action: Action) -> bool:
16831696
"""
16841697
Apply an action to the state.
@@ -1964,3 +1977,9 @@ def get_facts(self):
19641977
for fact in sorted(facts):
19651978
all_facts.append(fact)
19661979
return all_facts
1980+
1981+
def has_traceable(self):
1982+
for prop in self.facts:
1983+
if not prop.name.startswith('is__'):
1984+
return True
1985+
return False

0 commit comments

Comments
 (0)