lisudoku_solver/solver/logical_solver/
technique.rs1use std::collections::HashSet;
2use crate::{solver::Solver, types::{Area, CellPosition, InvalidStateReason, InvalidStateType, Rule, SolutionStep}};
3
4pub trait Technique {
5 fn is_grid_step(&self) -> bool { false }
7
8 fn is_candidate_validity_update_step(&self) -> bool { false }
11
12 fn get_rule(&self) -> Rule;
13
14 fn build_solution_step(
15 &self,
16 cells: Vec<CellPosition>, values: Vec<u32>, areas: Vec<Area>, affected_cells: Vec<CellPosition>
17 ) -> SolutionStep {
18 SolutionStep::new(self.get_rule(), cells, values, areas, affected_cells)
19 }
20
21 fn build_grid_solution_step(
22 &self, cells: Vec<CellPosition>, values: Vec<u32>, areas: Vec<Area>, solver: &Solver,
23 ) -> SolutionStep {
24 assert!(self.is_grid_step());
25 let affected_cells = if solver.candidates_active {
26 assert_eq!(cells.len(), 1);
27 let cell = cells[0];
28 let value = values[0];
29 let values_set = &HashSet::from([value]);
30 solver.get_affected_by_cell(&cell, values_set)
31 } else {
32 vec![]
33 };
34 self.build_solution_step(cells, values, areas, affected_cells)
35 }
36
37 fn build_simple_solution_step(
38 &self,
39 values: Vec<u32>, areas: Vec<Area>, affected_cells: Vec<CellPosition>
40 ) -> SolutionStep {
41 self.build_solution_step(vec![], values, areas, affected_cells)
42 }
43
44 fn run(&self, solver: &Solver) -> Vec<SolutionStep>;
45
46 fn apply(&self, step: &SolutionStep, solver: &mut Solver) -> (bool, Option<InvalidStateReason>) {
48 if self.is_grid_step() {
49 if solver.candidates_active {
50 assert_eq!(step.cells.len(), 1);
51 }
52 let cell = step.cells[0];
53 let CellPosition { row, col } = cell;
54 let value = step.values[0];
55
56 if solver.step_count_limit.is_some() {
57 if solver.grid[row][col] != 0 && solver.grid[row][col] != value {
62 return (false, Some(InvalidStateReason {
63 state_type: InvalidStateType::CellInvalidValue,
64 area: Area::Cell(cell.row, cell.col),
65 values: vec![value],
66 }))
67 }
68 } else {
69 assert_eq!(solver.grid[row][col], 0, "Attempted to overwrite cell");
70 }
71
72 if solver.grid[row][col] == 0 {
73 solver.grid[row][col] = value;
74
75 if solver.candidates_active {
76 solver.candidates[row][col].clear();
77 solver.update_candidates(&step.affected_cells, value);
78 }
79 }
80 } else if self.apply_corresponding_indices() {
81 for (index, cell) in step.affected_cells.iter().enumerate() {
82 let value = step.values[index];
83 solver.candidates[cell.row][cell.col].remove(&value);
84 }
85 } else {
86 for &CellPosition { row, col } in &step.affected_cells {
87 for value in &step.values {
88 solver.candidates[row][col].remove(value);
89 }
90 }
91 }
92
93 (true, None)
94 }
95
96 fn apply_corresponding_indices(&self) -> bool { false }
97}