pencil_puzzles_core/
rating.rs1use std::error::Error;
4use std::fmt;
5
6use crate::{BudgetExceeded, Difficulty};
7
8#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[non_exhaustive]
13pub struct Rating {
14 pub level: Difficulty,
16 pub score: u64,
20 pub techniques: Vec<String>,
22 pub steps: u32,
24 pub rater_version: u32,
26 #[cfg_attr(
29 feature = "serde",
30 serde(default, skip_serializing_if = "Option::is_none")
31 )]
32 pub metrics: Option<Metrics>,
33}
34
35impl Rating {
36 pub fn new(level: Difficulty, rater_version: u32) -> Self {
38 Self {
39 level,
40 score: 0,
41 techniques: Vec::new(),
42 steps: 0,
43 rater_version,
44 metrics: None,
45 }
46 }
47}
48
49#[derive(Clone, Debug, PartialEq, Eq, Hash)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53#[non_exhaustive]
54pub struct Metrics {
55 pub profile: String,
57 pub profile_version: u32,
59 pub available_moves: Vec<u32>,
62 pub productive_choices: Vec<u32>,
64 pub solved_cells: Vec<u32>,
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
70#[non_exhaustive]
71pub enum RateError {
72 NoSolution,
74 MultipleSolutions,
76 BudgetExceeded,
78 Unrated,
80 UnsupportedVersion(u32),
82}
83
84impl fmt::Display for RateError {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 if let Self::UnsupportedVersion(version) = self {
87 return write!(
88 f,
89 "rater version {version} is retired or unsupported; use the current rater version"
90 );
91 }
92 f.write_str(match self {
93 Self::NoSolution => "the puzzle has no solution",
94 Self::MultipleSolutions => "the puzzle has more than one solution",
95 Self::BudgetExceeded => "the work budget ran out before the rating finished",
96 Self::Unrated => "the puzzle is unique but the supported human techniques did not solve it; no difficulty is assigned",
97 Self::UnsupportedVersion(_) => unreachable!(),
98 })
99 }
100}
101
102impl Error for RateError {}
103
104impl From<BudgetExceeded> for RateError {
105 fn from(_: BudgetExceeded) -> Self {
106 Self::BudgetExceeded
107 }
108}