Skip to content

Commit ff04cb1

Browse files
committed
Added a little sudoku solver to test/bench for everone's puzzle solving needs
1 parent 134f7b7 commit ff04cb1

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

src/test/bench/sudoku.rs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
use std;
2+
3+
import std::io;
4+
import std::str;
5+
import std::uint;
6+
import std::u8;
7+
import std::vec;
8+
import std::bitv;
9+
10+
// Computes a single solution to a given 9x9 sudoku
11+
//
12+
// Call with "-" to read input sudoku from stdin
13+
//
14+
// The expected line-based format is:
15+
//
16+
// 9,9
17+
// <row>,<column>,<color>
18+
// ...
19+
//
20+
// Row and column are 0-based (i.e. <= 8) and color is 1-based (>=1,<=9).
21+
// A color of 0 indicates an empty field.
22+
//
23+
// If called without arguments, sudoku solves a built-in example sudoku
24+
//
25+
26+
export grid_t, read_grid, solve_grid, write_grid;
27+
28+
// internal type of sudoku grids
29+
type grid = [[mutable u8]];
30+
31+
// exported type of sudoku grids
32+
tag grid_t { grid_ctor(grid); }
33+
34+
// read a sudoku problem from file f
35+
fn read_grid(f: io::reader) -> grid_t {
36+
assert f.read_line() == "9,9"; /* assert first line is exactly "9,9" */
37+
38+
let g = vec::init_fn({|_i| vec::init_elt_mut(0 as u8, 10u) }, 10u);
39+
while !f.eof() {
40+
// FIXME: replace with unicode compliant call
41+
let comps = str::split(str::trim(f.read_line()), ',' as u8);
42+
if vec::len(comps) >= 3u {
43+
let row = uint::from_str(comps[0]) as u8;
44+
let col = uint::from_str(comps[1]) as u8;
45+
g[row][col] = uint::from_str(comps[2]) as u8;
46+
}
47+
}
48+
ret grid_ctor(g);
49+
}
50+
51+
// solve sudoku grid
52+
fn solve_grid(g: grid_t) {
53+
fn next_color(g: grid, row: u8, col: u8, start_color: u8) -> bool {
54+
if start_color < 10u8 {
55+
// colors not yet used
56+
let avail = bitv::create(10u, false);
57+
u8::range(start_color, 10u8) { |color|
58+
bitv::set(avail, color as uint, true);
59+
}
60+
61+
// drop colors already in use in neighbourhood
62+
drop_colors(g, avail, row, col);
63+
64+
// find first remaining color that is available
65+
let i = 1 as uint;
66+
while i < (10 as uint) { /* FIXME llvm ctlhd */
67+
if bitv::get(avail, i) {
68+
g[row][col] = i as u8;
69+
ret true;
70+
}
71+
i += 1 as uint; /* else */
72+
}
73+
}
74+
g[row][col] = 0u8;
75+
ret false;
76+
}
77+
78+
// find colors available in neighbourhood of (row, col)
79+
fn drop_colors(g: grid, avail: bitv::t, row: u8, col: u8) {
80+
fn drop_color(g: grid, colors: bitv::t, row: u8, col: u8) {
81+
let color = g[row][col];
82+
if color != 0u8 { bitv::set(colors, color as uint, false); }
83+
}
84+
85+
let it = bind drop_color(g, avail, _, _);
86+
87+
u8::range(0u8, 9u8) { |idx|
88+
it(idx, col); /* check same column fields */
89+
it(row, idx); /* check same row fields */
90+
}
91+
92+
// check same block fields
93+
let row0 = (row / 3u8) * 3u8;
94+
let col0 = (col / 3u8) * 3u8;
95+
u8::range(row0, row0 + 3u8) { |alt_row|
96+
u8::range(col0, col0 + 3u8) { |alt_col| it(alt_row, alt_col); }
97+
}
98+
}
99+
100+
let work: [(u8, u8)] = []; /* queue of uncolored fields */
101+
u8::range(0u8, 9u8) { |row|
102+
u8::range(0u8, 9u8) { |col|
103+
let color = (*g)[row][col];
104+
if color == 0u8 { work += [(row, col)]; }
105+
}
106+
}
107+
108+
let ptr = 0u;
109+
let end = vec::len(work);
110+
while (ptr < end) {
111+
let (row, col) = work[ptr];
112+
// is there another color to try?
113+
if next_color(*g, row, col, (*g)[row][col] + (1 as u8)) {
114+
// yes: advance work list
115+
ptr = ptr + 1u;
116+
} else {
117+
// no: redo this field aft recoloring pred; unless there is none
118+
if ptr == 0u { fail "No solution found for this sudoku"; }
119+
ptr = ptr - 1u;
120+
}
121+
}
122+
}
123+
124+
fn write_grid(f: io::writer, g: grid_t) {
125+
u8::range(0u8, 9u8) { |row|
126+
f.write_str(#fmt("%u", (*g)[row][0] as uint));
127+
u8::range(1u8, 9u8) { |col|
128+
f.write_str(#fmt(" %u", (*g)[row][col] as uint));
129+
}
130+
f.write_char('\n');
131+
}
132+
}
133+
134+
fn main(args: [str]) {
135+
let grid = if vec::len(args) == 1u {
136+
// FIXME create sudoku inline since nested vec consts dont work yet
137+
let g = vec::init_fn({|_i| vec::init_elt_mut(0 as u8, 10u) }, 10u);
138+
g[0][1] = 4u8;
139+
g[0][3] = 6u8;
140+
g[0][7] = 3u8;
141+
g[0][8] = 2u8;
142+
g[1][2] = 8u8;
143+
g[1][4] = 2u8;
144+
g[2][0] = 7u8;
145+
g[2][3] = 8u8;
146+
g[3][3] = 5u8;
147+
g[4][1] = 5u8;
148+
g[4][5] = 3u8;
149+
g[4][6] = 6u8;
150+
g[5][0] = 6u8;
151+
g[5][1] = 8u8;
152+
g[5][7] = 9u8;
153+
g[6][1] = 9u8;
154+
g[6][2] = 5u8;
155+
g[6][5] = 6u8;
156+
g[6][7] = 7u8;
157+
g[7][4] = 4u8;
158+
g[7][7] = 6u8;
159+
g[8][0] = 4u8;
160+
g[8][5] = 7u8;
161+
g[8][6] = 2u8;
162+
g[8][8] = 3u8;
163+
grid_ctor(g)
164+
} else {
165+
read_grid(io::stdin())
166+
};
167+
solve_grid(grid);
168+
write_grid(io::stdout(), grid);
169+
}
170+

0 commit comments

Comments
 (0)