rustoku_lib/core/solution.rs
1use crate::core::TechniqueFlags;
2
3use super::board::Board;
4
5/// Solved board and its solution path.
6///
7/// Most of the time, users just want to see the solved board, but this struct also
8/// provides the sequence of moves that led to the solution, which can be useful for debugging
9/// or understanding the solving process.
10#[derive(Debug, Clone)]
11pub struct Solution {
12 /// The solved Sudoku board, represented as a 2D array.
13 pub board: Board,
14 /// The sequence of moves (row, col, value) made to reach the solution.
15 pub solve_path: SolvePath,
16}
17
18/// Solve path associated with a solution.
19#[derive(Debug, Clone, Default)]
20pub struct SolvePath {
21 /// The sequence of steps taken to solve the Sudoku puzzle.
22 pub steps: Vec<SolveStep>,
23}
24
25impl SolvePath {
26 pub fn new() -> Self {
27 SolvePath { steps: Vec::new() }
28 }
29}
30
31/// Single step in the solving process.
32#[derive(Debug, Clone)]
33pub enum SolveStep {
34 /// A placement of a single value on the Sudoku board.
35 Placement {
36 /// The row where the value is placed.
37 row: usize,
38 /// The column where the value is placed.
39 col: usize,
40 /// The value being placed in the Sudoku board.
41 value: u8,
42 /// Flags indicating the technique used for this placement.
43 flags: TechniqueFlags,
44 /// Position of this step in the solve sequence (0-indexed).
45 step_number: u32,
46 /// Bitmask of candidate values eliminated by this placement.
47 candidates_eliminated: u32,
48 /// Count of related cells involved in determining this placement.
49 related_cell_count: u8,
50 /// Difficulty metric for this step (0-10): 0=trivial, 10=hardest.
51 difficulty_point: u8,
52 },
53 /// A removal of a candidate value from the Sudoku board.
54 CandidateElimination {
55 /// The row where the candidate is eliminated.
56 row: usize,
57 /// The column where the candidate is eliminated.
58 col: usize,
59 /// The value being eliminated as a candidate.
60 value: u8,
61 /// Flags indicating the technique used for this elimination.
62 flags: TechniqueFlags,
63 /// Position of this step in the solve sequence (0-indexed).
64 step_number: u32,
65 /// Bitmask of other candidate values eliminated along with this one.
66 candidates_eliminated: u32,
67 /// Count of related cells involved in determining this elimination.
68 related_cell_count: u8,
69 /// Difficulty metric for this step (0-10): 0=trivial, 10=hardest.
70 difficulty_point: u8,
71 },
72}
73
74impl SolveStep {
75 /// 4-letter code for the solve step.
76 pub fn code(&self) -> &str {
77 match self {
78 Self::CandidateElimination { .. } => "elim",
79 Self::Placement { .. } => "plac",
80 }
81 }
82
83 /// Returns the step number (position in solve sequence).
84 pub fn step_number(&self) -> u32 {
85 match self {
86 Self::Placement { step_number, .. }
87 | Self::CandidateElimination { step_number, .. } => *step_number,
88 }
89 }
90
91 /// Returns the bitmask of candidates eliminated by this step.
92 pub fn candidates_eliminated(&self) -> u32 {
93 match self {
94 Self::Placement {
95 candidates_eliminated,
96 ..
97 }
98 | Self::CandidateElimination {
99 candidates_eliminated,
100 ..
101 } => *candidates_eliminated,
102 }
103 }
104
105 /// Returns the count of related cells involved in this step.
106 pub fn related_cell_count(&self) -> u8 {
107 match self {
108 Self::Placement {
109 related_cell_count, ..
110 }
111 | Self::CandidateElimination {
112 related_cell_count, ..
113 } => *related_cell_count,
114 }
115 }
116
117 /// Returns the difficulty metric for this step (0-10).
118 pub fn difficulty_point(&self) -> u8 {
119 match self {
120 Self::Placement {
121 difficulty_point, ..
122 }
123 | Self::CandidateElimination {
124 difficulty_point, ..
125 } => *difficulty_point,
126 }
127 }
128}