feat: Create the Object Generator Oracle

This commit is contained in:
2025-05-21 23:45:16 +02:00
parent d556159f2a
commit 248d7a27af
2 changed files with 279 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
# SPDX-FileCopyrightText: 2025 2025
# SPDX-FileContributor: Gergely Polonkai
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""Object Generator Oracle"""
from typing import Any
from ..dice import Die
from .base import Oracle
class ObjectGeneratorProperty: # pylint: disable=too-few-public-methods
"""Property for the Object Generator Oracle"""
def __init__(self, property_data: dict[str, Any]) -> None:
self.question: str | None = None
self.die: Die | None = None
self.results: dict[int, str] = {}
self.parse_and_validate(property_data)
def parse_and_validate(self, property_data: dict[str, Any]) -> None:
"""Parse and validate property data"""
if "question" not in property_data:
raise ValueError("Missing question value")
self.question = property_data["question"]
if "roll-type" not in property_data:
raise ValueError("Missing roll-type value")
self.die = Die(property_data["roll-type"])
if "results" not in property_data:
raise ValueError("Missing results value")
new_results: dict[int, str | None] = {
roll_value: None for roll_value in range(self.die.minimum, self.die.maximum + 1)
}
for idx, result_data in enumerate(property_data["results"]):
if "min-roll" not in result_data:
raise ValueError(f"Missing min-roll value in result {idx}")
min_roll = int(result_data["min-roll"])
max_roll = int(result_data.get("max-roll", min_roll))
if max_roll < min_roll:
raise ValueError(f"max-roll cannot be smaller than min-roll in result {idx}")
if "value" not in result_data:
raise ValueError(f"Missing value value in result {idx}")
for roll_value in range(min_roll, max_roll + 1):
if new_results[roll_value] is not None:
raise ValueError(f"Roll value {roll_value} is already registered in result {idx}")
new_results[roll_value] = result_data["value"]
if any(value is None for value in new_results.values()):
raise ValueError(f"Not all roll values yield a result for property {self.question}")
# We just checked that every member of new_results is a string, so its safe to ignore type checking here
self.results = new_results # type: ignore[assignment]
def generate(self) -> str:
"""Generate a random value for this property"""
assert self.die
value = self.die.roll()
answer = self.results[value]
return f"""*{self.question}*
{answer}"""
class ObjectGeneratorOracle(Oracle):
"""Oracle that can generate objects"""
TYPE_MARKER = "object-generator"
def __init__(self, oracle_data: dict[str, Any]) -> None:
self.properties: list[ObjectGeneratorProperty] = []
super().__init__(oracle_data)
def parse_and_validate(self, oracle_data: dict[str, Any]) -> None:
super().parse_and_validate(oracle_data)
if "properties" not in oracle_data:
raise KeyError("properties")
self.properties = [ObjectGeneratorProperty(prop_data) for prop_data in oracle_data["properties"]]
def generate(self) -> str:
return "\n\n".join(prop.generate() for prop in self.properties)