Skip to content

osrforge.tracing.score

The scorer: how far a trace is from its answer key, one family of numbers at a time.

score_trace lines each panel of the trace up with the key at the whole-cell offset that fits best, then reports the families below. It scores the trace as repaired and, when the trace has a before_repair, the trace before repair, and each of those twice: over every cell, and without the cells the key marks as partly floor.

The rules are in docs/tracing-conventions.md under "The scorer".

ALIGNMENT_SEARCH = 3

How far, in cells, the alignment looks for each panel's best offset in each direction.

FAMILIES module-attribute

FAMILIES: tuple[str, ...] = (
    "floor",
    "areas",
    "keys",
    "joins",
    "doors",
    "edges",
    "reachability",
    "entrance",
    "transitions",
    "passages",
    "halves",
    "verdicts",
    "repairs",
)

The family names, in the order ScoreSet lists them.

AreaOverlap

Bases: BaseModel

One key's area in the key and in the trace.

dungeon instance-attribute

dungeon: str

level instance-attribute

level: int

key instance-attribute

key: str

key_cells class-attribute instance-attribute

key_cells: int = Field(ge=0)

trace_cells class-attribute instance-attribute

trace_cells: int = Field(ge=0)

0 when the trace has no area with this key on this level.

both class-attribute instance-attribute

both: int = Field(ge=0)

overlap property

overlap: float | None

both over the union.

AreasScore

Bases: BaseModel

Each area's cell overlap.

areas class-attribute instance-attribute

areas: tuple[AreaOverlap, ...] = ()

One entry per area of the key, in key order.

extra class-attribute instance-attribute

extra: tuple[str, ...] = ()

Areas the trace has and the key lacks, as dungeon/level/key.

mean_overlap property

mean_overlap: float | None

The mean of the areas' overlaps, or None with no areas.

perfect property

perfect: bool

True when every area covers the same cells in both and the trace has no extra area.

DoorTally

Bases: BaseModel

Precision and recall for one door kind.

key class-attribute instance-attribute

key: int = Field(ge=0)

Doors of this kind in the key.

trace class-attribute instance-attribute

trace: int = Field(ge=0)

Doors of this kind in the trace.

matched class-attribute instance-attribute

matched: int = Field(ge=0)

Edges that are this kind in both.

precision property

precision: float | None

The share of the trace's doors the key has.

recall property

recall: float | None

The share of the key's doors the trace has.

perfect property

perfect: bool

True when the two sets are the same edges.

DoorsScore

Bases: BaseModel

Doors by kind: plain, locked, and secret.

door instance-attribute

door: DoorTally

locked instance-attribute

locked: DoorTally

secret instance-attribute

secret: DoorTally

perfect property

perfect: bool

True when every kind is perfect.

EdgeTally

Bases: BaseModel

Passable or blocked, over a set of edges.

total class-attribute instance-attribute

total: int = Field(ge=0)

Edges in the key's universe: edges that touch floor or water.

right class-attribute instance-attribute

right: int = Field(ge=0)

Edges the trace reads as passable or blocked the way the key does.

walls_read_as_open class-attribute instance-attribute

walls_read_as_open: int = Field(ge=0)

Edges blocked in the key and passable in the trace.

open_read_as_blocked class-attribute instance-attribute

open_read_as_blocked: int = Field(ge=0)

Edges passable in the key and blocked in the trace.

accuracy property

accuracy: float | None

right over total.

perfect property

perfect: bool

True when every edge is read the way the key reads it.

EdgesScore

Bases: BaseModel

Passable or blocked, with cave edges apart from straight walls.

all instance-attribute

all: EdgeTally

straight instance-attribute

straight: EdgeTally

cave instance-attribute

cave: EdgeTally

Edges with a cave cell on either side.

perfect property

perfect: bool

True when every edge is right.

FloorScore

Bases: BaseModel

How much of the floor the trace and the key agree on: the . cells of the panels, after alignment.

key_cells class-attribute instance-attribute

key_cells: int = Field(ge=0)

Floor cells in the key.

trace_cells class-attribute instance-attribute

trace_cells: int = Field(ge=0)

Floor cells in the trace, after alignment.

both class-attribute instance-attribute

both: int = Field(ge=0)

Cells that are floor in both.

overlap property

overlap: float | None

both over the union, or None when neither has floor.

perfect property

perfect: bool

True when the two floors are the same cells.

HalvesScore

Bases: BaseModel

Whether each pair of halves was joined at the key's offset, or left apart as the key says.

total class-attribute instance-attribute

total: int = Field(ge=0)

right class-attribute instance-attribute

right: int = Field(ge=0)

perfect property

perfect: bool

True when every pair is right.

JoinsScore

Bases: BaseModel

Whether the areas adjoin the same way.

Two areas of one level adjoin when a passable edge or a door joins a cell of one to a cell of the other.

key_joins class-attribute instance-attribute

key_joins: int = Field(ge=0)

matched class-attribute instance-attribute

matched: int = Field(ge=0)

Joins in both.

missing class-attribute instance-attribute

missing: tuple[str, ...] = ()

Joins in the key the trace lacks, as dungeon/level/key~key.

extra class-attribute instance-attribute

extra: tuple[str, ...] = ()

Joins in the trace the key lacks.

perfect property

perfect: bool

True with nothing missing and nothing extra.

KeysScore

Bases: BaseModel

Whether each printed key landed in the right area.

A key is right when the trace's placed cell for it lies in the key's area of the same name, and the key's placed cell lies in the trace's area of that name.

total class-attribute instance-attribute

total: int = Field(ge=0)

right class-attribute instance-attribute

right: int = Field(ge=0)

wrong class-attribute instance-attribute

wrong: tuple[str, ...] = ()

The keys that landed wrong, as dungeon/level/label.

perfect property

perfect: bool

True when every key landed right.

PlacementScore

Bases: BaseModel

Whether each entrance, transition, or passage stands where the key puts it, leading where the key says.

total class-attribute instance-attribute

total: int = Field(ge=0)

Items in the key.

right class-attribute instance-attribute

right: int = Field(ge=0)

Items the trace has on the same cell with the same kind, side, and destination.

extra class-attribute instance-attribute

extra: int = Field(ge=0)

Items in the trace that match nothing in the key.

wrong class-attribute instance-attribute

wrong: tuple[str, ...] = ()

The key's items the trace lacks, as dungeon/level/cell.

perfect property

perfect: bool

True when the two sets are the same.

ReachabilityScore

Bases: BaseModel

Per dungeon, whether the same areas are reachable from the entrance.

The walk crosses passable edges, doors of every kind, transitions, and passages. A dungeon is right when the trace reaches the areas the key reaches and no others.

total class-attribute instance-attribute

total: int = Field(ge=0)

right class-attribute instance-attribute

right: int = Field(ge=0)

wrong class-attribute instance-attribute

wrong: tuple[str, ...] = ()

The dungeons that differ, with what differs, as dungeon: ....

perfect property

perfect: bool

True when every dungeon is right.

RepairsScore

Bases: BaseModel

What the trace repaired, and whether each repaired edge ended up as the key reads it.

per_level class-attribute instance-attribute

per_level: dict[str, int] = {}

Repairs per level, keyed dungeon/level, for levels with at least one.

edges class-attribute instance-attribute

edges: int = Field(ge=0)

Edges the repairs changed.

edges_matching class-attribute instance-attribute

edges_matching: int = Field(ge=0)

Changed edges whose final reading matches the key.

perfect property

perfect: bool

True when every repaired edge matches the key.

ScoreSet

Bases: BaseModel

Every family, for one way of scoring.

floor instance-attribute

floor: FloorScore

areas instance-attribute

areas: AreasScore

keys instance-attribute

keys: KeysScore

joins instance-attribute

joins: JoinsScore

doors instance-attribute

doors: DoorsScore

edges instance-attribute

edges: EdgesScore

reachability instance-attribute

reachability: ReachabilityScore

entrance instance-attribute

entrance: PlacementScore

transitions instance-attribute

transitions: PlacementScore

passages instance-attribute

passages: PlacementScore

halves instance-attribute

halves: HalvesScore

verdicts instance-attribute

verdicts: VerdictsScore

repairs instance-attribute

repairs: RepairsScore

imperfect_families

imperfect_families() -> tuple[str, ...]

The families that aren't perfect, in FAMILIES order.

Returns:

Type Description
tuple[str, ...]

The names. Empty when the trace matches the key in every family.

TraceScore

Bases: BaseModel

A trace scored against its key.

after instance-attribute

after: ScoreSet

The trace as repaired, over every cell.

after_whole instance-attribute

after_whole: ScoreSet

The trace as repaired, without the cells the key marks as partly floor and the edges that touch them.

before class-attribute instance-attribute

before: ScoreSet | None = None

The trace before repair, over every cell, or None when the trace has no before_repair.

before_whole class-attribute instance-attribute

before_whole: ScoreSet | None = None

The trace before repair, without the partly-floor cells.

VerdictsScore

Bases: BaseModel

Whether refusals, registration failures, and fallbacks are right.

A region is right when its verdict, style, scale, north, and legend page match the key's. A level is right when its verdict matches.

regions class-attribute instance-attribute

regions: int = Field(ge=0)

regions_right class-attribute instance-attribute

regions_right: int = Field(ge=0)

levels class-attribute instance-attribute

levels: int = Field(ge=0)

levels_right class-attribute instance-attribute

levels_right: int = Field(ge=0)

wrong class-attribute instance-attribute

wrong: tuple[str, ...] = ()

The regions and levels that differ, with what differs.

perfect property

perfect: bool

True when every region and level is right.

score_trace

score_trace(trace: GeometryTruth, key: GeometryTruth) -> TraceScore

Score a trace against its answer key.

A 5-foot panel in either document is converted with convert_five_foot before anything is compared. Panels are matched by id. Each panel of the trace is then lined up with the key's panel of the same id at the whole-cell offset (dx, dy) within ALIGNMENT_SEARCH cells that makes the most floor cells agree, ties going to the smallest |dx| + |dy|, then the smallest dy, then the smallest dx. A panel with no partner of the same id is left out of the reading families, and the halves family reports the difference.

The floor, edges, and doors families compare the panels: the reading, with the trace's panels as repaired and before_repair's as read. A panel used only by a level that fell back in either document is left out of them. The areas, keys, joins, reachability, entrance, transitions, passages, and repairs families compare the levels: the resolution. A level cell is mapped through the panel it lies on: back to that panel's page coordinates by undoing the trace's panel origin and turn, across by the panel's offset, and onto the key's level by the key's panel turn and origin. A destination cell is mapped the same way through its target level's panels, and when the target level fell back in either document the destination compares by level number alone. A level that fell back in either document scores in the verdicts family only. The whole-cell scores leave the partly-floor cells and their edges out of the floor, edges, and doors families and change nothing else. The rules are in docs/tracing-conventions.md under "The scorer".

Parameters:

Name Type Description Default
trace GeometryTruth

The trace.

required
key GeometryTruth

The answer key, or a synthetic map's answer.

required

Returns:

Type Description
TraceScore

The score.