Skip to main content

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}