Venket / src /analysis /difficulty_analyzer.py
venki101's picture
Add files using upload-large-folder tool
3f820d9 verified
Raw History Blame Contribute Delete
2.52 kB
"""Computes the deterministic difficulty score from post-render geometry metrics.
Pure function of :class:`~src.analysis.geometry_analyzer.GeometryResult` and
the configured weights -- no randomness is involved, so the score is
trivially reproducible given identical geometry inputs.
"""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from src.analysis.geometry_analyzer import GeometryResult
from src.config.schema import DifficultyWeights
from src.utils.geometry_utils import clamp01
@dataclass
class DifficultyResult:
"""The five difficulty components, the weighted score, and its tier."""
misplacement: float
whitespace: float
faintness: float
smallness: float
low_texture: float
score: float
tier: str
class DifficultyAnalyzer:
"""Computes the exact spec-defined difficulty score and tier.
``score = 0.35*misplacement + 0.20*whitespace + 0.20*faintness + 0.15*smallness + 0.10*low_texture``
Example:
>>> analyzer = DifficultyAnalyzer(cfg.difficulty)
>>> result = analyzer.analyze(geometry_result)
"""
def __init__(self, weights: DifficultyWeights) -> None:
self.weights = weights
def analyze(self, geometry: GeometryResult) -> DifficultyResult:
"""Compute the difficulty components, weighted score, and tier for one sample."""
w = self.weights
misplacement = clamp01(1.0 - geometry.polygon_overlap_proxy)
whitespace = clamp01(geometry.whitespace_ratio)
faintness = clamp01((geometry.mean_dark_intensity - 90.0) / 120.0)
smallness = clamp01(1.0 - geometry.signature_area_ratio / 0.04)
low_texture = clamp01(1.0 - geometry.gray_stddev / 60.0)
score = (
w.misplacement * misplacement
+ w.whitespace * whitespace
+ w.faintness * faintness
+ w.smallness * smallness
+ w.low_texture * low_texture
)
score = float(np.clip(score, 0.0, 1.0))
if score < w.easy_threshold:
tier = "easy"
elif score < w.hard_threshold:
tier = "medium"
else:
tier = "hard"
return DifficultyResult(
misplacement=round(misplacement, 4),
whitespace=round(whitespace, 4),
faintness=round(faintness, 4),
smallness=round(smallness, 4),
low_texture=round(low_texture, 4),
score=round(score, 4),
tier=tier,
)