feat: enhance lord's decision-making with action probabilities and personality traits
Browse files
src/unpredictable_lord/game_state.py
CHANGED
|
@@ -236,16 +236,11 @@ ACTION_EFFECTS: dict[str, dict[str, int]] = {
|
|
| 236 |
"do_nothing": {},
|
| 237 |
}
|
| 238 |
|
| 239 |
-
#
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
"improve_diplomacy": ["do_nothing", "public_festival"],
|
| 245 |
-
"public_festival": ["do_nothing", "improve_diplomacy"],
|
| 246 |
-
"build_infrastructure": ["do_nothing", "improve_diplomacy"],
|
| 247 |
-
"do_nothing": ["do_nothing"], # Always accept do_nothing
|
| 248 |
-
}
|
| 249 |
|
| 250 |
|
| 251 |
def _calculate_acceptance(state: "GameState", advice: str) -> tuple[bool, str, str]:
|
|
@@ -285,11 +280,36 @@ def _calculate_acceptance(state: "GameState", advice: str) -> tuple[bool, str, s
|
|
| 285 |
f"{ADVICE_DESCRIPTIONS[advice]['name']}."
|
| 286 |
)
|
| 287 |
else:
|
| 288 |
-
# Lord rejects and takes alternative action
|
| 289 |
-
|
| 290 |
-
|
| 291 |
-
if
|
|
|
|
|
|
|
|
|
|
| 292 |
action_taken = "do_nothing"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 293 |
adoption_message = (
|
| 294 |
f"The lord has rejected your advice ({ADVICE_DESCRIPTIONS[advice]['name']}) "
|
| 295 |
f"and instead chose: {ADVICE_DESCRIPTIONS[action_taken]['name']}."
|
|
|
|
| 236 |
"do_nothing": {},
|
| 237 |
}
|
| 238 |
|
| 239 |
+
# All possible actions (derived from ACTION_EFFECTS keys)
|
| 240 |
+
ALL_ACTIONS: list[str] = list(ACTION_EFFECTS.keys())
|
| 241 |
+
|
| 242 |
+
# Probability that lord chooses a preferred action when rejecting advice
|
| 243 |
+
PREFERRED_ACTION_PROBABILITY = 0.7
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 244 |
|
| 245 |
|
| 246 |
def _calculate_acceptance(state: "GameState", advice: str) -> tuple[bool, str, str]:
|
|
|
|
| 280 |
f"{ADVICE_DESCRIPTIONS[advice]['name']}."
|
| 281 |
)
|
| 282 |
else:
|
| 283 |
+
# Lord rejects and takes alternative action based on personality
|
| 284 |
+
# Exclude: the original advice and disliked actions
|
| 285 |
+
excluded_actions = {advice} | set(traits["disliked"])
|
| 286 |
+
available_actions = [a for a in ALL_ACTIONS if a not in excluded_actions]
|
| 287 |
+
|
| 288 |
+
# If no actions available (edge case), fall back to do_nothing
|
| 289 |
+
if not available_actions:
|
| 290 |
action_taken = "do_nothing"
|
| 291 |
+
else:
|
| 292 |
+
# High probability: choose from preferred actions
|
| 293 |
+
# Low probability: choose from other available actions
|
| 294 |
+
preferred_available = [
|
| 295 |
+
a for a in traits["preferred"] if a not in excluded_actions
|
| 296 |
+
]
|
| 297 |
+
|
| 298 |
+
if preferred_available and random.random() < PREFERRED_ACTION_PROBABILITY:
|
| 299 |
+
action_taken = random.choice(preferred_available)
|
| 300 |
+
else:
|
| 301 |
+
# Choose from non-preferred available actions
|
| 302 |
+
non_preferred = [
|
| 303 |
+
a for a in available_actions if a not in traits["preferred"]
|
| 304 |
+
]
|
| 305 |
+
if non_preferred:
|
| 306 |
+
action_taken = random.choice(non_preferred)
|
| 307 |
+
elif preferred_available:
|
| 308 |
+
# All available actions are preferred, pick from preferred
|
| 309 |
+
action_taken = random.choice(preferred_available)
|
| 310 |
+
else:
|
| 311 |
+
action_taken = "do_nothing"
|
| 312 |
+
|
| 313 |
adoption_message = (
|
| 314 |
f"The lord has rejected your advice ({ADVICE_DESCRIPTIONS[advice]['name']}) "
|
| 315 |
f"and instead chose: {ADVICE_DESCRIPTIONS[action_taken]['name']}."
|