This is traditional backtracking: Try all possibilities, but give up the moment it is obviously wrong.
The board is read from a file. Further down you will find 2 puzzles you can put in files.
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::env;
use std::process;
struct Board {
b: [[char;9];9],
}
impl Board {
pub fn new() -> Board {
Board { b: [['.';9];9] }
} // end new
fn okrow(&self, r: usize,val: char) -> bool {
for i in 0..9 {
if self.b[r][i]==val {
return false;
}
}
true
} // end okrow
fn okcol(&self, c: usize,val: char) -> bool {
for i in 0..9 {
if self.b[i][c]==val {
return false;
}
}
return true;
} // end okcol
fn oksquare(&self, r: usize,c: usize,val: char) -> bool {
let corner: [usize;9] = [0,0,0,3,3,3,6,6,6];
let top = corner[r];
let left = corner[c];
for i in left..left+3 {
for j in top..top+3 {
if self.b[j][i]==val {
return false;
}
}
}
return true;
} // end oksquare
pub fn print(&self) {
for x in 0..9 {
for y in 0..9 {
print!("{}",self.b[x][y]);
if (y+1) % 3 == 0 { print!(" "); }
}
println!();
if (x+1) % 3 == 0 { println!(); }
}
} // end p
pub fn readfile(&mut self,filename: String) {
let f = File::open(filename);
match f {
Ok(file) => {
let reader = BufReader::new(file);
let mut x = 0;
for line in reader.lines() {
let line = line.unwrap(); // Ignore errors.
let mut y = 0;
for char in line.chars() {
if char!=' ' {
self.b[x][y] = char;
y += 1;
}
}
if y>0 {
x += 1;
}
}
},
Err(_why) => {
println!("File not found");
process::exit(1);
}
}
} // end readfile
pub fn tryit(&mut self,r: usize,c: usize) {
if r>=9 {
println!("Solution");
self.print();
} else {
let c1 = if c==9-1 { 0 } else { c+1 };
let r1 = if c==9-1 { r+1 } else { r };
if self.b[r][c]=='.' {
for val in ['1','2','3','4','5','6','7','8','9'].iter() {
if self.okrow(r,*val) &&
self.okcol(c,*val) &&
self.oksquare(r,c,*val) {
self.b[r][c]=*val;
self.tryit(r1,c1);
self.b[r][c]='.';
}
}
} else {
self.tryit(r1,c1);
}
}
} // end tryit
} // end impl BoardStruct
fn main() {
println!("Hello Sudoku!");
let filename;
let args: Vec<_> = env::args().collect();
if args.len() == 2 {
filename = args[1].to_string();
} else if args.len() == 1{
println!("Missing file argument");
process::exit(1);
} else {
println!("Too many arguments");
process::exit(1);
}
println!("Opening {}",filename);
let mut board = Board::new();
board.readfile(filename);
board.tryit(0,0);
}
Compile and run:
rustc sudoku.rs
./sudoku sudoku1.txt
29..4.8..
....9.2.1
...7...3.
...6..72.
4.1...6.8
.52..4...
.6...7...
7.5.6....
..9.8..76
3.1...8.4
.468.13..
8.74.3..2
61..8...9
4896.2...
73.....86
5.47.8...
.731.5648
1.8...9..
It is faster than the lua-version, even when it has to read the file first:
real 0m0.009s
user 0m0.005s
sys 0m0.004s