1
- // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1
+ // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2
2
// file at the top-level directory of this distribution and at
3
3
// http://rust-lang.org/COPYRIGHT.
4
4
//
8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
+ #![ feature( phase) ]
12
+ #[ phase( syntax) ] extern crate green;
13
+ extern crate sync;
14
+
15
+ use sync:: Arc ;
16
+
17
+ green_start ! ( main)
18
+
11
19
//
12
20
// Utilities.
13
21
//
14
22
15
-
16
23
// returns an infinite iterator of repeated applications of f to x,
17
24
// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
18
25
fn iterate < ' a , T > ( x : T , f: |& T |: ' a -> T ) -> Iterate <' a, T > {
@@ -93,7 +100,7 @@ fn transform(piece: Vec<(int, int)> , all: bool) -> Vec<Vec<(int, int)>> {
93
100
// Takes a piece with minimum coordinate (0, 0) (as generated by
94
101
// transform). Returns the corresponding mask if p translated by (dy,
95
102
// dx) is on the board.
96
- fn mask ( dy : int , dx : int , id : uint , p : & [ ( int , int ) ] ) -> Option < u64 > {
103
+ fn mask ( dy : int , dx : int , id : uint , p : & Vec < ( int , int ) > ) -> Option < u64 > {
97
104
let mut m = 1 << ( 50 + id) ;
98
105
for & ( y, x) in p. iter ( ) {
99
106
let x = x + dx + ( y + ( dy % 2 ) ) / 2 ;
@@ -105,7 +112,7 @@ fn mask(dy: int, dx: int, id: uint, p: &[(int, int)]) -> Option<u64> {
105
112
Some ( m)
106
113
}
107
114
108
- // Makes every possible masks. masks[id][i ] correspond to every
115
+ // Makes every possible masks. masks[i][id ] correspond to every
109
116
// possible masks for piece with identifier id with minimum coordinate
110
117
// (i/5, i%5).
111
118
fn make_masks ( ) -> Vec < Vec < Vec < u64 > > > {
@@ -120,168 +127,182 @@ fn make_masks() -> Vec<Vec<Vec<u64> > > {
120
127
vec!( ( 0 , 0 ) , ( 0 , 1 ) , ( 0 , 2 ) , ( 1 , 0 ) , ( 1 , 2 ) ) ,
121
128
vec!( ( 0 , 0 ) , ( 0 , 1 ) , ( 0 , 2 ) , ( 1 , 2 ) , ( 1 , 3 ) ) ,
122
129
vec!( ( 0 , 0 ) , ( 0 , 1 ) , ( 0 , 2 ) , ( 0 , 3 ) , ( 1 , 2 ) ) ) ;
123
- let mut res = Vec :: new ( ) ;
124
- for ( id, p) in pieces. move_iter ( ) . enumerate ( ) {
125
- // To break the central symetry of the problem, every
126
- // transformation must be taken except for one piece (piece 3
127
- // here).
128
- let trans = transform ( p, id != 3 ) ;
129
- let mut cur_piece = Vec :: new ( ) ;
130
- for dy in range ( 0 , 10 ) {
131
- for dx in range ( 0 , 5 ) {
132
- let masks =
133
- trans. iter ( )
134
- . filter_map ( |t| mask ( dy, dx, id, t. as_slice ( ) ) )
135
- . collect ( ) ;
136
- cur_piece. push ( masks) ;
137
- }
138
- }
139
- res. push ( cur_piece) ;
140
- }
141
- res
130
+
131
+ // To break the central symetry of the problem, every
132
+ // transformation must be taken except for one piece (piece 3
133
+ // here).
134
+ let transforms: Vec < Vec < Vec < ( int , int ) > > > =
135
+ pieces. move_iter ( ) . enumerate ( )
136
+ . map ( |( id, p) | transform ( p, id != 3 ) )
137
+ . collect ( ) ;
138
+
139
+ range ( 0 , 50 ) . map ( |yx| {
140
+ transforms. iter ( ) . enumerate ( ) . map ( |( id, t) | {
141
+ t. iter ( ) . filter_map ( |p| mask ( yx / 5 , yx % 5 , id, p) ) . collect ( )
142
+ } ) . collect ( )
143
+ } ) . collect ( )
142
144
}
143
145
144
146
// Check if all coordinates can be covered by an unused piece and that
145
147
// all unused piece can be placed on the board.
146
- fn is_board_unfeasible ( board : u64 , masks : & [ Vec < Vec < u64 > > ] ) -> bool {
148
+ fn is_board_unfeasible ( board : u64 , masks : & Vec < Vec < Vec < u64 > > > ) -> bool {
147
149
let mut coverable = board;
148
- for i in range ( 0 , 50 ) . filter ( |& i| board & 1 << i == 0 ) {
149
- for ( cur_id, pos_masks) in masks. iter ( ) . enumerate ( ) {
150
- if board & 1 << ( 50 + cur_id) != 0 { continue ; }
151
- for & cur_m in pos_masks. get ( i as uint ) . iter ( ) {
152
- if cur_m & board == 0 { coverable |= cur_m; }
150
+ for ( i, masks_at) in masks. iter ( ) . enumerate ( ) {
151
+ if board & 1 << i != 0 { continue ; }
152
+ for ( cur_id, pos_masks) in masks_at. iter ( ) . enumerate ( ) {
153
+ if board & 1 << ( 50 + cur_id) != 0 { continue ; }
154
+ for & cur_m in pos_masks. iter ( ) {
155
+ if cur_m & board != 0 { continue ; }
156
+ coverable |= cur_m;
157
+ // if every coordinates can be covered and every
158
+ // piece can be used.
159
+ if coverable == ( 1 << 60 ) - 1 { return false ; }
153
160
}
154
161
}
155
- if coverable & ( 1 << i) == 0 { return true ; }
162
+ if coverable & 1 << i == 0 { return true ; }
156
163
}
157
- // check if every coordinates can be covered and every piece can
158
- // be used.
159
- coverable != ( 1 << 60 ) - 1
164
+ true
160
165
}
161
166
162
167
// Filter the masks that we can prove to result to unfeasible board.
163
- fn filter_masks ( masks : & [ Vec < Vec < u64 > > ] ) -> Vec < Vec < Vec < u64 > > > {
164
- masks. iter ( ) . map (
165
- |p| p . iter ( ) . map (
166
- |p| p . iter ( )
167
- . map ( |& m| m)
168
+ fn filter_masks ( masks : & mut Vec < Vec < Vec < u64 > > > ) {
169
+ for i in range ( 0 , masks. len ( ) ) {
170
+ for j in range ( 0 , masks . get ( i ) . len ( ) ) {
171
+ * masks . get_mut ( i ) . get_mut ( j ) =
172
+ masks . get ( i ) . get ( j ) . iter ( ) . map ( |& m| m)
168
173
. filter ( |& m| !is_board_unfeasible ( m, masks) )
169
- . collect ( ) )
170
- . collect ( ) )
171
- . collect ( )
174
+ . collect ( ) ;
175
+ }
176
+ }
172
177
}
173
178
174
179
// Gets the identifier of a mask.
175
180
fn get_id ( m : u64 ) -> u8 {
176
- for id in range ( 0 , 10 ) {
177
- if m & ( 1 << ( id + 50 ) ) != 0 { return id as u8 ; }
181
+ for id in range ( 0u8 , 10 ) {
182
+ if m & ( 1 << ( id + 50 ) ) != 0 { return id; }
178
183
}
179
184
fail ! ( "{:016x} does not have a valid identifier" , m) ;
180
185
}
181
186
182
187
// Converts a list of mask to a ~str.
183
- fn to_utf8 ( raw_sol : & List < u64 > ) -> ~ str {
184
- let mut sol: Vec < u8 > = Vec :: from_elem ( 50 , '.' as u8 ) ;
188
+ fn to_vec ( raw_sol : & List < u64 > ) -> Vec < u8 > {
189
+ let mut sol = Vec :: from_elem ( 50 , '.' as u8 ) ;
185
190
for & m in raw_sol. iter ( ) {
186
- let id = get_id ( m) ;
187
- for i in range ( 0 , 50 ) {
191
+ let id = '0' as u8 + get_id ( m) ;
192
+ for i in range ( 0 u , 50 ) {
188
193
if m & 1 << i != 0 {
189
- * sol. get_mut ( i as uint ) = '0' as u8 + id;
194
+ * sol. get_mut ( i) = id;
190
195
}
191
196
}
192
197
}
193
- std :: str :: from_utf8 ( sol. as_slice ( ) ) . unwrap ( ) . to_owned ( )
198
+ sol
194
199
}
195
200
196
201
// Prints a solution in ~str form.
197
- fn print_sol ( sol : & str ) {
198
- for ( i, c) in sol. chars ( ) . enumerate ( ) {
202
+ fn print_sol ( sol : & Vec < u8 > ) {
203
+ for ( i, c) in sol. iter ( ) . enumerate ( ) {
199
204
if ( i) % 5 == 0 { println ! ( "" ) ; }
200
205
if ( i + 5 ) % 10 == 0 { print ! ( " " ) ; }
201
- print ! ( "{} " , c ) ;
206
+ print ! ( "{} " , * c as char ) ;
202
207
}
203
208
println ! ( "" ) ;
204
209
}
205
210
206
211
// The data managed during the search
207
212
struct Data {
208
- // If more than stop_after is found, stop the search.
209
- stop_after : int ,
210
213
// Number of solution found.
211
214
nb : int ,
212
215
// Lexicographically minimal solution found.
213
- min : ~ str ,
216
+ min : Vec < u8 > ,
214
217
// Lexicographically maximal solution found.
215
- max : ~str
218
+ max : Vec < u8 >
219
+ }
220
+ impl Data {
221
+ fn new ( ) -> Data {
222
+ Data { nb : 0 , min : vec ! ( ) , max : vec ! ( ) }
223
+ }
224
+ fn reduce_from ( & mut self , other : Data ) {
225
+ self . nb += other. nb ;
226
+ let Data { min : min, max : max, ..} = other;
227
+ if min < self . min { self . min = min; }
228
+ if max > self . max { self . max = max; }
229
+ }
216
230
}
217
231
218
232
// Records a new found solution. Returns false if the search must be
219
233
// stopped.
220
- fn handle_sol ( raw_sol : & List < u64 > , data : & mut Data ) -> bool {
234
+ fn handle_sol ( raw_sol : & List < u64 > , data : & mut Data ) {
221
235
// because we break the symetry, 2 solutions correspond to a call
222
236
// to this method: the normal solution, and the same solution in
223
237
// reverse order, i.e. the board rotated by half a turn.
224
238
data. nb += 2 ;
225
- let sol1 = to_utf8 ( raw_sol) ;
226
- let sol2: ~ str = sol1. chars ( ) . rev ( ) . collect ( ) ;
239
+ let sol1 = to_vec ( raw_sol) ;
240
+ let sol2: Vec < u8 > = sol1. iter ( ) . rev ( ) . map ( |x| * x ) . collect ( ) ;
227
241
228
242
if data. nb == 2 {
229
243
data. min = sol1. clone ( ) ;
230
244
data. max = sol1. clone ( ) ;
231
245
}
232
246
233
- if sol1 < data. min { data. min = sol1. clone ( ) ; }
234
- if sol2 < data. min { data. min = sol2. clone ( ) ; }
235
- if sol1 > data. max { data. max = sol1; }
236
- if sol2 > data. max { data. max = sol2; }
237
- data. nb < data. stop_after
247
+ if sol1 < data. min { data. min = sol1; }
248
+ else if sol1 > data. max { data. max = sol1; }
249
+ if sol2 < data. min { data. min = sol2; }
250
+ else if sol2 > data. max { data. max = sol2; }
238
251
}
239
252
240
- // Search for every solutions. Returns false if the search was
241
- // stopped before the end.
242
253
fn search (
243
- masks : & [ Vec < Vec < u64 > > ] ,
254
+ masks : & Vec < Vec < Vec < u64 > > > ,
244
255
board : u64 ,
245
- mut i : int ,
256
+ mut i : uint ,
246
257
cur : List < u64 > ,
247
258
data : & mut Data )
248
- -> bool
249
259
{
250
260
// Search for the lesser empty coordinate.
251
261
while board & ( 1 << i) != 0 && i < 50 { i += 1 ; }
252
262
// the board is full: a solution is found.
253
263
if i >= 50 { return handle_sol ( & cur, data) ; }
264
+ let masks_at = masks. get ( i) ;
254
265
255
266
// for every unused piece
256
- for id in range ( 0 , 10 ) . filter ( |id| board & ( 1 << ( id + 50 ) ) == 0 ) {
267
+ for id in range ( 0 u , 10 ) . filter ( |id| board & ( 1 << ( id + 50 ) ) == 0 ) {
257
268
// for each mask that fits on the board
258
- for & m in masks[ id as uint ] . get ( i as uint )
259
- . iter ( )
260
- . filter ( |& m| board & * m == 0 ) {
269
+ for & m in masks_at. get ( id) . iter ( ) . filter ( |& m| board & * m == 0 ) {
261
270
// This check is too costy.
262
271
//if is_board_unfeasible(board | m, masks) {continue;}
263
- if !search ( masks, board | m, i + 1 , Cons ( m, & cur) , data) {
264
- return false ;
265
- }
272
+ search ( masks, board | m, i + 1 , Cons ( m, & cur) , data) ;
266
273
}
267
274
}
268
- return true ;
275
+ }
276
+
277
+ fn par_search ( masks : Vec < Vec < Vec < u64 > > > ) -> Data {
278
+ let masks = Arc :: new ( masks) ;
279
+ let ( tx, rx) = channel ( ) ;
280
+
281
+ // launching the search in parallel on every masks at minimum
282
+ // coordinate (0,0)
283
+ for & m in masks. get ( 0 ) . iter ( ) . flat_map ( |masks_pos| masks_pos. iter ( ) ) {
284
+ let masks = masks. clone ( ) ;
285
+ let tx = tx. clone ( ) ;
286
+ spawn ( proc ( ) {
287
+ let mut data = Data :: new ( ) ;
288
+ search ( & * masks, m, 1 , Cons ( m, & Nil ) , & mut data) ;
289
+ tx. send ( data) ;
290
+ } ) ;
291
+ }
292
+
293
+ // collecting the results
294
+ drop ( tx) ;
295
+ let mut data = rx. recv ( ) ;
296
+ for d in rx. iter ( ) { data. reduce_from ( d) ; }
297
+ data
269
298
}
270
299
271
300
fn main ( ) {
272
- let args = std:: os:: args ( ) ;
273
- let args = args. as_slice ( ) ;
274
- let stop_after = if args. len ( ) <= 1 {
275
- 2098
276
- } else {
277
- from_str ( args[ 1 ] ) . unwrap ( )
278
- } ;
279
- let masks = make_masks ( ) ;
280
- let masks = filter_masks ( masks. as_slice ( ) ) ;
281
- let mut data = Data { stop_after : stop_after, nb : 0 , min : "" . to_owned ( ) , max : "" . to_owned ( ) } ;
282
- search ( masks. as_slice ( ) , 0 , 0 , Nil , & mut data) ;
301
+ let mut masks = make_masks ( ) ;
302
+ filter_masks ( & mut masks) ;
303
+ let data = par_search ( masks) ;
283
304
println ! ( "{} solutions found" , data. nb) ;
284
- print_sol ( data. min ) ;
285
- print_sol ( data. max ) ;
305
+ print_sol ( & data. min ) ;
306
+ print_sol ( & data. max ) ;
286
307
println ! ( "" ) ;
287
308
}
0 commit comments