2012-09-11 19:46:20 -05:00
|
|
|
extern mod std;
|
2011-11-19 18:53:12 -06:00
|
|
|
|
2012-09-05 14:32:05 -05:00
|
|
|
use std::bitv;
|
|
|
|
use io::{ReaderUtil, WriterUtil};
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// Computes a single solution to a given 9x9 sudoku
|
|
|
|
//
|
|
|
|
// Call with "-" to read input sudoku from stdin
|
|
|
|
//
|
|
|
|
// The expected line-based format is:
|
|
|
|
//
|
|
|
|
// 9,9
|
|
|
|
// <row>,<column>,<color>
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
// Row and column are 0-based (i.e. <= 8) and color is 1-based (>=1,<=9).
|
|
|
|
// A color of 0 indicates an empty field.
|
|
|
|
//
|
|
|
|
// If called without arguments, sudoku solves a built-in example sudoku
|
|
|
|
//
|
|
|
|
|
|
|
|
export grid_t, read_grid, solve_grid, write_grid;
|
|
|
|
|
|
|
|
// internal type of sudoku grids
|
2012-06-29 18:26:56 -05:00
|
|
|
type grid = ~[~[mut u8]];
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// exported type of sudoku grids
|
2012-01-19 20:31:08 -06:00
|
|
|
enum grid_t { grid_ctor(grid), }
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// read a sudoku problem from file f
|
2012-08-14 15:38:35 -05:00
|
|
|
fn read_grid(f: io::Reader) -> grid_t {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert f.read_line() == ~"9,9"; /* assert first line is exactly "9,9" */
|
2011-11-19 18:53:12 -06:00
|
|
|
|
2012-03-12 17:52:30 -05:00
|
|
|
let g = vec::from_fn(10u, {|_i|
|
|
|
|
vec::to_mut(vec::from_elem(10u, 0 as u8))
|
2012-03-01 01:44:52 -06:00
|
|
|
});
|
2011-11-19 18:53:12 -06:00
|
|
|
while !f.eof() {
|
2012-02-23 09:59:30 -06:00
|
|
|
let comps = str::split_char(str::trim(f.read_line()), ',');
|
2011-11-19 18:53:12 -06:00
|
|
|
if vec::len(comps) >= 3u {
|
2012-09-21 21:37:57 -05:00
|
|
|
let row = uint::from_str(comps[0]).get() as u8;
|
|
|
|
let col = uint::from_str(comps[1]).get() as u8;
|
|
|
|
g[row][col] = uint::from_str(comps[2]).get() as u8;
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return grid_ctor(g);
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// solve sudoku grid
|
|
|
|
fn solve_grid(g: grid_t) {
|
|
|
|
fn next_color(g: grid, row: u8, col: u8, start_color: u8) -> bool {
|
|
|
|
if start_color < 10u8 {
|
|
|
|
// colors not yet used
|
2012-08-11 09:08:42 -05:00
|
|
|
let avail = bitv::Bitv(10u, false);
|
2012-06-30 18:19:07 -05:00
|
|
|
for u8::range(start_color, 10u8) |color| {
|
2012-07-29 18:00:55 -05:00
|
|
|
avail.set(color as uint, true);
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// drop colors already in use in neighbourhood
|
2012-12-06 17:56:52 -06:00
|
|
|
drop_colors(copy g, copy avail, row, col);
|
2011-11-19 18:53:12 -06:00
|
|
|
|
|
|
|
// find first remaining color that is available
|
2012-06-30 18:19:07 -05:00
|
|
|
for uint::range(1u, 10u) |i| {
|
2012-07-29 18:00:55 -05:00
|
|
|
if avail.get(i) {
|
2011-11-19 18:53:12 -06:00
|
|
|
g[row][col] = i as u8;
|
2012-08-01 19:30:05 -05:00
|
|
|
return true;
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
2012-06-14 17:14:18 -05:00
|
|
|
};
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
g[row][col] = 0u8;
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// find colors available in neighbourhood of (row, col)
|
2012-08-11 09:08:42 -05:00
|
|
|
fn drop_colors(g: grid, avail: bitv::Bitv, row: u8, col: u8) {
|
|
|
|
fn drop_color(g: grid, colors: bitv::Bitv, row: u8, col: u8) {
|
2011-11-19 18:53:12 -06:00
|
|
|
let color = g[row][col];
|
2012-07-29 18:00:55 -05:00
|
|
|
if color != 0u8 { colors.set(color as uint, false); }
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
|
2012-12-06 17:56:52 -06:00
|
|
|
let it = |a,b| drop_color(copy g, copy avail, a, b);
|
2011-11-19 18:53:12 -06:00
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
for u8::range(0u8, 9u8) |idx| {
|
2011-11-19 18:53:12 -06:00
|
|
|
it(idx, col); /* check same column fields */
|
|
|
|
it(row, idx); /* check same row fields */
|
|
|
|
}
|
|
|
|
|
|
|
|
// check same block fields
|
|
|
|
let row0 = (row / 3u8) * 3u8;
|
|
|
|
let col0 = (col / 3u8) * 3u8;
|
2012-06-30 18:19:07 -05:00
|
|
|
for u8::range(row0, row0 + 3u8) |alt_row| {
|
|
|
|
for u8::range(col0, col0 + 3u8) |alt_col| { it(alt_row, alt_col); }
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut work: ~[(u8, u8)] = ~[]; /* queue of uncolored fields */
|
2012-06-30 18:19:07 -05:00
|
|
|
for u8::range(0u8, 9u8) |row| {
|
|
|
|
for u8::range(0u8, 9u8) |col| {
|
2011-11-19 18:53:12 -06:00
|
|
|
let color = (*g)[row][col];
|
2012-06-29 18:26:56 -05:00
|
|
|
if color == 0u8 { work += ~[(row, col)]; }
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut ptr = 0u;
|
2011-11-19 18:53:12 -06:00
|
|
|
let end = vec::len(work);
|
|
|
|
while (ptr < end) {
|
|
|
|
let (row, col) = work[ptr];
|
|
|
|
// is there another color to try?
|
2012-12-06 17:56:52 -06:00
|
|
|
if next_color(copy *g, row, col, (*g)[row][col] + (1 as u8)) {
|
2011-11-19 18:53:12 -06:00
|
|
|
// yes: advance work list
|
|
|
|
ptr = ptr + 1u;
|
|
|
|
} else {
|
|
|
|
// no: redo this field aft recoloring pred; unless there is none
|
2012-07-14 00:57:48 -05:00
|
|
|
if ptr == 0u { fail ~"No solution found for this sudoku"; }
|
2011-11-19 18:53:12 -06:00
|
|
|
ptr = ptr - 1u;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn write_grid(f: io::Writer, g: grid_t) {
|
2012-06-30 18:19:07 -05:00
|
|
|
for u8::range(0u8, 9u8) |row| {
|
2012-08-22 19:24:52 -05:00
|
|
|
f.write_str(fmt!("%u", (*g)[row][0] as uint));
|
2012-06-30 18:19:07 -05:00
|
|
|
for u8::range(1u8, 9u8) |col| {
|
2012-08-22 19:24:52 -05:00
|
|
|
f.write_str(fmt!(" %u", (*g)[row][col] as uint));
|
2011-11-19 18:53:12 -06:00
|
|
|
}
|
|
|
|
f.write_char('\n');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-03 21:16:27 -05:00
|
|
|
fn main() {
|
|
|
|
let args = os::args();
|
2012-10-11 20:08:58 -05:00
|
|
|
let grid = if vec::len(args) == 1u {
|
|
|
|
// FIXME create sudoku inline since nested vec consts dont work yet
|
2012-10-11 20:09:55 -05:00
|
|
|
// (#3733)
|
2012-10-11 20:08:58 -05:00
|
|
|
let g = vec::from_fn(10u, |_i| {
|
|
|
|
vec::to_mut(vec::from_elem(10u, 0 as u8))
|
|
|
|
});
|
|
|
|
g[0][1] = 4u8;
|
|
|
|
g[0][3] = 6u8;
|
|
|
|
g[0][7] = 3u8;
|
|
|
|
g[0][8] = 2u8;
|
|
|
|
g[1][2] = 8u8;
|
|
|
|
g[1][4] = 2u8;
|
|
|
|
g[2][0] = 7u8;
|
|
|
|
g[2][3] = 8u8;
|
|
|
|
g[3][3] = 5u8;
|
|
|
|
g[4][1] = 5u8;
|
|
|
|
g[4][5] = 3u8;
|
|
|
|
g[4][6] = 6u8;
|
|
|
|
g[5][0] = 6u8;
|
|
|
|
g[5][1] = 8u8;
|
|
|
|
g[5][7] = 9u8;
|
|
|
|
g[6][1] = 9u8;
|
|
|
|
g[6][2] = 5u8;
|
|
|
|
g[6][5] = 6u8;
|
|
|
|
g[6][7] = 7u8;
|
|
|
|
g[7][4] = 4u8;
|
|
|
|
g[7][7] = 6u8;
|
|
|
|
g[8][0] = 4u8;
|
|
|
|
g[8][5] = 7u8;
|
|
|
|
g[8][6] = 2u8;
|
|
|
|
g[8][8] = 3u8;
|
|
|
|
grid_ctor(g)
|
2011-11-19 18:53:12 -06:00
|
|
|
} else {
|
|
|
|
read_grid(io::stdin())
|
|
|
|
};
|
2012-12-06 17:56:52 -06:00
|
|
|
solve_grid(copy grid);
|
2011-11-19 18:53:12 -06:00
|
|
|
write_grid(io::stdout(), grid);
|
|
|
|
}
|
|
|
|
|