diff --git a/src/main.rs b/src/main.rs index 67acbab..5acbd1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ use std::fmt; -use std::collections::HashSet; +//use std::collections::HashSet; use rand::seq::SliceRandom; #[derive(Clone)] @@ -21,7 +21,7 @@ impl Cell { self.possibilities = (1..=9).collect(); } - fn remove_possibilities(&mut self, possibilities: &HashSet) { + fn remove_possibilities(&mut self, possibilities: &Vec) { self.possibilities.retain(|&x| !possibilities.contains(&x)) } } @@ -87,63 +87,28 @@ impl Sudoku { } fn update_possibilities(&mut self) { - self.update_rows(); - self.update_columns(); - self.update_squares(); - } - - fn update_rows(&mut self) { - for row_index in 0..9 { - let mut used_values: HashSet = HashSet::new(); - - for column_index in 0..9 { - if let Some(value) = self.grid[row_index][column_index].value { - used_values.insert(value); - } - } - - for column_index in 0..9 { - self.grid[row_index][column_index].remove_possibilities(&used_values); - } - } - } - - fn update_columns(&mut self) { - for column_index in 0..9 { - let mut used_values: HashSet = HashSet::new(); - - for row_index in 0..9 { - if let Some(value) = self.grid[row_index][column_index].value { - used_values.insert(value); - } - } - - for row_index in 0..9 { - self.grid[row_index][column_index].remove_possibilities(&used_values); - } - } - } - - fn update_squares(&mut self) { - for square_row_index in 0..3 { - for square_column_index in 0..3 { - let mut used_values: HashSet = HashSet::new(); - - for row_offset_index in 0..3 { - for column_offset_index in 0..3 { - if let Some(value) = self.grid[square_row_index * 3 + row_offset_index][square_column_index * 3 + column_offset_index].value { - used_values.insert(value); - } - } - } - - for row_offset_index in 0..3 { - for column_offset_index in 0..3 { - self.grid[square_row_index * 3 + row_offset_index][square_column_index * 3 + column_offset_index].remove_possibilities(&used_values.clone()); - } - } - } - } + let mut row_used_values: [Vec;9] = [vec![],vec![],vec![],vec![],vec![],vec![],vec![],vec![],vec![]]; + let mut column_used_values: [Vec;9] = [vec![],vec![],vec![],vec![],vec![],vec![],vec![],vec![],vec![]]; + let mut square_used_values: [[Vec;3];3] = [[vec![],vec![],vec![]],[vec![],vec![],vec![]],[vec![],vec![],vec![]]]; + + for row_index in 0..9 { + for column_index in 0..9 { + let Some(value) = self.grid[row_index][column_index].value else { + continue + }; + row_used_values[row_index].push(value); + column_used_values[column_index].push(value); + square_used_values[row_index/3][column_index/3].push(value); + } + } + + for row_index in 0..9 { + for column_index in 0..9 { + self.grid[row_index][column_index].remove_possibilities(&row_used_values[row_index]); + self.grid[row_index][column_index].remove_possibilities(&column_used_values[column_index]); + self.grid[row_index][column_index].remove_possibilities(&square_used_values[row_index/3][column_index/3]); + } + } } fn collapse(&mut self) -> bool { @@ -188,16 +153,14 @@ impl Sudoku { } } - if let Some(choice) = fork { - self.reset_possibilities(); - let mut choice_value = HashSet::new(); - choice_value.insert(choice.selected_value); - self.grid[choice.cell_selected[0]][choice.cell_selected[1]].remove_possibilities(&choice_value); - return self.collapse_cell(choice.cell_selected[0], choice.cell_selected[1]) - } else { + let Some(choice) = fork else { println!("x backtracked to start"); return false - } + }; + + self.reset_possibilities(); + self.grid[choice.cell_selected[0]][choice.cell_selected[1]].remove_possibilities(&vec![choice.selected_value]); + return self.collapse_cell(choice.cell_selected[0], choice.cell_selected[1]) } fn reset_possibilities(&mut self) { @@ -211,26 +174,61 @@ impl Sudoku { } fn collapse_cell(&mut self, row_index: usize, column_index: usize) -> bool { - if let Some(&selected_value) = self.grid[row_index][column_index].possibilities.choose(&mut self.rng) { - self.history.push(Choice { - cell_selected: [row_index, column_index], - possibilities: self.grid[row_index][column_index].possibilities.clone(), - selected_value, - }); - - self.grid[row_index][column_index].set(selected_value); - println!("# collapsing [{}][{}] ({:?}) to {}", row_index, column_index, self.grid[row_index][column_index].possibilities, selected_value); - return true - } else { + let Some(&selected_value) = self.grid[row_index][column_index].possibilities.choose(&mut self.rng) else { println!("x no possibilities for [{}][{}]", row_index, column_index); return false + }; + + self.history.push(Choice { + cell_selected: [row_index, column_index], + possibilities: self.grid[row_index][column_index].possibilities.clone(), + selected_value, + }); + + self.grid[row_index][column_index].set(selected_value); + println!("# collapsing [{}][{}] ({:?}) to {}", row_index, column_index, self.grid[row_index][column_index].possibilities, selected_value); + return true + } + + fn solve(&mut self, display: bool) { + if display { + self.display(); + println!("--------"); } - } + + self.update_possibilities(); + + let mut counter: usize = 0; + + while self.collapse() { + self.update_possibilities(); + counter +=1; + } + + if display { + println!("--------"); + + println!("finished with {} steps", counter); + + self.display(); + } + } } + // [6,0,0,0,0,2,1,0,0], // has to backtrack + // [0,3,2,9,0,0,0,7,0], + // [0,0,0,0,0,8,0,0,0], + // [2,0,0,0,0,0,4,0,0], + // [7,0,3,0,0,0,9,1,0], + // [0,8,0,0,9,4,0,0,0], + // [0,0,4,0,0,0,6,0,0], + // [1,2,0,7,0,0,0,0,5], + // [0,0,0,0,0,0,0,9,4], + + fn main() { let sudoku_set: [[u8; 9]; 9] = [ - [6,0,0,0,0,2,1,0,0], + [0,0,0,0,0,0,0,0,0], [0,3,2,9,0,0,0,7,0], [0,0,0,0,0,8,0,0,0], [2,0,0,0,0,0,4,0,0], @@ -243,17 +241,5 @@ fn main() { let mut sudoku = Sudoku::new(sudoku_set); - sudoku.display(); - - println!("--------"); - - sudoku.update_possibilities(); - - while sudoku.collapse() { - sudoku.update_possibilities(); - } - - println!("--------"); - - sudoku.display(); + sudoku.solve(true); }