12
12
13
13
extern mod std;
14
14
15
- use std:: bitv;
16
15
use core:: io:: { ReaderUtil , WriterUtil } ;
17
16
use core:: io;
17
+ use core:: unstable:: intrinsics:: cttz16;
18
18
19
19
// Computes a single solution to a given 9x9 sudoku
20
20
//
@@ -35,146 +35,241 @@ use core::io;
35
35
// internal type of sudoku grids
36
36
type grid = ~[ ~[ u8 ] ] ;
37
37
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
+ }
54
116
}
55
117
}
56
- return grid_ctor(g);
57
- }
58
118
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 {
62
120
if start_color < 10u8 {
63
121
// 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) ;
68
123
69
124
// drop colors already in use in neighbourhood
70
- drop_colors(copy g, copy avail, row, col);
125
+ self . drop_colors ( avail, row, col) ;
71
126
72
127
// 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;
79
131
}
80
- g [row][col] = 0u8;
132
+ self . grid [ row] [ col] = 0u8 ;
81
133
return false ;
82
134
}
83
135
84
136
// 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 ) {
93
138
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 */
96
141
}
97
142
98
143
// check same block fields
99
144
let row0 = ( row / 3u8 ) * 3u8 ;
100
145
let col0 = ( col / 3u8 ) * 3u8 ;
101
146
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] ) ; }
103
148
}
104
149
}
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
+ }
105
163
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 ;
111
172
}
112
173
}
113
174
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) ;
126
180
}
127
181
}
128
182
}
129
183
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) ) ;
138
262
}
139
263
140
264
fn 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)
174
269
} else {
175
- read_grid ( io:: stdin ( ) )
270
+ Sudoku :: read ( io:: stdin ( ) )
176
271
} ;
177
- solve_grid ( copy grid ) ;
178
- write_grid ( io:: stdout ( ) , grid ) ;
272
+ sudoku . solve ( ) ;
273
+ sudoku . write ( io:: stdout ( ) ) ;
179
274
}
180
275
0 commit comments