Skip to main content

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}