lisudoku_solver/solver/logical_solver/
arrow_advanced_candidates.rs

1use crate::solver::Solver;
2use crate::solver::logical_solver::combinations::cell_combinations_runner::CellCombinationsRunner;
3use crate::types::{SolutionStep, Rule, Area};
4use super::technique::Technique;
5
6// Eliminate arrow combinations that remove all candidates from 1 cell
7pub struct ArrowAdvancedCandidates;
8
9impl Technique for ArrowAdvancedCandidates {
10  fn is_candidate_validity_update_step(&self) -> bool { true }
11  fn get_rule(&self) -> Rule { Rule::ArrowAdvancedCandidates }
12
13  fn run(&self, solver: &Solver) -> Vec<SolutionStep> {
14    if !solver.candidates_active {
15      return vec![]
16    }
17
18    solver.constraints.arrows.iter().enumerate().flat_map(|(arrow_index, arrow)| {
19      let cells = arrow.all_cells();
20
21      // Running the algorithm for really long arrows will take too much time, so
22      // wait for better opportunities
23      if solver.count_empty_cells_in_list(&cells) > 8 {
24        return vec![]
25      }
26
27      let mut arrow_combinatons_logic_factory = solver.arrow_combinatons_logic_factory.borrow_mut();
28      let combination_logic = arrow_combinatons_logic_factory.create(arrow, solver);
29      let mut runner = CellCombinationsRunner::new(solver, Box::new(combination_logic));
30      let (_, combinations) = runner.run();
31
32      let invalid_candidates = solver.eliminate_combinations(&combinations, &cells);
33
34      // TODO: may eliminate same candidate twice?
35      invalid_candidates.into_iter().map(|(cell, invalid_values)| {
36        self.build_simple_solution_step(
37          invalid_values,
38          vec![ Area::Arrow(arrow_index) ],
39          vec![ cell ]
40        )
41      }).collect::<Vec<_>>()
42    }).collect()
43  }
44}