pub struct Sudoku {
inner: [[char; 9]; 9],
}
impl Sudoku {
pub fn solve_iterative(&mut self) {
let mut stack = Vec::new();
let [i, j] = self.next_blank().unwrap();
for x in '1'..='9' {
stack.push((i, j, x));
}
loop {
let (i, j, v) = stack.pop().unwrap();
if v == '.' {
self.set(i, j, v);
} else if self.can_set(i, j, v) {
self.set(i, j, v);
if let Some([i, j]) = self.next_blank() {
stack.push((i, j, '.'));
for x in '1'..='9' {
stack.push((i, j, x));
}
} else {
return;
}
}
}
}
}
impl Sudoku {
pub fn solve_recursive(&mut self) -> bool {
if let Some([i, j]) = self.next_blank() {
for v in '1'..='9' {
if self.can_set(i, j, v) {
self.set(i, j, v);
if self.solve_recursive() {
return true;
} else {
self.erase(i, j);
}
}
}
} else {
return true;
}
false
}
}
impl Sudoku {
pub fn new(matrix: [[char; 9]; 9]) -> Self {
Self { inner: matrix }
}
fn next_blank(&self) -> Option<[usize; 2]> {
for i in 0..9 {
for j in 0..9 {
if self.inner[i][j] == '.' {
return Some([i, j]);
}
}
}
None
}
fn can_set(&self, i: usize, j: usize, n: char) -> bool {
for j_ in 0..9 {
if self.inner[i][j_] == n {
return false;
}
}
for i_ in 0..9 {
if self.inner[i_][j] == n {
return false;
}
}
let i1 = i / 3;
let j1 = j / 3;
for i2 in 0..3 {
for j2 in 0..3 {
if self.inner[i1 * 3 + i2][j1 * 3 + j2] == n {
return false;
}
}
}
true
}
fn set(&mut self, i: usize, j: usize, v: char) {
self.inner[i][j] = v
}
fn erase(&mut self, i: usize, j: usize) {
self.inner[i][j] = '.';
}
}
use std::fmt;
impl fmt::Display for Sudoku {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut s = String::with_capacity(180);
for i in 0..9 {
for j in 0..9 {
s.push_str(&format!("{} ", self.inner[i][j]))
}
s.push('\n')
}
s.push('\n');
write!(f, "{}", s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sudoku() {
let ans = [
['5', '1', '9', '7', '4', '8', '6', '3', '2'],
['7', '8', '3', '6', '5', '2', '4', '1', '9'],
['4', '2', '6', '1', '3', '9', '8', '7', '5'],
['3', '5', '7', '9', '8', '6', '2', '4', '1'],
['2', '6', '4', '3', '1', '7', '5', '9', '8'],
['1', '9', '8', '5', '2', '4', '3', '6', '7'],
['9', '7', '5', '8', '6', '3', '1', '2', '4'],
['8', '3', '2', '4', '9', '1', '7', '5', '6'],
['6', '4', '1', '2', '7', '5', '9', '8', '3'],
];
let s = [
['.', '.', '9', '7', '4', '8', '.', '.', '.'],
['7', '.', '.', '.', '.', '.', '.', '.', '.'],
['.', '2', '.', '1', '.', '9', '.', '.', '.'],
['.', '.', '7', '.', '.', '.', '2', '4', '.'],
['.', '6', '4', '.', '1', '.', '5', '9', '.'],
['.', '9', '8', '.', '.', '.', '3', '.', '.'],
['.', '.', '.', '8', '.', '3', '.', '2', '.'],
['.', '.', '.', '.', '.', '.', '.', '.', '6'],
['.', '.', '.', '2', '7', '5', '9', '.', '.'],
];
let mut sudoku = Sudoku::new(s);
sudoku.solve_iterative();
println!("{}", &sudoku);
assert_eq!(sudoku.inner, ans);
let mut sudoku = Sudoku::new(s);
sudoku.solve_recursive();
println!("{}", &sudoku);
assert_eq!(sudoku.inner, ans);
let ans = [
['5', '3', '4', '6', '7', '8', '9', '1', '2'],
['6', '7', '2', '1', '9', '5', '3', '4', '8'],
['1', '9', '8', '3', '4', '2', '5', '6', '7'],
['8', '5', '9', '7', '6', '1', '4', '2', '3'],
['4', '2', '6', '8', '5', '3', '7', '9', '1'],
['7', '1', '3', '9', '2', '4', '8', '5', '6'],
['9', '6', '1', '5', '3', '7', '2', '8', '4'],
['2', '8', '7', '4', '1', '9', '6', '3', '5'],
['3', '4', '5', '2', '8', '6', '1', '7', '9'],
];
let s = [
['5', '3', '.', '.', '7', '.', '.', '.', '.'],
['6', '.', '.', '1', '9', '5', '.', '.', '.'],
['.', '9', '8', '.', '.', '.', '.', '6', '.'],
['8', '.', '.', '.', '6', '.', '.', '.', '3'],
['4', '.', '.', '8', '.', '3', '.', '.', '1'],
['7', '.', '.', '.', '2', '.', '.', '.', '6'],
['.', '6', '.', '.', '.', '.', '2', '8', '.'],
['.', '.', '.', '4', '1', '9', '.', '.', '5'],
['.', '.', '.', '.', '8', '.', '.', '7', '9'],
];
let mut sudoku = Sudoku::new(s);
sudoku.solve_iterative();
println!("{}", &sudoku);
assert_eq!(sudoku.inner, ans);
let mut sudoku = Sudoku::new(s);
sudoku.solve_recursive();
println!("{}", &sudoku);
assert_eq!(sudoku.inner, ans);
}
}