use std::collections::HashSet; use crate::playfield::Field; use crate::playfield::Playfield; pub struct SudokuSolver { playfield: Playfield, } impl SudokuSolver { pub fn new(playfield: &Playfield) -> SudokuSolver { Self { playfield: playfield.clone(), } } pub fn solve(&mut self) -> Playfield { self.populate_possible_values(); return self.playfield.clone(); } fn solve_fields(&mut self) { for open_field in &self.playfield.open_fields {} } fn populate_possible_values(&mut self) { for open_field in &self.playfield.open_fields { let (row_idx, col_idx) = self.playfield.convert_index(*open_field); let row = &self.playfield.fields[row_idx]; let possible_values_row = SudokuSolver::possible_values_from_vec(row, self.playfield.size as u32); let col_index = open_field % self.playfield.size; let col = self.playfield.get_column(col_idx); let possible_values_col = SudokuSolver::possible_values_from_vec(&col, self.playfield.size as u32); let possible_values = possible_values_row .intersection(&possible_values_col) .map(|v| *v) .collect(); let row = &mut self.playfield.fields[row_idx]; let field = &mut row[col_index]; field.possible_values = possible_values; } } fn possible_values_from_vec(row: &Vec, max_value: u32) -> HashSet { let possible_values: HashSet = (1..max_value + 1).collect(); let populated_values: HashSet = row .iter() .filter(|field| field.value.is_some()) .map(|v| v.value.unwrap()) .collect(); possible_values .difference(&populated_values) .map(|v| *v) .collect() } } #[cfg(test)] mod tests { use crate::sudoku_solver::SudokuSolver; use crate::Playfield; fn create_test_playfield(input: &str, size: usize) -> Playfield { Playfield::new(&input.to_string(), size) } fn setup_solver(input: &str, size: usize) -> SudokuSolver { let playfield = create_test_playfield(input, size); SudokuSolver::new(&playfield) } mod solve { use super::*; #[test] fn simple() { let solver = &mut setup_solver("1 0 3 4 4 0 2 0 0 1 0 2 2 4 0 3", 4); let expected = create_test_playfield("1 2 3 4 4 3 2 1 3 1 4 2 2 4 1 3", 4); let solved = solver.solve(); assert_eq!(solved, expected); } } mod solve_fields { use super::*; #[test] fn simple() {} } mod possible_values { use super::*; #[test] fn simple() { let solver = &mut setup_solver("1 0 0 3 0 0 2 3 1", 3); let expected_1 = vec![2]; let expected_2 = vec![3, 2]; let expected_3 = vec![2, 1]; let expected_4 = vec![2]; solver.populate_possible_values(); let field_1_values = &solver.playfield.fields[0][1].possible_values; let field_2_values = &solver.playfield.fields[0][2].possible_values; let field_3_values = &solver.playfield.fields[1][1].possible_values; let field_4_values = &solver.playfield.fields[1][2].possible_values; assert!(field_1_values.iter().all(|i| expected_1.contains(i))); assert!(field_2_values.iter().all(|i| expected_2.contains(i))); assert!(field_3_values.iter().all(|i| expected_3.contains(i))); assert!(field_4_values.iter().all(|i| expected_4.contains(i))); } #[test] fn populate_from_box() { let solver = &mut setup_solver("1 2 0 0 3 0 0 0 0 0 0 0 0 0 0 0", 4); } } mod possible_values_from_vec { use super::super::*; use super::*; #[test] fn simple() { let playfield = create_test_playfield("1 2 0 3 0 0 0 0 0", 3); let expected_row_1 = HashSet::from_iter(vec![3]); let expected_row_2 = vec![1, 2]; let expected_row_3 = vec![1, 2, 3]; let possible_values_row_1 = SudokuSolver::possible_values_from_vec(&playfield.fields[0], 3); let possible_values_row_2 = SudokuSolver::possible_values_from_vec(&playfield.fields[1], 3); let possible_values_row_3 = SudokuSolver::possible_values_from_vec(&playfield.fields[2], 3); assert_eq!(possible_values_row_1, expected_row_1); assert!(possible_values_row_2 .iter() .all(|item| expected_row_2.contains(item))); assert!(possible_values_row_3 .iter() .all(|item| expected_row_3.contains(item))); } } }