File size: 1,993 Bytes
67acd34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
from __future__ import annotations

from dataclasses import dataclass
from statistics import mean, median
from typing import Any


ALLOWED_PUZZLES = [
    "bridges",
    "flow_free",
    "galaxies",
    "loopy",
    "pattern",
    "undead",
]
ALLOWED_DIFFICULTIES = ["easy", "medium", "hard"]
SESSION_STATUSES = ["assigned", "ready", "attempted", "solved"]


def normalize_player_name(value: str) -> str:
    parts = value.strip().split()
    return " ".join(parts).lower()


def engine_for_puzzle(puzzle_type: str) -> str:
    return f"{puzzle_type}_ascii"


@dataclass(frozen=True)
class DatasetRow:
    filename: str
    puzzlename: str
    args: str
    problem: str
    solution: str
    difficulty: str
    image_base64: str | None = None

    @classmethod
    def from_payload(cls, payload: dict[str, Any]) -> "DatasetRow":
        return cls(
            filename=str(payload["filename"]),
            puzzlename=str(payload["puzzlename"]),
            args=str(payload.get("args") or ""),
            problem=str(payload["problem"]),
            solution=str(payload["solution"]),
            difficulty=str(payload["difficulty"]),
            image_base64=payload.get("image_base64"),
        )


@dataclass(frozen=True)
class SolveAggregate:
    player_name_norm: str
    puzzle_type: str
    difficulty: str
    solve_count: int
    avg_ms: float
    median_ms: float
    min_ms: int
    max_ms: int

    @classmethod
    def from_rows(
        cls,
        *,
        player_name_norm: str,
        puzzle_type: str,
        difficulty: str,
        elapsed_values: list[int],
    ) -> "SolveAggregate":
        return cls(
            player_name_norm=player_name_norm,
            puzzle_type=puzzle_type,
            difficulty=difficulty,
            solve_count=len(elapsed_values),
            avg_ms=float(mean(elapsed_values)),
            median_ms=float(median(elapsed_values)),
            min_ms=min(elapsed_values),
            max_ms=max(elapsed_values),
        )