1212
1313extern mod std;
1414
15- use std:: bitv;
1615use core:: io:: { ReaderUtil , WriterUtil } ;
1716use core:: io;
17+ use core:: unstable:: intrinsics:: cttz16;
1818
1919// Computes a single solution to a given 9x9 sudoku
2020//
@@ -35,146 +35,241 @@ use core::io;
3535// internal type of sudoku grids
3636type grid = ~[ ~[ u8 ] ] ;
3737
38- // exported type of sudoku grids
39- pub enum grid_t { grid_ctor( grid ) , }
40-
41- // read a sudoku problem from file f
42- pub fn read_grid ( f : @io:: Reader ) -> grid_t {
43- fail_unless ! ( f. read_line( ) == ~"9 , 9 "); /* assert first line is exactly " 9 , 9 " */
44-
45- let mut g = vec::from_fn(10u, {|_i|
46- vec::from_elem(10u, 0 as u8)
47- });
48- while !f.eof() {
49- let comps = str::split_char(str::trim(f.read_line()), ',');
50- if vec::len(comps) >= 3u {
51- let row = uint::from_str(comps[0]).get() as u8;
52- let col = uint::from_str(comps[1]).get() as u8;
53- g[row][col] = uint::from_str(comps[2]).get() as u8;
38+ struct Sudoku {
39+ grid : grid
40+ }
41+
42+ pub impl Sudoku {
43+ static pub fn new( g: grid ) -> Sudoku {
44+ return Sudoku { grid : g }
45+ }
46+
47+ static pub fn from_vec ( vec : & [ [ u8 * 9 ] * 9 ] ) -> Sudoku {
48+ let mut g = do vec:: from_fn ( 9 u) |i| {
49+ do vec:: from_fn ( 9 u) |j| { vec[ i] [ j] }
50+ } ;
51+ return Sudoku :: new( g)
52+ }
53+
54+ pub fn equal ( & self , other : & Sudoku ) -> bool {
55+ for u8:: range( 0u8 , 9u8 ) |row| {
56+ for u8:: range( 0u8 , 9u8 ) |col| {
57+ if self . grid [ row] [ col] != other. grid [ row] [ col] {
58+ return false ;
59+ }
60+ }
61+ }
62+ return true ;
63+ }
64+
65+ static pub fn read( reader: @io:: Reader ) -> Sudoku {
66+ fail_unless ! ( reader. read_line( ) == ~"9 , 9 "); /* assert first line is exactly " 9 , 9 " */
67+
68+ let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] });
69+ while !reader.eof() {
70+ let comps = str::split_char(str::trim(reader.read_line()), ',');
71+ if vec::len(comps) == 3u {
72+ let row = uint::from_str(comps[0]).get() as u8;
73+ let col = uint::from_str(comps[1]).get() as u8;
74+ g[row][col] = uint::from_str(comps[2]).get() as u8;
75+ }
76+ else {
77+ fail!(~" Invalid sudoku file");
78+ }
79+ }
80+ return Sudoku::new(g)
81+ }
82+
83+ pub fn write(&self, writer: @io::Writer) {
84+ for u8::range(0u8, 9u8) |row| {
85+ writer.write_str(fmt!(" %u", self.grid[row][0] as uint));
86+ for u8::range(1u8, 9u8) |col| {
87+ writer.write_str(fmt!(" %u", self.grid[row][col] as uint));
88+ }
89+ writer.write_char('\n ');
90+ }
91+ }
92+
93+ // solve sudoku grid
94+ pub fn solve(&mut self) {
95+ let mut work: ~[(u8, u8)] = ~[]; /* queue of uncolored fields */
96+ for u8::range(0u8, 9u8) |row| {
97+ for u8::range(0u8, 9u8) |col| {
98+ let color = self.grid[row][col];
99+ if color == 0u8 { work += ~[(row, col)]; }
100+ }
101+ }
102+
103+ let mut ptr = 0u;
104+ let end = vec::len(work);
105+ while (ptr < end) {
106+ let (row, col) = work[ptr];
107+ // is there another color to try?
108+ if self.next_color(row, col, self.grid[row][col] + (1 as u8)) {
109+ // yes: advance work list
110+ ptr = ptr + 1u;
111+ } else {
112+ // no: redo this field aft recoloring pred; unless there is none
113+ if ptr == 0u { fail!(~" No solution found for this sudoku" ) ; }
114+ ptr = ptr - 1 u;
115+ }
54116 }
55117 }
56- return grid_ctor(g);
57- }
58118
59- // solve sudoku grid
60- pub fn solve_grid(g: grid_t) {
61- fn next_color(mut g: grid, row: u8, col: u8, start_color: u8) -> bool {
119+ fn next_color ( & mut self , row : u8 , col : u8 , start_color : u8 ) -> bool {
62120 if start_color < 10u8 {
63121 // colors not yet used
64- let mut avail = bitv::Bitv::new(10u, false);
65- for u8::range(start_color, 10u8) |color| {
66- avail.set(color as uint, true);
67- }
122+ let mut avail = ~Colors :: new ( start_color) ;
68123
69124 // drop colors already in use in neighbourhood
70- drop_colors(copy g, copy avail, row, col);
125+ self . drop_colors ( avail, row, col) ;
71126
72127 // find first remaining color that is available
73- for uint::range(1u, 10u) |i| {
74- if avail.get(i) {
75- g[row][col] = i as u8;
76- return true;
77- }
78- };
128+ let next = avail. next ( ) ;
129+ self . grid [ row] [ col] = next;
130+ return 0u8 != next;
79131 }
80- g [row][col] = 0u8;
132+ self . grid [ row] [ col] = 0u8 ;
81133 return false ;
82134 }
83135
84136 // find colors available in neighbourhood of (row, col)
85- fn drop_colors(g: grid, avail: bitv::Bitv, row: u8, col: u8) {
86- fn drop_color(g: grid, mut colors: bitv::Bitv, row: u8, col: u8) {
87- let color = g[row][col];
88- if color != 0u8 { colors.set(color as uint, false); }
89- }
90-
91- let it = |a,b| drop_color(copy g, copy avail, a, b);
92-
137+ fn drop_colors ( & mut self , avail : & mut Colors , row : u8 , col : u8 ) {
93138 for u8:: range( 0u8 , 9u8 ) |idx| {
94- it( idx, col); /* check same column fields */
95- it( row, idx); /* check same row fields */
139+ avail . remove ( self . grid [ idx] [ col] ) ; /* check same column fields */
140+ avail . remove ( self . grid [ row] [ idx] ) ; /* check same row fields */
96141 }
97142
98143 // check same block fields
99144 let row0 = ( row / 3u8 ) * 3u8 ;
100145 let col0 = ( col / 3u8 ) * 3u8 ;
101146 for u8:: range( row0, row0 + 3u8 ) |alt_row| {
102- for u8::range(col0, col0 + 3u8) |alt_col| { it( alt_row, alt_col); }
147+ for u8:: range( col0, col0 + 3u8 ) |alt_col| { avail . remove ( self . grid [ alt_row] [ alt_col] ) ; }
103148 }
104149 }
150+ }
151+
152+ // Stores available colors as simple bitfield, bit 0 is always unset
153+ struct Colors ( u16 ) ;
154+
155+ const heads: u16 = ( 1u16 << 10 ) - 1 ; /* bits 9..0 */
156+
157+ impl Colors {
158+ static fn new( start_color: u8 ) -> Colors {
159+ // Sets bits 9..start_color
160+ let tails = !0u16 << start_color;
161+ return Colors ( heads & tails) ;
162+ }
105163
106- let mut work: ~[(u8, u8)] = ~[]; /* queue of uncolored fields */
107- for u8::range(0u8, 9u8) |row| {
108- for u8::range(0u8, 9u8) |col| {
109- let color = (*g)[row][col];
110- if color == 0u8 { work += ~[(row, col)]; }
164+ fn next ( & self ) -> u8 {
165+ let val = * * self & heads;
166+ if ( 0u16 == val) {
167+ return 0u8 ;
168+ }
169+ else
170+ {
171+ return cttz16 ( val as i16 ) as u8 ;
111172 }
112173 }
113174
114- let mut ptr = 0u;
115- let end = vec::len(work);
116- while (ptr < end) {
117- let (row, col) = work[ptr];
118- // is there another color to try?
119- if next_color(copy *g, row, col, (*g)[row][col] + (1 as u8)) {
120- // yes: advance work list
121- ptr = ptr + 1u;
122- } else {
123- // no: redo this field aft recoloring pred; unless there is none
124- if ptr == 0u { fail!(~" No solution found for this sudoku"); }
125- ptr = ptr - 1u;
175+ fn remove ( & mut self , color : u8 ) {
176+ if color != 0u8 {
177+ let val = * * self ;
178+ let mask = !( 1u16 << color) ;
179+ * self = Colors ( val & mask) ;
126180 }
127181 }
128182}
129183
130- pub fn write_grid(f: @io::Writer, g: grid_t) {
131- for u8::range(0u8, 9u8) |row| {
132- f.write_str(fmt!(" %u", (*g)[row][0] as uint));
133- for u8::range(1u8, 9u8) |col| {
134- f.write_str(fmt!(" %u", (*g)[row][col] as uint));
135- }
136- f.write_char('\n ' ) ;
137- }
184+ const default_sudoku: [ [ u8 * 9 ] * 9 ] = [
185+ /* 0 1 2 3 4 5 6 7 8 */
186+ /* 0 */ [ 0u8 , 4u8 , 0u8 , 6u8 , 0u8 , 0u8 , 0u8 , 3u8 , 2u8 ] ,
187+ /* 1 */ [ 0u8 , 0u8 , 8u8 , 0u8 , 2u8 , 0u8 , 0u8 , 0u8 , 0u8 ] ,
188+ /* 2 */ [ 7u8 , 0u8 , 0u8 , 8u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 ] ,
189+ /* 3 */ [ 0u8 , 0u8 , 0u8 , 5u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 ] ,
190+ /* 4 */ [ 0u8 , 5u8 , 0u8 , 0u8 , 0u8 , 3u8 , 6u8 , 0u8 , 0u8 ] ,
191+ /* 5 */ [ 6u8 , 8u8 , 0u8 , 0u8 , 0u8 , 0u8 , 0u8 , 9u8 , 0u8 ] ,
192+ /* 6 */ [ 0u8 , 9u8 , 5u8 , 0u8 , 0u8 , 6u8 , 0u8 , 7u8 , 0u8 ] ,
193+ /* 7 */ [ 0u8 , 0u8 , 0u8 , 0u8 , 4u8 , 0u8 , 0u8 , 6u8 , 0u8 ] ,
194+ /* 8 */ [ 4u8 , 0u8 , 0u8 , 0u8 , 0u8 , 7u8 , 2u8 , 0u8 , 3u8 ]
195+ ] ;
196+
197+ #[ cfg( test) ]
198+ const default_solution: [ [ u8 * 9 ] * 9 ] = [
199+ /* 0 1 2 3 4 5 6 7 8 */
200+ /* 0 */ [ 1u8 , 4u8 , 9u8 , 6u8 , 7u8 , 5u8 , 8u8 , 3u8 , 2u8 ] ,
201+ /* 1 */ [ 5u8 , 3u8 , 8u8 , 1u8 , 2u8 , 9u8 , 7u8 , 4u8 , 6u8 ] ,
202+ /* 2 */ [ 7u8 , 2u8 , 6u8 , 8u8 , 3u8 , 4u8 , 1u8 , 5u8 , 9u8 ] ,
203+ /* 3 */ [ 9u8 , 1u8 , 4u8 , 5u8 , 6u8 , 8u8 , 3u8 , 2u8 , 7u8 ] ,
204+ /* 4 */ [ 2u8 , 5u8 , 7u8 , 4u8 , 9u8 , 3u8 , 6u8 , 1u8 , 8u8 ] ,
205+ /* 5 */ [ 6u8 , 8u8 , 3u8 , 7u8 , 1u8 , 2u8 , 5u8 , 9u8 , 4u8 ] ,
206+ /* 6 */ [ 3u8 , 9u8 , 5u8 , 2u8 , 8u8 , 6u8 , 4u8 , 7u8 , 1u8 ] ,
207+ /* 7 */ [ 8u8 , 7u8 , 2u8 , 3u8 , 4u8 , 1u8 , 9u8 , 6u8 , 5u8 ] ,
208+ /* 8 */ [ 4u8 , 6u8 , 1u8 , 9u8 , 5u8 , 7u8 , 2u8 , 8u8 , 3u8 ]
209+ ] ;
210+
211+ #[ test]
212+ fn colors_new_works ( ) {
213+ fail_unless ! ( * Colors :: new( 1 ) == 1022u16 ) ;
214+ fail_unless ! ( * Colors :: new( 2 ) == 1020u16 ) ;
215+ fail_unless ! ( * Colors :: new( 3 ) == 1016u16 ) ;
216+ fail_unless ! ( * Colors :: new( 4 ) == 1008u16 ) ;
217+ fail_unless ! ( * Colors :: new( 5 ) == 992u16 ) ;
218+ fail_unless ! ( * Colors :: new( 6 ) == 960u16 ) ;
219+ fail_unless ! ( * Colors :: new( 7 ) == 896u16 ) ;
220+ fail_unless ! ( * Colors :: new( 8 ) == 768u16 ) ;
221+ fail_unless ! ( * Colors :: new( 9 ) == 512u16 ) ;
222+ }
223+
224+ #[ test]
225+ fn colors_next_works ( ) {
226+ fail_unless ! ( Colors ( 0 ) . next( ) == 0u8 ) ;
227+ fail_unless ! ( Colors ( 2 ) . next( ) == 1u8 ) ;
228+ fail_unless ! ( Colors ( 4 ) . next( ) == 2u8 ) ;
229+ fail_unless ! ( Colors ( 8 ) . next( ) == 3u8 ) ;
230+ fail_unless ! ( Colors ( 16 ) . next( ) == 4u8 ) ;
231+ fail_unless ! ( Colors ( 32 ) . next( ) == 5u8 ) ;
232+ fail_unless ! ( Colors ( 64 ) . next( ) == 6u8 ) ;
233+ fail_unless ! ( Colors ( 128 ) . next( ) == 7u8 ) ;
234+ fail_unless ! ( Colors ( 256 ) . next( ) == 8u8 ) ;
235+ fail_unless ! ( Colors ( 512 ) . next( ) == 9u8 ) ;
236+ fail_unless ! ( Colors ( 1024 ) . next( ) == 0u8 ) ;
237+ }
238+
239+ #[ test]
240+ fn colors_remove_works ( ) {
241+ // GIVEN
242+ let mut colors = Colors :: new ( 1 ) ;
243+
244+ // WHEN
245+ colors. remove ( 1 ) ;
246+
247+ // THEN
248+ fail_unless ! ( colors. next( ) == 2u8 ) ;
249+ }
250+
251+ #[ test]
252+ fn check_default_sudoku_solution ( ) {
253+ // GIVEN
254+ let mut sudoku = Sudoku :: from_vec ( & default_sudoku) ;
255+ let solution = Sudoku :: from_vec ( & default_solution) ;
256+
257+ // WHEN
258+ sudoku. solve ( ) ;
259+
260+ // THEN
261+ fail_unless ! ( sudoku. equal( & solution) ) ;
138262}
139263
140264fn main ( ) {
141- let args = os:: args ( ) ;
142- let grid = if vec:: len ( args) == 1 u {
143- // FIXME create sudoku inline since nested vec consts dont work yet
144- // (#3733)
145- let mut g = vec:: from_fn ( 10 u, |_i| {
146- vec:: from_elem ( 10 u, 0 as u8 )
147- } ) ;
148- g[ 0 ] [ 1 ] = 4u8 ;
149- g[ 0 ] [ 3 ] = 6u8 ;
150- g[ 0 ] [ 7 ] = 3u8 ;
151- g[ 0 ] [ 8 ] = 2u8 ;
152- g[ 1 ] [ 2 ] = 8u8 ;
153- g[ 1 ] [ 4 ] = 2u8 ;
154- g[ 2 ] [ 0 ] = 7u8 ;
155- g[ 2 ] [ 3 ] = 8u8 ;
156- g[ 3 ] [ 3 ] = 5u8 ;
157- g[ 4 ] [ 1 ] = 5u8 ;
158- g[ 4 ] [ 5 ] = 3u8 ;
159- g[ 4 ] [ 6 ] = 6u8 ;
160- g[ 5 ] [ 0 ] = 6u8 ;
161- g[ 5 ] [ 1 ] = 8u8 ;
162- g[ 5 ] [ 7 ] = 9u8 ;
163- g[ 6 ] [ 1 ] = 9u8 ;
164- g[ 6 ] [ 2 ] = 5u8 ;
165- g[ 6 ] [ 5 ] = 6u8 ;
166- g[ 6 ] [ 7 ] = 7u8 ;
167- g[ 7 ] [ 4 ] = 4u8 ;
168- g[ 7 ] [ 7 ] = 6u8 ;
169- g[ 8 ] [ 0 ] = 4u8 ;
170- g[ 8 ] [ 5 ] = 7u8 ;
171- g[ 8 ] [ 6 ] = 2u8 ;
172- g[ 8 ] [ 8 ] = 3u8 ;
173- grid_ctor ( g)
265+ let args = os:: args ( ) ;
266+ let use_default = vec:: len ( args) == 1 u;
267+ let mut sudoku = if use_default {
268+ Sudoku :: from_vec ( & default_sudoku)
174269 } else {
175- read_grid ( io:: stdin ( ) )
270+ Sudoku :: read ( io:: stdin ( ) )
176271 } ;
177- solve_grid ( copy grid ) ;
178- write_grid ( io:: stdout ( ) , grid ) ;
272+ sudoku . solve ( ) ;
273+ sudoku . write ( io:: stdout ( ) ) ;
179274}
180275
0 commit comments