1- // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
1+ // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
22// file at the top-level directory of this distribution and at
33// http://rust-lang.org/COPYRIGHT.
44//
88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11+ #![ feature( phase) ]
12+ #[ phase( syntax) ] extern crate green;
13+ extern crate sync;
14+
15+ use sync:: Arc ;
16+
17+ green_start ! ( main)
18+
1119//
1220// Utilities.
1321//
1422
15-
1623// returns an infinite iterator of repeated applications of f to x,
1724// i.e. [x, f(x), f(f(x)), ...], as haskell iterate function.
1825fn 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)>> {
93100// Takes a piece with minimum coordinate (0, 0) (as generated by
94101// transform). Returns the corresponding mask if p translated by (dy,
95102// 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 > {
97104 let mut m = 1 << ( 50 + id) ;
98105 for & ( y, x) in p. iter ( ) {
99106 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> {
105112 Some ( m)
106113}
107114
108- // Makes every possible masks. masks[id][i ] correspond to every
115+ // Makes every possible masks. masks[i][id ] correspond to every
109116// possible masks for piece with identifier id with minimum coordinate
110117// (i/5, i%5).
111118fn make_masks ( ) -> Vec < Vec < Vec < u64 > > > {
@@ -120,168 +127,182 @@ fn make_masks() -> Vec<Vec<Vec<u64> > > {
120127 vec!( ( 0 , 0 ) , ( 0 , 1 ) , ( 0 , 2 ) , ( 1 , 0 ) , ( 1 , 2 ) ) ,
121128 vec!( ( 0 , 0 ) , ( 0 , 1 ) , ( 0 , 2 ) , ( 1 , 2 ) , ( 1 , 3 ) ) ,
122129 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 ( )
142144}
143145
144146// Check if all coordinates can be covered by an unused piece and that
145147// 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 {
147149 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 ; }
153160 }
154161 }
155- if coverable & ( 1 << i) == 0 { return true ; }
162+ if coverable & 1 << i == 0 { return true ; }
156163 }
157- // check if every coordinates can be covered and every piece can
158- // be used.
159- coverable != ( 1 << 60 ) - 1
164+ true
160165}
161166
162167// 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)
168173 . filter ( |& m| !is_board_unfeasible ( m, masks) )
169- . collect ( ) )
170- . collect ( ) )
171- . collect ( )
174+ . collect ( ) ;
175+ }
176+ }
172177}
173178
174179// Gets the identifier of a mask.
175180fn 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; }
178183 }
179184 fail ! ( "{:016x} does not have a valid identifier" , m) ;
180185}
181186
182187// 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 ) ;
185190 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 ) {
188193 if m & 1 << i != 0 {
189- * sol. get_mut ( i as uint ) = '0' as u8 + id;
194+ * sol. get_mut ( i) = id;
190195 }
191196 }
192197 }
193- std :: str :: from_utf8 ( sol. as_slice ( ) ) . unwrap ( ) . to_owned ( )
198+ sol
194199}
195200
196201// 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 ( ) {
199204 if ( i) % 5 == 0 { println ! ( "" ) ; }
200205 if ( i + 5 ) % 10 == 0 { print ! ( " " ) ; }
201- print ! ( "{} " , c ) ;
206+ print ! ( "{} " , * c as char ) ;
202207 }
203208 println ! ( "" ) ;
204209}
205210
206211// The data managed during the search
207212struct Data {
208- // If more than stop_after is found, stop the search.
209- stop_after : int ,
210213 // Number of solution found.
211214 nb : int ,
212215 // Lexicographically minimal solution found.
213- min : ~ str ,
216+ min : Vec < u8 > ,
214217 // 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+ }
216230}
217231
218232// Records a new found solution. Returns false if the search must be
219233// stopped.
220- fn handle_sol ( raw_sol : & List < u64 > , data : & mut Data ) -> bool {
234+ fn handle_sol ( raw_sol : & List < u64 > , data : & mut Data ) {
221235 // because we break the symetry, 2 solutions correspond to a call
222236 // to this method: the normal solution, and the same solution in
223237 // reverse order, i.e. the board rotated by half a turn.
224238 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 ( ) ;
227241
228242 if data. nb == 2 {
229243 data. min = sol1. clone ( ) ;
230244 data. max = sol1. clone ( ) ;
231245 }
232246
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; }
238251}
239252
240- // Search for every solutions. Returns false if the search was
241- // stopped before the end.
242253fn search (
243- masks : & [ Vec < Vec < u64 > > ] ,
254+ masks : & Vec < Vec < Vec < u64 > > > ,
244255 board : u64 ,
245- mut i : int ,
256+ mut i : uint ,
246257 cur : List < u64 > ,
247258 data : & mut Data )
248- -> bool
249259{
250260 // Search for the lesser empty coordinate.
251261 while board & ( 1 << i) != 0 && i < 50 { i += 1 ; }
252262 // the board is full: a solution is found.
253263 if i >= 50 { return handle_sol ( & cur, data) ; }
264+ let masks_at = masks. get ( i) ;
254265
255266 // 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 ) {
257268 // 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 ) {
261270 // This check is too costy.
262271 //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) ;
266273 }
267274 }
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
269298}
270299
271300fn 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) ;
283304 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 ) ;
286307 println ! ( "" ) ;
287308}
0 commit comments