Add support for guesses; add other puzzle

This commit is contained in:
Joel Therrien 2020-09-14 12:58:40 -07:00
parent b51d05908c
commit 5d2681184c
2 changed files with 141 additions and 61 deletions

10
puzzles/challenge2.csv Normal file
View file

@ -0,0 +1,10 @@
4,0,0,0,2,3,0,0,0
0,2,0,0,4,0,5,8,0
0,1,0,0,0,6,0,0,0
0,0,6,0,5,0,2,0,0
2,3,0,6,0,4,8,0,0
0,4,0,0,0,0,0,3,0
1,6,0,2,3,0,0,0,0
0,0,5,7,0,1,0,0,0
0,0,0,0,6,5,0,0,0
1 4 0 0 0 2 3 0 0 0
2 0 2 0 0 4 0 5 8 0
3 0 1 0 0 0 6 0 0 0
4 0 0 6 0 5 0 2 0 0
5 2 3 0 6 0 4 8 0 0
6 0 4 0 0 0 0 0 3 0
7 1 6 0 2 3 0 0 0 0
8 0 0 5 7 0 1 0 0 0
9 0 0 0 0 6 5 0 0 0

View file

@ -337,6 +337,38 @@ impl Grid {
} }
} }
impl Clone for Grid {
fn clone(&self) -> Self {
let mut new = Grid::new();
new.clone_from(&self);
return new;
}
fn clone_from(&mut self, source: &Self) {
for x in 0..9 {
for y in 0..9 {
let source_value = source.get(x, y).unwrap().get_value_copy();
self.get(x, y).unwrap().set_value_exact(source_value);
}
}
for i in 0..9 {
let new_row = &*self.rows.get(i).unwrap().borrow();
let source_row = &*source.rows.get(i).unwrap().borrow();
new_row.do_update.replace(source_row.do_update());
let new_column = &*self.columns.get(i).unwrap().borrow();
let source_column = &*source.columns.get(i).unwrap().borrow();
new_column.do_update.replace(source_column.do_update());
let new_section = &*self.sections.get(i).unwrap().borrow();
let source_section = &*source.sections.get(i).unwrap().borrow();
new_section.do_update.replace(source_section.do_update());
}
}
}
@ -346,7 +378,6 @@ impl Grid {
struct FauxCell{ struct FauxCell{
index: usize, index: usize,
real_cell: Rc<Cell>,
possibilities: HashSet<u8>, possibilities: HashSet<u8>,
in_group: bool in_group: bool
} }
@ -364,12 +395,9 @@ impl FauxCell {
struct FauxLine (Vec<FauxCell>); struct FauxLine (Vec<FauxCell>);
impl FauxLine { impl FauxLine {
fn get_mut(&mut self, index: usize) -> Option<&mut FauxCell>{
return self.0.get_mut(index);
}
fn num_in_group(&self) -> usize { fn num_in_group(&self) -> usize {
self.0.iter().filter(|fauxcell| fauxcell.in_group).count() self.0.iter().filter(|faux_cell| faux_cell.in_group).count()
} }
fn num_out_group(&self) -> usize { fn num_out_group(&self) -> usize {
@ -432,7 +460,6 @@ fn bisect_possibility_groups(line: &Line, cells_of_interest: Vec<usize>){
let faux_cell = FauxCell { let faux_cell = FauxCell {
index: i, index: i,
real_cell: cell,
possibilities: faux_possibilities, possibilities: faux_possibilities,
in_group: false in_group: false
}; };
@ -754,8 +781,70 @@ fn solve_line(grid: &Grid, line: &Line){
} }
fn solve_grid(grid: &Grid) { fn find_smallest_cell(grid: &Grid) -> Option<Rc<Cell>>{
'outer: loop { // Find a cell of smallest size (in terms of possibilities) and make a guess
// Can assume that no cells of only possibility 1 exist
let mut smallest_cell : Option<Rc<Cell>> = None;
let mut smallest_size = usize::MAX;
'outer: for x in 0..9 {
for y in 0..9 {
let cell_rc = grid.get(x, y).unwrap();
let cell = &*grid.get(x, y).unwrap();
let cell_value = &*cell.value.borrow();
match cell_value {
CellValue::UNKNOWN(possibilities) => {
if (possibilities.len() < smallest_size) && (possibilities.len() > 0){
smallest_size = possibilities.len();
smallest_cell = Some(cell_rc);
}
},
_ => {}
}
if smallest_size <= 2 {
break 'outer; // We aren't going to get smaller
}
}
}
smallest_cell
}
enum SolveStatus {
COMPLETE,
UNFINISHED,
INVALID
}
fn solve_grid(grid: &mut Grid) -> SolveStatus{
// Code is kind of messy so here it goes - solve_grid first tries to solve without any guesses
// If that's not enough and a guess is required, then solve_grid_guess is called
// solve_grid_guess runs through all the possibilities for the smallest cell, trying to solve them
// through calling this function.
// solve_grid_no_guess tries to solve without any guesses.
let mut status = solve_grid_no_guess(grid);
status = match status {
SolveStatus::UNFINISHED => {
solve_grid_guess(grid)
},
_ => {status}
};
match status {
SolveStatus::UNFINISHED => panic!("solve_grid_guess should never return UNFINISHED"),
_ => return status
}
}
fn solve_grid_no_guess(grid: &mut Grid) -> SolveStatus{
loop {
let mut ran_something = false; let mut ran_something = false;
for (_index, line_ref) in grid.rows.iter().enumerate() { for (_index, line_ref) in grid.rows.iter().enumerate() {
//println!("Processing row {}", _index); //println!("Processing row {}", _index);
@ -783,8 +872,7 @@ fn solve_grid(grid: &Grid) {
} }
if !ran_something{ // No lines have changed since we last analyzed them if !ran_something{ // No lines have changed since we last analyzed them
println!("Unable to find a solution (no changes)"); return SolveStatus::UNFINISHED;
break 'outer;
} }
// Check if complete or invalid // Check if complete or invalid
@ -799,8 +887,8 @@ fn solve_grid(grid: &Grid) {
CellValue::UNKNOWN(possibilities) => { CellValue::UNKNOWN(possibilities) => {
appears_complete = false; appears_complete = false;
if possibilities.len() == 0 { if possibilities.len() == 0 {
println!("Unable to find a solution"); return SolveStatus::INVALID;
break 'outer;
} }
}, },
CellValue::FIXED(_) => {} CellValue::FIXED(_) => {}
@ -809,70 +897,52 @@ fn solve_grid(grid: &Grid) {
} }
if appears_complete { if appears_complete {
break 'outer; return SolveStatus::COMPLETE;
}
} }
}
fn solve_grid_guess(grid: &mut Grid) -> SolveStatus{
let smallest_cell = find_smallest_cell(grid);
let smallest_cell = match smallest_cell {
Some(cell) => cell,
None => return SolveStatus::INVALID
};
let possibilities = smallest_cell.get_value_possibilities().unwrap();
for (_index, &digit) in possibilities.iter().enumerate() {
let mut grid_copy = grid.clone();
grid_copy.get(smallest_cell.x, smallest_cell.y).unwrap().set(digit);
let status = solve_grid(&mut grid_copy);
match status {
SolveStatus::COMPLETE => {
grid.clone_from(&grid_copy);
return SolveStatus::COMPLETE;
},
SolveStatus::UNFINISHED => {
panic!("solve_grid should never return UNFINISHED")
},
SolveStatus::INVALID => {
continue;
} }
}
}
return SolveStatus::INVALID;
} }
/*
fn main() {
let grid = Grid::new();
println!("Now setting some values");
grid.get(0, 4).unwrap().set(8);
grid.get(0, 5).unwrap().set(5);
grid.get(0, 6).unwrap().set(6);
grid.get(2, 3).unwrap().set(9);
grid.get(2, 4).unwrap().set(4);
grid.get(2, 5).unwrap().set(3);
grid.get(2, 6).unwrap().set(5);
grid.get(2, 7).unwrap().set(7);
grid.get(3, 0).unwrap().set(8);
grid.get(3, 2).unwrap().set(2);
grid.get(3, 3).unwrap().set(6);
grid.get(3, 4).unwrap().set(7);
grid.get(3, 5).unwrap().set(4);
grid.get(3, 6).unwrap().set(9);
grid.get(4, 4).unwrap().set(9);
grid.get(4, 8).unwrap().set(5);
grid.get(5, 1).unwrap().set(6);
grid.get(5, 6).unwrap().set(2);
grid.get(6, 1).unwrap().set(8);
grid.get(6, 8).unwrap().set(2);
grid.get(7, 3).unwrap().set(7);
grid.get(7, 5).unwrap().set(6);
grid.get(7, 7).unwrap().set(5);
grid.get(7, 8).unwrap().set(4);
grid.get(8, 2).unwrap().set(7);
grid.get(8, 3).unwrap().set(4);
grid.print();
println!("Now going to start a solver on it");
solve_grid(&grid);
grid.print();
println!("\n");
}
*/
fn main() { fn main() {
let grid = read_grid().unwrap(); let mut grid = read_grid().unwrap();
grid.print(); grid.print();
println!("Solving grid"); println!("Solving grid");
solve_grid(&grid); solve_grid(&mut grid);
grid.print(); grid.print();
} }