1
0
Fork 0

refactor logic labels to use matching

This commit is contained in:
Sean Sube 2024-05-19 16:49:02 -05:00
parent 18c56f9cf3
commit 132682f015
Signed by: ssube
GPG Key ID: 3EED7B957D362AF1
6 changed files with 131 additions and 98 deletions

View File

@ -8,13 +8,7 @@ from rule_engine import Rule
from yaml import Loader, load from yaml import Loader, load
from adventure.game_system import FormatPerspective, GameSystem from adventure.game_system import FormatPerspective, GameSystem
from adventure.models.entity import ( from adventure.models.entity import Attributes, World, WorldEntity, dataclass
Attributes,
AttributeValue,
World,
WorldEntity,
dataclass,
)
from adventure.plugins import get_plugin_function from adventure.plugins import get_plugin_function
logger = getLogger(__name__) logger = getLogger(__name__)
@ -24,6 +18,8 @@ logger = getLogger(__name__)
class LogicLabel: class LogicLabel:
backstory: str backstory: str
description: str | None = None description: str | None = None
match: Optional[Attributes] = None
rule: Optional[str] = None
@dataclass @dataclass
@ -39,20 +35,46 @@ class LogicRule:
@dataclass @dataclass
class LogicTable: class LogicTable:
rules: List[LogicRule] rules: List[LogicRule] = Field(default_factory=list)
labels: Dict[str, Dict[AttributeValue, LogicLabel]] = Field(default_factory=dict) labels: List[LogicLabel] = Field(default_factory=list)
LogicTrigger = Callable[[WorldEntity], None] LogicTrigger = Callable[[WorldEntity], None]
TriggerTable = Dict[str, LogicTrigger] TriggerTable = Dict[str, LogicTrigger]
def match_logic(
entity: WorldEntity,
matcher: LogicLabel | LogicRule,
) -> bool:
typed_attributes = {
**entity.attributes,
"type": entity.type,
}
if matcher.rule:
# TODO: pre-compile rules
rule_impl = Rule(matcher.rule)
if not rule_impl.matches(
{
"attributes": typed_attributes,
}
):
logger.debug("logic rule did not match attributes: %s", matcher.rule)
return False
if matcher.match and not (matcher.match.items() <= typed_attributes.items()):
logger.debug("logic did not match attributes: %s", matcher.match)
return False
return True
def update_attributes( def update_attributes(
entity: WorldEntity, entity: WorldEntity,
rules: LogicTable, rules: LogicTable,
triggers: TriggerTable, triggers: TriggerTable,
) -> None: ) -> None:
entity_type = entity.__class__.__name__.lower()
skip_groups = set() skip_groups = set()
for rule in rules.rules: for rule in rules.rules:
@ -61,24 +83,7 @@ def update_attributes(
logger.debug("already ran a rule from group %s, skipping", rule.group) logger.debug("already ran a rule from group %s, skipping", rule.group)
continue continue
typed_attributes = { if not match_logic(entity, rule):
**entity.attributes,
"type": entity_type,
}
if rule.rule:
# TODO: pre-compile rules
rule_impl = Rule(rule.rule)
if not rule_impl.matches(
{
"attributes": typed_attributes,
}
):
logger.debug("logic rule did not match attributes: %s", rule.rule)
continue
if rule.match and not (rule.match.items() <= typed_attributes.items()):
logger.debug("logic did not match attributes: %s", rule.match)
continue continue
logger.info("matched logic: %s", rule.match) logger.info("matched logic: %s", rule.match)
@ -125,9 +130,8 @@ def format_logic(
) -> str: ) -> str:
labels = [] labels = []
for attribute, value in entity.attributes.items(): for label in rules.labels:
if attribute in rules.labels and value in rules.labels[attribute]: if match_logic(entity, label):
label = rules.labels[attribute][value]
if perspective == FormatPerspective.SECOND_PERSON: if perspective == FormatPerspective.SECOND_PERSON:
labels.append(label.backstory) labels.append(label.backstory)
elif perspective == FormatPerspective.THIRD_PERSON and label.description: elif perspective == FormatPerspective.THIRD_PERSON and label.description:

View File

@ -32,8 +32,9 @@ rules:
trigger: [adventure.sim_systems.environment_triggers:cold_room] trigger: [adventure.sim_systems.environment_triggers:cold_room]
labels: labels:
wet: - match:
true: type: actor
backstory: You are soaking wet. wet: true
description: They are soaking wet and dripping water. backstory: You are soaking wet.
description: They are soaking wet and dripping water.
# false intentionally omitted # false intentionally omitted

View File

@ -51,38 +51,53 @@ rules:
thirst: hydrated thirst: hydrated
labels: labels:
edible: - match:
true: type: item
backstory: You are edible. edible: true
description: This item is edible. backstory: You are edible.
false: description: This item is edible.
backstory: You are not edible. - match:
description: This item is not edible. type: item
cooked: edible: false
true: backstory: You are not edible.
backstory: You are cooked. description: This item is not edible.
description: This item is cooked. - match:
false: type: item
backstory: You are raw. cooked: true
description: This item is raw. backstory: You are cooked.
spoiled: description: This item is cooked.
true: - match:
backstory: You are rotten and inedible. type: item
description: This item is rotten and inedible. cooked: false
false: backstory: You are raw.
backstory: You are fresh and edible. description: This item is raw.
description: This item is fresh and edible. - match:
hunger: type: item
full: spoiled: true
backstory: You are have eaten recently and are full. backstory: You are rotten and inedible.
description: ~ description: This item is rotten and inedible.
hungry: - match:
backstory: You are hungry and need to eat. type: actor
description: They look hungry. spoiled: false
thirst: backstory: You are fresh and edible.
hydrated: description: This item is fresh and edible.
backstory: You are hydrated. - match:
description: ~ type: actor
thirsty: hunger: full
backstory: You are thirsty and need to drink. backstory: You are have eaten recently and are full.
description: They look thirsty. description: ~
- match:
type: actor
hunger: hungry
backstory: You are hungry and need to eat.
description: They look hungry.
- match:
type: actor
thirst: hydrated
backstory: You are hydrated.
description: ~
- match:
type: actor
thirst: thirsty
backstory: You are thirsty and need to drink.
description: They look thirsty.

View File

@ -20,13 +20,18 @@ rules:
hygiene: clean hygiene: clean
labels: labels:
hygiene: - match:
clean: type: actor
backstory: You are clean and smell fresh. hygiene: clean
description: They look freshly washed and smell clean. backstory: You are clean and smell fresh.
dirty: description: They look freshly washed and smell clean.
backstory: You are dirty and smell bad. - match:
description: They look dirty and smell bad. type: actor
filthy: hygiene: dirty
backstory: You are filthy and smell terrible. backstory: You are dirty and smell bad.
description: They look filthy and smell terrible. description: They look dirty and smell bad.
- match:
type: actor
hygiene: filthy
backstory: You are filthy and smell terrible.
description: They look filthy and smell terrible.

View File

@ -118,14 +118,19 @@ rules:
mood: happy mood: happy
labels: labels:
mood: - match:
happy: type: actor
backstory: You are feeling happy. mood: happy
description: They look happy. backstory: You are feeling happy.
# neutral intentionally left out description: They look happy.
sad: - match:
backstory: You are feeling sad. type: actor
description: They look sad. mood: sad
angry: backstory: You are feeling sad.
backstory: You are feeling angry. description: They look sad.
description: They look angry. - match:
type: actor
mood: angry
backstory: You are feeling angry.
description: They look angry.
# neutral intentionally omitted

View File

@ -14,10 +14,13 @@ rules:
sleep: tired sleep: tired
labels: labels:
sleep: - match:
rested: type: actor
backstory: You are well-rested. sleep: rested
description: They look well-rested. backstory: You are well-rested.
tired: description: They look well-rested.
backstory: You are tired. - match:
description: They look tired. type: actor
sleep: tired
backstory: You are tired.
description: They look tired.