1 |
700 |
jeremybenn |
/*
|
2 |
|
|
Redistribution and use in source and binary forms, with or without
|
3 |
|
|
modification, are permitted provided that the following conditions are met:
|
4 |
|
|
|
5 |
|
|
* Redistributions of source code must retain the above copyright
|
6 |
|
|
notice, this list of conditions and the following disclaimer.
|
7 |
|
|
|
8 |
|
|
* Redistributions in binary form must reproduce the above copyright
|
9 |
|
|
notice, this list of conditions and the following disclaimer in the
|
10 |
|
|
documentation and/or other materials provided with the distribution.
|
11 |
|
|
|
12 |
|
|
* Neither the name of "The Computer Language Benchmarks Game" nor the
|
13 |
|
|
name of "The Computer Language Shootout Benchmarks" nor the names of
|
14 |
|
|
its contributors may be used to endorse or promote products derived
|
15 |
|
|
from this software without specific prior written permission.
|
16 |
|
|
|
17 |
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18 |
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19 |
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20 |
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
21 |
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
22 |
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
23 |
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
24 |
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
25 |
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
26 |
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
|
|
POSSIBILITY OF SUCH DAMAGE.
|
28 |
|
|
*/
|
29 |
|
|
|
30 |
|
|
/* The Computer Language Benchmarks Game
|
31 |
|
|
* http://shootout.alioth.debian.org/
|
32 |
|
|
*
|
33 |
|
|
* contributed by Christian Vosteen
|
34 |
|
|
*/
|
35 |
|
|
|
36 |
|
|
#include <stdlib.h>
|
37 |
|
|
#include <stdio.h>
|
38 |
|
|
#define TRUE 1
|
39 |
|
|
#define FALSE 0
|
40 |
|
|
|
41 |
|
|
/* The board is a 50 cell hexagonal pattern. For . . . . .
|
42 |
|
|
* maximum speed the board will be implemented as . . . . .
|
43 |
|
|
* 50 bits, which will fit into a 64 bit long long . . . . .
|
44 |
|
|
* int. . . . . .
|
45 |
|
|
* . . . . .
|
46 |
|
|
* I will represent 0's as empty cells and 1's . . . . .
|
47 |
|
|
* as full cells. . . . . .
|
48 |
|
|
* . . . . .
|
49 |
|
|
* . . . . .
|
50 |
|
|
* . . . . .
|
51 |
|
|
*/
|
52 |
|
|
|
53 |
|
|
unsigned long long board = 0xFFFC000000000000ULL;
|
54 |
|
|
|
55 |
|
|
/* The puzzle pieces must be specified by the path followed
|
56 |
|
|
* from one end to the other along 12 hexagonal directions.
|
57 |
|
|
*
|
58 |
|
|
* Piece 0 Piece 1 Piece 2 Piece 3 Piece 4
|
59 |
|
|
*
|
60 |
|
|
* O O O O O O O O O O O O O O O
|
61 |
|
|
* O O O O O O O
|
62 |
|
|
* O O O
|
63 |
|
|
*
|
64 |
|
|
* Piece 5 Piece 6 Piece 7 Piece 8 Piece 9
|
65 |
|
|
*
|
66 |
|
|
* O O O O O O O O O O O O O
|
67 |
|
|
* O O O O O O O O O
|
68 |
|
|
* O O O
|
69 |
|
|
*
|
70 |
|
|
* I had to make it 12 directions because I wanted all of the
|
71 |
|
|
* piece definitions to fit into the same size arrays. It is
|
72 |
|
|
* not possible to define piece 4 in terms of the 6 cardinal
|
73 |
|
|
* directions in 4 moves.
|
74 |
|
|
*/
|
75 |
|
|
|
76 |
|
|
#define E 0
|
77 |
|
|
#define ESE 1
|
78 |
|
|
#define SE 2
|
79 |
|
|
#define S 3
|
80 |
|
|
#define SW 4
|
81 |
|
|
#define WSW 5
|
82 |
|
|
#define W 6
|
83 |
|
|
#define WNW 7
|
84 |
|
|
#define NW 8
|
85 |
|
|
#define N 9
|
86 |
|
|
#define NE 10
|
87 |
|
|
#define ENE 11
|
88 |
|
|
#define PIVOT 12
|
89 |
|
|
|
90 |
|
|
char piece_def[10][4] = {
|
91 |
|
|
{ E, E, E, SE},
|
92 |
|
|
{ SE, E, NE, E},
|
93 |
|
|
{ E, E, SE, SW},
|
94 |
|
|
{ E, E, SW, SE},
|
95 |
|
|
{ SE, E, NE, S},
|
96 |
|
|
{ E, E, SW, E},
|
97 |
|
|
{ E, SE, SE, NE},
|
98 |
|
|
{ E, SE, SE, W},
|
99 |
|
|
{ E, SE, E, E},
|
100 |
|
|
{ E, E, E, SW}
|
101 |
|
|
};
|
102 |
|
|
|
103 |
|
|
|
104 |
|
|
/* To minimize the amount of work done in the recursive solve function below,
|
105 |
|
|
* I'm going to allocate enough space for all legal rotations of each piece
|
106 |
|
|
* at each position on the board. That's 10 pieces x 50 board positions x
|
107 |
|
|
* 12 rotations. However, not all 12 rotations will fit on every cell, so
|
108 |
|
|
* I'll have to keep count of the actual number that do.
|
109 |
|
|
* The pieces are going to be unsigned long long ints just like the board so
|
110 |
|
|
* they can be bitwise-anded with the board to determine if they fit.
|
111 |
|
|
* I'm also going to record the next possible open cell for each piece and
|
112 |
|
|
* location to reduce the burden on the solve function.
|
113 |
|
|
*/
|
114 |
|
|
unsigned long long pieces[10][50][12];
|
115 |
|
|
int piece_counts[10][50];
|
116 |
|
|
char next_cell[10][50][12];
|
117 |
|
|
|
118 |
|
|
/* Returns the direction rotated 60 degrees clockwise */
|
119 |
|
|
char rotate(char dir) {
|
120 |
|
|
return (dir + 2) % PIVOT;
|
121 |
|
|
}
|
122 |
|
|
|
123 |
|
|
/* Returns the direction flipped on the horizontal axis */
|
124 |
|
|
char flip(char dir) {
|
125 |
|
|
return (PIVOT - dir) % PIVOT;
|
126 |
|
|
}
|
127 |
|
|
|
128 |
|
|
|
129 |
|
|
/* Returns the new cell index from the specified cell in the
|
130 |
|
|
* specified direction. The index is only valid if the
|
131 |
|
|
* starting cell and direction have been checked by the
|
132 |
|
|
* out_of_bounds function first.
|
133 |
|
|
*/
|
134 |
|
|
char shift(char cell, char dir) {
|
135 |
|
|
switch(dir) {
|
136 |
|
|
case E:
|
137 |
|
|
return cell + 1;
|
138 |
|
|
case ESE:
|
139 |
|
|
if((cell / 5) % 2)
|
140 |
|
|
return cell + 7;
|
141 |
|
|
else
|
142 |
|
|
return cell + 6;
|
143 |
|
|
case SE:
|
144 |
|
|
if((cell / 5) % 2)
|
145 |
|
|
return cell + 6;
|
146 |
|
|
else
|
147 |
|
|
return cell + 5;
|
148 |
|
|
case S:
|
149 |
|
|
return cell + 10;
|
150 |
|
|
case SW:
|
151 |
|
|
if((cell / 5) % 2)
|
152 |
|
|
return cell + 5;
|
153 |
|
|
else
|
154 |
|
|
return cell + 4;
|
155 |
|
|
case WSW:
|
156 |
|
|
if((cell / 5) % 2)
|
157 |
|
|
return cell + 4;
|
158 |
|
|
else
|
159 |
|
|
return cell + 3;
|
160 |
|
|
case W:
|
161 |
|
|
return cell - 1;
|
162 |
|
|
case WNW:
|
163 |
|
|
if((cell / 5) % 2)
|
164 |
|
|
return cell - 6;
|
165 |
|
|
else
|
166 |
|
|
return cell - 7;
|
167 |
|
|
case NW:
|
168 |
|
|
if((cell / 5) % 2)
|
169 |
|
|
return cell - 5;
|
170 |
|
|
else
|
171 |
|
|
return cell - 6;
|
172 |
|
|
case N:
|
173 |
|
|
return cell - 10;
|
174 |
|
|
case NE:
|
175 |
|
|
if((cell / 5) % 2)
|
176 |
|
|
return cell - 4;
|
177 |
|
|
else
|
178 |
|
|
return cell - 5;
|
179 |
|
|
case ENE:
|
180 |
|
|
if((cell / 5) % 2)
|
181 |
|
|
return cell - 3;
|
182 |
|
|
else
|
183 |
|
|
return cell - 4;
|
184 |
|
|
default:
|
185 |
|
|
return cell;
|
186 |
|
|
}
|
187 |
|
|
}
|
188 |
|
|
|
189 |
|
|
/* Returns wether the specified cell and direction will land outside
|
190 |
|
|
* of the board. Used to determine if a piece is at a legal board
|
191 |
|
|
* location or not.
|
192 |
|
|
*/
|
193 |
|
|
char out_of_bounds(char cell, char dir) {
|
194 |
|
|
char i;
|
195 |
|
|
switch(dir) {
|
196 |
|
|
case E:
|
197 |
|
|
return cell % 5 == 4;
|
198 |
|
|
case ESE:
|
199 |
|
|
i = cell % 10;
|
200 |
|
|
return i == 4 || i == 8 || i == 9 || cell >= 45;
|
201 |
|
|
case SE:
|
202 |
|
|
return cell % 10 == 9 || cell >= 45;
|
203 |
|
|
case S:
|
204 |
|
|
return cell >= 40;
|
205 |
|
|
case SW:
|
206 |
|
|
return cell % 10 == 0 || cell >= 45;
|
207 |
|
|
case WSW:
|
208 |
|
|
i = cell % 10;
|
209 |
|
|
return i == 0 || i == 1 || i == 5 || cell >= 45;
|
210 |
|
|
case W:
|
211 |
|
|
return cell % 5 == 0;
|
212 |
|
|
case WNW:
|
213 |
|
|
i = cell % 10;
|
214 |
|
|
return i == 0 || i == 1 || i == 5 || cell < 5;
|
215 |
|
|
case NW:
|
216 |
|
|
return cell % 10 == 0 || cell < 5;
|
217 |
|
|
case N:
|
218 |
|
|
return cell < 10;
|
219 |
|
|
case NE:
|
220 |
|
|
return cell % 10 == 9 || cell < 5;
|
221 |
|
|
case ENE:
|
222 |
|
|
i = cell % 10;
|
223 |
|
|
return i == 4 || i == 8 || i == 9 || cell < 5;
|
224 |
|
|
default:
|
225 |
|
|
return FALSE;
|
226 |
|
|
}
|
227 |
|
|
}
|
228 |
|
|
|
229 |
|
|
/* Rotate a piece 60 degrees clockwise */
|
230 |
|
|
void rotate_piece(int piece) {
|
231 |
|
|
int i;
|
232 |
|
|
for(i = 0; i < 4; i++)
|
233 |
|
|
piece_def[piece][i] = rotate(piece_def[piece][i]);
|
234 |
|
|
}
|
235 |
|
|
|
236 |
|
|
/* Flip a piece along the horizontal axis */
|
237 |
|
|
void flip_piece(int piece) {
|
238 |
|
|
int i;
|
239 |
|
|
for(i = 0; i < 4; i++)
|
240 |
|
|
piece_def[piece][i] = flip(piece_def[piece][i]);
|
241 |
|
|
}
|
242 |
|
|
|
243 |
|
|
/* Convenience function to quickly calculate all of the indices for a piece */
|
244 |
|
|
void calc_cell_indices(char *cell, int piece, char index) {
|
245 |
|
|
cell[0] = index;
|
246 |
|
|
cell[1] = shift(cell[0], piece_def[piece][0]);
|
247 |
|
|
cell[2] = shift(cell[1], piece_def[piece][1]);
|
248 |
|
|
cell[3] = shift(cell[2], piece_def[piece][2]);
|
249 |
|
|
cell[4] = shift(cell[3], piece_def[piece][3]);
|
250 |
|
|
}
|
251 |
|
|
|
252 |
|
|
/* Convenience function to quickly calculate if a piece fits on the board */
|
253 |
|
|
int cells_fit_on_board(char *cell, int piece) {
|
254 |
|
|
return (!out_of_bounds(cell[0], piece_def[piece][0]) &&
|
255 |
|
|
!out_of_bounds(cell[1], piece_def[piece][1]) &&
|
256 |
|
|
!out_of_bounds(cell[2], piece_def[piece][2]) &&
|
257 |
|
|
!out_of_bounds(cell[3], piece_def[piece][3]));
|
258 |
|
|
}
|
259 |
|
|
|
260 |
|
|
/* Returns the lowest index of the cells of a piece.
|
261 |
|
|
* I use the lowest index that a piece occupies as the index for looking up
|
262 |
|
|
* the piece in the solve function.
|
263 |
|
|
*/
|
264 |
|
|
char minimum_of_cells(char *cell) {
|
265 |
|
|
char minimum = cell[0];
|
266 |
|
|
minimum = cell[1] < minimum ? cell[1] : minimum;
|
267 |
|
|
minimum = cell[2] < minimum ? cell[2] : minimum;
|
268 |
|
|
minimum = cell[3] < minimum ? cell[3] : minimum;
|
269 |
|
|
minimum = cell[4] < minimum ? cell[4] : minimum;
|
270 |
|
|
return minimum;
|
271 |
|
|
}
|
272 |
|
|
|
273 |
|
|
/* Calculate the lowest possible open cell if the piece is placed on the board.
|
274 |
|
|
* Used to later reduce the amount of time searching for open cells in the
|
275 |
|
|
* solve function.
|
276 |
|
|
*/
|
277 |
|
|
char first_empty_cell(char *cell, char minimum) {
|
278 |
|
|
char first_empty = minimum;
|
279 |
|
|
while(first_empty == cell[0] || first_empty == cell[1] ||
|
280 |
|
|
first_empty == cell[2] || first_empty == cell[3] ||
|
281 |
|
|
first_empty == cell[4])
|
282 |
|
|
first_empty++;
|
283 |
|
|
return first_empty;
|
284 |
|
|
}
|
285 |
|
|
|
286 |
|
|
/* Generate the unsigned long long int that will later be anded with the
|
287 |
|
|
* board to determine if it fits.
|
288 |
|
|
*/
|
289 |
|
|
unsigned long long bitmask_from_cells(char *cell) {
|
290 |
|
|
unsigned long long piece_mask = 0ULL;
|
291 |
|
|
int i;
|
292 |
|
|
for(i = 0; i < 5; i++)
|
293 |
|
|
piece_mask |= 1ULL << cell[i];
|
294 |
|
|
return piece_mask;
|
295 |
|
|
}
|
296 |
|
|
|
297 |
|
|
/* Record the piece and other important information in arrays that will
|
298 |
|
|
* later be used by the solve function.
|
299 |
|
|
*/
|
300 |
|
|
void record_piece(int piece, int minimum, char first_empty,
|
301 |
|
|
unsigned long long piece_mask) {
|
302 |
|
|
pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask;
|
303 |
|
|
next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty;
|
304 |
|
|
piece_counts[piece][minimum]++;
|
305 |
|
|
}
|
306 |
|
|
|
307 |
|
|
|
308 |
|
|
/* Fill the entire board going cell by cell. If any cells are "trapped"
|
309 |
|
|
* they will be left alone.
|
310 |
|
|
*/
|
311 |
|
|
void fill_contiguous_space(char *board, int index) {
|
312 |
|
|
if(board[index] == 1)
|
313 |
|
|
return;
|
314 |
|
|
board[index] = 1;
|
315 |
|
|
if(!out_of_bounds(index, E))
|
316 |
|
|
fill_contiguous_space(board, shift(index, E));
|
317 |
|
|
if(!out_of_bounds(index, SE))
|
318 |
|
|
fill_contiguous_space(board, shift(index, SE));
|
319 |
|
|
if(!out_of_bounds(index, SW))
|
320 |
|
|
fill_contiguous_space(board, shift(index, SW));
|
321 |
|
|
if(!out_of_bounds(index, W))
|
322 |
|
|
fill_contiguous_space(board, shift(index, W));
|
323 |
|
|
if(!out_of_bounds(index, NW))
|
324 |
|
|
fill_contiguous_space(board, shift(index, NW));
|
325 |
|
|
if(!out_of_bounds(index, NE))
|
326 |
|
|
fill_contiguous_space(board, shift(index, NE));
|
327 |
|
|
}
|
328 |
|
|
|
329 |
|
|
|
330 |
|
|
/* To thin the number of pieces, I calculate if any of them trap any empty
|
331 |
|
|
* cells at the edges. There are only a handful of exceptions where the
|
332 |
|
|
* the board can be solved with the trapped cells. For example: piece 8 can
|
333 |
|
|
* trap 5 cells in the corner, but piece 3 can fit in those cells, or piece 0
|
334 |
|
|
* can split the board in half where both halves are viable.
|
335 |
|
|
*/
|
336 |
|
|
int has_island(char *cell, int piece) {
|
337 |
|
|
char temp_board[50];
|
338 |
|
|
char c;
|
339 |
|
|
int i;
|
340 |
|
|
for(i = 0; i < 50; i++)
|
341 |
|
|
temp_board[i] = 0;
|
342 |
|
|
for(i = 0; i < 5; i++)
|
343 |
|
|
temp_board[((int)cell[i])] = 1;
|
344 |
|
|
i = 49;
|
345 |
|
|
while(temp_board[i] == 1)
|
346 |
|
|
i--;
|
347 |
|
|
fill_contiguous_space(temp_board, i);
|
348 |
|
|
c = 0;
|
349 |
|
|
for(i = 0; i < 50; i++)
|
350 |
|
|
if(temp_board[i] == 0)
|
351 |
|
|
c++;
|
352 |
|
|
if(c == 0 || (c == 5 && piece == 8) || (c == 40 && piece == 8) ||
|
353 |
|
|
(c % 5 == 0 && piece == 0))
|
354 |
|
|
return FALSE;
|
355 |
|
|
else
|
356 |
|
|
return TRUE;
|
357 |
|
|
}
|
358 |
|
|
|
359 |
|
|
|
360 |
|
|
/* Calculate all six rotations of the specified piece at the specified index.
|
361 |
|
|
* We calculate only half of piece 3's rotations. This is because any solution
|
362 |
|
|
* found has an identical solution rotated 180 degrees. Thus we can reduce the
|
363 |
|
|
* number of attempted pieces in the solve algorithm by not including the 180-
|
364 |
|
|
* degree-rotated pieces of ONE of the pieces. I chose piece 3 because it gave
|
365 |
|
|
* me the best time ;)
|
366 |
|
|
*/
|
367 |
|
|
void calc_six_rotations(char piece, char index) {
|
368 |
|
|
char rotation, cell[5];
|
369 |
|
|
char minimum, first_empty;
|
370 |
|
|
unsigned long long piece_mask;
|
371 |
|
|
|
372 |
|
|
for(rotation = 0; rotation < 6; rotation++) {
|
373 |
|
|
if(piece != 3 || rotation < 3) {
|
374 |
|
|
calc_cell_indices(cell, piece, index);
|
375 |
|
|
if(cells_fit_on_board(cell, piece) && !has_island(cell, piece)) {
|
376 |
|
|
minimum = minimum_of_cells(cell);
|
377 |
|
|
first_empty = first_empty_cell(cell, minimum);
|
378 |
|
|
piece_mask = bitmask_from_cells(cell);
|
379 |
|
|
record_piece(piece, minimum, first_empty, piece_mask);
|
380 |
|
|
}
|
381 |
|
|
}
|
382 |
|
|
rotate_piece(piece);
|
383 |
|
|
}
|
384 |
|
|
}
|
385 |
|
|
|
386 |
|
|
/* Calculate every legal rotation for each piece at each board location. */
|
387 |
|
|
void calc_pieces(void) {
|
388 |
|
|
char piece, index;
|
389 |
|
|
|
390 |
|
|
for(piece = 0; piece < 10; piece++) {
|
391 |
|
|
for(index = 0; index < 50; index++) {
|
392 |
|
|
calc_six_rotations(piece, index);
|
393 |
|
|
flip_piece(piece);
|
394 |
|
|
calc_six_rotations(piece, index);
|
395 |
|
|
}
|
396 |
|
|
}
|
397 |
|
|
}
|
398 |
|
|
|
399 |
|
|
|
400 |
|
|
|
401 |
|
|
/* Calculate all 32 possible states for a 5-bit row and all rows that will
|
402 |
|
|
* create islands that follow any of the 32 possible rows. These pre-
|
403 |
|
|
* calculated 5-bit rows will be used to find islands in a partially solved
|
404 |
|
|
* board in the solve function.
|
405 |
|
|
*/
|
406 |
|
|
#define ROW_MASK 0x1F
|
407 |
|
|
#define TRIPLE_MASK 0x7FFF
|
408 |
|
|
char all_rows[32] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
409 |
|
|
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
410 |
|
|
int bad_even_rows[32][32];
|
411 |
|
|
int bad_odd_rows[32][32];
|
412 |
|
|
int bad_even_triple[32768];
|
413 |
|
|
int bad_odd_triple[32768];
|
414 |
|
|
|
415 |
|
|
int rows_bad(char row1, char row2, int even) {
|
416 |
|
|
/* even is referring to row1 */
|
417 |
|
|
int i, in_zeroes, group_okay;
|
418 |
|
|
char block, row2_shift;
|
419 |
|
|
/* Test for blockages at same index and shifted index */
|
420 |
|
|
if(even)
|
421 |
|
|
row2_shift = ((row2 << 1) & ROW_MASK) | 0x01;
|
422 |
|
|
else
|
423 |
|
|
row2_shift = (row2 >> 1) | 0x10;
|
424 |
|
|
block = ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift);
|
425 |
|
|
/* Test for groups of 0's */
|
426 |
|
|
in_zeroes = FALSE;
|
427 |
|
|
group_okay = FALSE;
|
428 |
|
|
for(i = 0; i < 5; i++) {
|
429 |
|
|
if(row1 & (1 << i)) {
|
430 |
|
|
if(in_zeroes) {
|
431 |
|
|
if(!group_okay)
|
432 |
|
|
return TRUE;
|
433 |
|
|
in_zeroes = FALSE;
|
434 |
|
|
group_okay = FALSE;
|
435 |
|
|
}
|
436 |
|
|
} else {
|
437 |
|
|
if(!in_zeroes)
|
438 |
|
|
in_zeroes = TRUE;
|
439 |
|
|
if(!(block & (1 << i)))
|
440 |
|
|
group_okay = TRUE;
|
441 |
|
|
}
|
442 |
|
|
}
|
443 |
|
|
if(in_zeroes)
|
444 |
|
|
return !group_okay;
|
445 |
|
|
else
|
446 |
|
|
return FALSE;
|
447 |
|
|
}
|
448 |
|
|
|
449 |
|
|
/* Check for cases where three rows checked sequentially cause a false
|
450 |
|
|
* positive. One scenario is when 5 cells may be surrounded where piece 5
|
451 |
|
|
* or 7 can fit. The other scenario is when piece 2 creates a hook shape.
|
452 |
|
|
*/
|
453 |
|
|
int triple_is_okay(char row1, char row2, char row3, int even) {
|
454 |
|
|
if(even) {
|
455 |
|
|
/* There are four cases:
|
456 |
|
|
* row1: 00011 00001 11001 10101
|
457 |
|
|
* row2: 01011 00101 10001 10001
|
458 |
|
|
* row3: 011?? 00110 ????? ?????
|
459 |
|
|
*/
|
460 |
|
|
return ((row1 == 0x03) && (row2 == 0x0B) && ((row3 & 0x1C) == 0x0C)) ||
|
461 |
|
|
((row1 == 0x01) && (row2 == 0x05) && (row3 == 0x06)) ||
|
462 |
|
|
((row1 == 0x19) && (row2 == 0x11)) ||
|
463 |
|
|
((row1 == 0x15) && (row2 == 0x11));
|
464 |
|
|
} else {
|
465 |
|
|
/* There are two cases:
|
466 |
|
|
* row1: 10011 10101
|
467 |
|
|
* row2: 10001 10001
|
468 |
|
|
* row3: ????? ?????
|
469 |
|
|
*/
|
470 |
|
|
return ((row1 == 0x13) && (row2 == 0x11)) ||
|
471 |
|
|
((row1 == 0x15) && (row2 == 0x11));
|
472 |
|
|
}
|
473 |
|
|
}
|
474 |
|
|
|
475 |
|
|
|
476 |
|
|
void calc_rows(void) {
|
477 |
|
|
int row1, row2, row3;
|
478 |
|
|
int result1, result2;
|
479 |
|
|
for(row1 = 0; row1 < 32; row1++) {
|
480 |
|
|
for(row2 = 0; row2 < 32; row2++) {
|
481 |
|
|
bad_even_rows[row1][row2] = rows_bad(row1, row2, TRUE);
|
482 |
|
|
bad_odd_rows[row1][row2] = rows_bad(row1, row2, FALSE);
|
483 |
|
|
}
|
484 |
|
|
}
|
485 |
|
|
for(row1 = 0; row1 < 32; row1++) {
|
486 |
|
|
for(row2 = 0; row2 < 32; row2++) {
|
487 |
|
|
for(row3 = 0; row3 < 32; row3++) {
|
488 |
|
|
result1 = bad_even_rows[row1][row2];
|
489 |
|
|
result2 = bad_odd_rows[row2][row3];
|
490 |
|
|
if(result1 == FALSE && result2 == TRUE
|
491 |
|
|
&& triple_is_okay(row1, row2, row3, TRUE))
|
492 |
|
|
bad_even_triple[row1+(row2*32)+(row3*1024)] = FALSE;
|
493 |
|
|
else
|
494 |
|
|
bad_even_triple[row1+(row2*32)+(row3*1024)] = result1 || result2;
|
495 |
|
|
|
496 |
|
|
result1 = bad_odd_rows[row1][row2];
|
497 |
|
|
result2 = bad_even_rows[row2][row3];
|
498 |
|
|
if(result1 == FALSE && result2 == TRUE
|
499 |
|
|
&& triple_is_okay(row1, row2, row3, FALSE))
|
500 |
|
|
bad_odd_triple[row1+(row2*32)+(row3*1024)] = FALSE;
|
501 |
|
|
else
|
502 |
|
|
bad_odd_triple[row1+(row2*32)+(row3*1024)] = result1 || result2;
|
503 |
|
|
}
|
504 |
|
|
}
|
505 |
|
|
}
|
506 |
|
|
}
|
507 |
|
|
|
508 |
|
|
|
509 |
|
|
|
510 |
|
|
/* Calculate islands while solving the board.
|
511 |
|
|
*/
|
512 |
|
|
int boardHasIslands(char cell) {
|
513 |
|
|
/* Too low on board, don't bother checking */
|
514 |
|
|
if(cell >= 40)
|
515 |
|
|
return FALSE;
|
516 |
|
|
int current_triple = (board >> ((cell / 5) * 5)) & TRIPLE_MASK;
|
517 |
|
|
if((cell / 5) % 2)
|
518 |
|
|
return bad_odd_triple[current_triple];
|
519 |
|
|
else
|
520 |
|
|
return bad_even_triple[current_triple];
|
521 |
|
|
}
|
522 |
|
|
|
523 |
|
|
|
524 |
|
|
/* The recursive solve algorithm. Try to place each permutation in the upper-
|
525 |
|
|
* leftmost empty cell. Mark off available pieces as it goes along.
|
526 |
|
|
* Because the board is a bit mask, the piece number and bit mask must be saved
|
527 |
|
|
* at each successful piece placement. This data is used to create a 50 char
|
528 |
|
|
* array if a solution is found.
|
529 |
|
|
*/
|
530 |
|
|
short avail = 0x03FF;
|
531 |
|
|
char sol_nums[10];
|
532 |
|
|
unsigned long long sol_masks[10];
|
533 |
|
|
signed char solutions[2100][50];
|
534 |
|
|
int solution_count = 0;
|
535 |
|
|
int max_solutions = 2100;
|
536 |
|
|
|
537 |
|
|
void record_solution(void) {
|
538 |
|
|
int sol_no, index;
|
539 |
|
|
unsigned long long sol_mask;
|
540 |
|
|
for(sol_no = 0; sol_no < 10; sol_no++) {
|
541 |
|
|
sol_mask = sol_masks[sol_no];
|
542 |
|
|
for(index = 0; index < 50; index++) {
|
543 |
|
|
if(sol_mask & 1ULL) {
|
544 |
|
|
solutions[solution_count][index] = sol_nums[sol_no];
|
545 |
|
|
/* Board rotated 180 degrees is a solution too! */
|
546 |
|
|
solutions[solution_count+1][49-index] = sol_nums[sol_no];
|
547 |
|
|
}
|
548 |
|
|
sol_mask = sol_mask >> 1;
|
549 |
|
|
}
|
550 |
|
|
}
|
551 |
|
|
solution_count += 2;
|
552 |
|
|
}
|
553 |
|
|
|
554 |
|
|
void solve(int depth, int cell) {
|
555 |
|
|
int piece, rotation, max_rots;
|
556 |
|
|
unsigned long long *piece_mask;
|
557 |
|
|
short piece_no_mask;
|
558 |
|
|
|
559 |
|
|
if(solution_count >= max_solutions)
|
560 |
|
|
return;
|
561 |
|
|
|
562 |
|
|
while(board & (1ULL << cell))
|
563 |
|
|
cell++;
|
564 |
|
|
|
565 |
|
|
for(piece = 0; piece < 10; piece++) {
|
566 |
|
|
piece_no_mask = 1 << piece;
|
567 |
|
|
if(!(avail & piece_no_mask))
|
568 |
|
|
continue;
|
569 |
|
|
avail ^= piece_no_mask;
|
570 |
|
|
max_rots = piece_counts[piece][cell];
|
571 |
|
|
piece_mask = pieces[piece][cell];
|
572 |
|
|
for(rotation = 0; rotation < max_rots; rotation++) {
|
573 |
|
|
if(!(board & *(piece_mask + rotation))) {
|
574 |
|
|
sol_nums[depth] = piece;
|
575 |
|
|
sol_masks[depth] = *(piece_mask + rotation);
|
576 |
|
|
if(depth == 9) {
|
577 |
|
|
/* Solution found!!!!!11!!ONE! */
|
578 |
|
|
record_solution();
|
579 |
|
|
avail ^= piece_no_mask;
|
580 |
|
|
return;
|
581 |
|
|
}
|
582 |
|
|
board |= *(piece_mask + rotation);
|
583 |
|
|
if(!boardHasIslands(next_cell[piece][cell][rotation]))
|
584 |
|
|
solve(depth + 1, next_cell[piece][cell][rotation]);
|
585 |
|
|
board ^= *(piece_mask + rotation);
|
586 |
|
|
}
|
587 |
|
|
}
|
588 |
|
|
avail ^= piece_no_mask;
|
589 |
|
|
}
|
590 |
|
|
}
|
591 |
|
|
|
592 |
|
|
|
593 |
|
|
/* qsort comparator - used to find first and last solutions */
|
594 |
|
|
int solution_sort(const void *elem1, const void *elem2) {
|
595 |
|
|
signed char *char1 = (signed char *) elem1;
|
596 |
|
|
signed char *char2 = (signed char *) elem2;
|
597 |
|
|
int i = 0;
|
598 |
|
|
while(i < 50 && char1[i] == char2[i])
|
599 |
|
|
i++;
|
600 |
|
|
return char1[i] - char2[i];
|
601 |
|
|
}
|
602 |
|
|
|
603 |
|
|
|
604 |
|
|
/* pretty print a board in the specified hexagonal format */
|
605 |
|
|
void pretty(signed char *b) {
|
606 |
|
|
int i;
|
607 |
|
|
for(i = 0; i < 50; i += 10) {
|
608 |
|
|
printf("%c %c %c %c %c \n %c %c %c %c %c \n", b[i]+'0', b[i+1]+'0',
|
609 |
|
|
b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0',
|
610 |
|
|
b[i+7]+'0', b[i+8]+'0', b[i+9]+'0');
|
611 |
|
|
}
|
612 |
|
|
printf("\n");
|
613 |
|
|
}
|
614 |
|
|
|
615 |
|
|
int main(int argc, char **argv) {
|
616 |
|
|
if(argc > 1)
|
617 |
|
|
max_solutions = atoi(argv[1]);
|
618 |
|
|
calc_pieces();
|
619 |
|
|
calc_rows();
|
620 |
|
|
solve(0, 0);
|
621 |
|
|
printf("%d solutions found\n\n", solution_count);
|
622 |
|
|
qsort(solutions, solution_count, 50 * sizeof(signed char), solution_sort);
|
623 |
|
|
pretty(solutions[0]);
|
624 |
|
|
pretty(solutions[solution_count-1]);
|
625 |
|
|
return 0;
|
626 |
|
|
}
|