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