lisudoku_solver/solver/logical_solver/
hidden_set.rs1use std::collections::HashSet;
2use crate::solver::Solver;
3use crate::types::{CellPosition, InvalidStateReason, Rule, SolutionStep};
4use combinations::Combinations;
5use itertools::Itertools;
6use super::technique::Technique;
7
8pub struct HiddenSet {
11 set_size: usize,
12}
13
14impl Technique for HiddenSet {
15 fn get_rule(&self) -> Rule { if self.set_size == 2 { Rule::HiddenPairs } else { Rule::HiddenTriples } }
16
17 fn run(&self, solver: &Solver) -> Vec<SolutionStep> {
18 if !solver.candidates_active {
19 return vec![]
20 }
21
22 let areas = solver.get_all_proper_areas();
23 for area in areas {
24 let value_cells = solver.compute_cells_by_value_in_area(&area, &solver.candidates);
25
26 let area_values: Vec<u32> = solver.compute_area_candidates_union(&area).into_iter().sorted().collect();
27 let value_combinations: Vec<_> = if self.set_size < area_values.len() {
28 Combinations::new(area_values, self.set_size).collect()
29 } else {
30 vec![area_values]
32 };
33
34 for values in value_combinations {
35 let mut combined_cells: HashSet<CellPosition> = HashSet::new();
36 for value in &values {
37 let cells: HashSet<CellPosition> = value_cells[value].iter().copied().collect();
38 combined_cells = combined_cells.union(&cells).cloned().collect();
39 if combined_cells.len() > self.set_size {
40 break
41 }
42 }
43
44 if combined_cells.len() != self.set_size {
45 continue
46 }
47
48 let cells_array: Vec<CellPosition> = combined_cells.into_iter().sorted().collect();
49 let values_set: HashSet<u32> = values.iter().copied().collect();
50 if !solver.any_cells_with_other_candidates(&cells_array, &values_set) {
51 continue
52 }
53
54 return vec![
55 self.build_solution_step(
56 cells_array,
57 values,
58 vec![area],
59 vec![],
60 )
61 ]
62 }
63 }
64
65 vec![]
66 }
67
68 fn apply(&self, step: &SolutionStep, solver: &mut Solver) -> (bool, Option<InvalidStateReason>) {
69 for &CellPosition { row, col } in &step.cells {
70 let value_set: HashSet<u32> = step.values.iter().copied().collect();
71 solver.candidates[row][col] = solver.candidates[row][col].intersection(&value_set).copied().collect();
72 }
73 (true, None)
74 }
75}
76
77impl HiddenSet {
78 pub fn new(set_size: usize) -> HiddenSet {
79 HiddenSet { set_size }
80 }
81}