# 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 it’s 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)