diff options
Diffstat (limited to 'test/bench/meteor-contest.c')
-rw-r--r-- | test/bench/meteor-contest.c | 626 |
1 files changed, 0 insertions, 626 deletions
diff --git a/test/bench/meteor-contest.c b/test/bench/meteor-contest.c deleted file mode 100644 index 19c43402c..000000000 --- a/test/bench/meteor-contest.c +++ /dev/null @@ -1,626 +0,0 @@ -/* -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of "The Computer Language Benchmarks Game" nor the - name of "The Computer Language Shootout Benchmarks" nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. -*/ - -/* The Computer Language Benchmarks Game - * http://shootout.alioth.debian.org/ - * - * contributed by Christian Vosteen - */ - -#include <stdlib.h> -#include <stdio.h> -#define TRUE 1 -#define FALSE 0 - -/* The board is a 50 cell hexagonal pattern. For . . . . . - * maximum speed the board will be implemented as . . . . . - * 50 bits, which will fit into a 64 bit long long . . . . . - * int. . . . . . - * . . . . . - * I will represent 0's as empty cells and 1's . . . . . - * as full cells. . . . . . - * . . . . . - * . . . . . - * . . . . . - */ - -unsigned long long board = 0xFFFC000000000000ULL; - -/* The puzzle pieces must be specified by the path followed - * from one end to the other along 12 hexagonal directions. - * - * Piece 0 Piece 1 Piece 2 Piece 3 Piece 4 - * - * O O O O O O O O O O O O O O O - * O O O O O O O - * O O O - * - * Piece 5 Piece 6 Piece 7 Piece 8 Piece 9 - * - * O O O O O O O O O O O O O - * O O O O O O O O O - * O O O - * - * I had to make it 12 directions because I wanted all of the - * piece definitions to fit into the same size arrays. It is - * not possible to define piece 4 in terms of the 6 cardinal - * directions in 4 moves. - */ - -#define E 0 -#define ESE 1 -#define SE 2 -#define S 3 -#define SW 4 -#define WSW 5 -#define W 6 -#define WNW 7 -#define NW 8 -#define N 9 -#define NE 10 -#define ENE 11 -#define PIVOT 12 - -char piece_def[10][4] = { - { E, E, E, SE}, - { SE, E, NE, E}, - { E, E, SE, SW}, - { E, E, SW, SE}, - { SE, E, NE, S}, - { E, E, SW, E}, - { E, SE, SE, NE}, - { E, SE, SE, W}, - { E, SE, E, E}, - { E, E, E, SW} -}; - - -/* To minimize the amount of work done in the recursive solve function below, - * I'm going to allocate enough space for all legal rotations of each piece - * at each position on the board. That's 10 pieces x 50 board positions x - * 12 rotations. However, not all 12 rotations will fit on every cell, so - * I'll have to keep count of the actual number that do. - * The pieces are going to be unsigned long long ints just like the board so - * they can be bitwise-anded with the board to determine if they fit. - * I'm also going to record the next possible open cell for each piece and - * location to reduce the burden on the solve function. - */ -unsigned long long pieces[10][50][12]; -int piece_counts[10][50]; -char next_cell[10][50][12]; - -/* Returns the direction rotated 60 degrees clockwise */ -char rotate(char dir) { - return (dir + 2) % PIVOT; -} - -/* Returns the direction flipped on the horizontal axis */ -char flip(char dir) { - return (PIVOT - dir) % PIVOT; -} - - -/* Returns the new cell index from the specified cell in the - * specified direction. The index is only valid if the - * starting cell and direction have been checked by the - * out_of_bounds function first. - */ -char shift(char cell, char dir) { - switch(dir) { - case E: - return cell + 1; - case ESE: - if((cell / 5) % 2) - return cell + 7; - else - return cell + 6; - case SE: - if((cell / 5) % 2) - return cell + 6; - else - return cell + 5; - case S: - return cell + 10; - case SW: - if((cell / 5) % 2) - return cell + 5; - else - return cell + 4; - case WSW: - if((cell / 5) % 2) - return cell + 4; - else - return cell + 3; - case W: - return cell - 1; - case WNW: - if((cell / 5) % 2) - return cell - 6; - else - return cell - 7; - case NW: - if((cell / 5) % 2) - return cell - 5; - else - return cell - 6; - case N: - return cell - 10; - case NE: - if((cell / 5) % 2) - return cell - 4; - else - return cell - 5; - case ENE: - if((cell / 5) % 2) - return cell - 3; - else - return cell - 4; - default: - return cell; - } -} - -/* Returns wether the specified cell and direction will land outside - * of the board. Used to determine if a piece is at a legal board - * location or not. - */ -char out_of_bounds(char cell, char dir) { - char i; - switch(dir) { - case E: - return cell % 5 == 4; - case ESE: - i = cell % 10; - return i == 4 || i == 8 || i == 9 || cell >= 45; - case SE: - return cell % 10 == 9 || cell >= 45; - case S: - return cell >= 40; - case SW: - return cell % 10 == 0 || cell >= 45; - case WSW: - i = cell % 10; - return i == 0 || i == 1 || i == 5 || cell >= 45; - case W: - return cell % 5 == 0; - case WNW: - i = cell % 10; - return i == 0 || i == 1 || i == 5 || cell < 5; - case NW: - return cell % 10 == 0 || cell < 5; - case N: - return cell < 10; - case NE: - return cell % 10 == 9 || cell < 5; - case ENE: - i = cell % 10; - return i == 4 || i == 8 || i == 9 || cell < 5; - default: - return FALSE; - } -} - -/* Rotate a piece 60 degrees clockwise */ -void rotate_piece(int piece) { - int i; - for(i = 0; i < 4; i++) - piece_def[piece][i] = rotate(piece_def[piece][i]); -} - -/* Flip a piece along the horizontal axis */ -void flip_piece(int piece) { - int i; - for(i = 0; i < 4; i++) - piece_def[piece][i] = flip(piece_def[piece][i]); -} - -/* Convenience function to quickly calculate all of the indices for a piece */ -void calc_cell_indices(char *cell, int piece, char index) { - cell[0] = index; - cell[1] = shift(cell[0], piece_def[piece][0]); - cell[2] = shift(cell[1], piece_def[piece][1]); - cell[3] = shift(cell[2], piece_def[piece][2]); - cell[4] = shift(cell[3], piece_def[piece][3]); -} - -/* Convenience function to quickly calculate if a piece fits on the board */ -int cells_fit_on_board(char *cell, int piece) { - return (!out_of_bounds(cell[0], piece_def[piece][0]) && - !out_of_bounds(cell[1], piece_def[piece][1]) && - !out_of_bounds(cell[2], piece_def[piece][2]) && - !out_of_bounds(cell[3], piece_def[piece][3])); -} - -/* Returns the lowest index of the cells of a piece. - * I use the lowest index that a piece occupies as the index for looking up - * the piece in the solve function. - */ -char minimum_of_cells(char *cell) { - char minimum = cell[0]; - minimum = cell[1] < minimum ? cell[1] : minimum; - minimum = cell[2] < minimum ? cell[2] : minimum; - minimum = cell[3] < minimum ? cell[3] : minimum; - minimum = cell[4] < minimum ? cell[4] : minimum; - return minimum; -} - -/* Calculate the lowest possible open cell if the piece is placed on the board. - * Used to later reduce the amount of time searching for open cells in the - * solve function. - */ -char first_empty_cell(char *cell, char minimum) { - char first_empty = minimum; - while(first_empty == cell[0] || first_empty == cell[1] || - first_empty == cell[2] || first_empty == cell[3] || - first_empty == cell[4]) - first_empty++; - return first_empty; -} - -/* Generate the unsigned long long int that will later be anded with the - * board to determine if it fits. - */ -unsigned long long bitmask_from_cells(char *cell) { - unsigned long long piece_mask = 0ULL; - int i; - for(i = 0; i < 5; i++) - piece_mask |= 1ULL << cell[i]; - return piece_mask; -} - -/* Record the piece and other important information in arrays that will - * later be used by the solve function. - */ -void record_piece(int piece, int minimum, char first_empty, - unsigned long long piece_mask) { - pieces[piece][minimum][piece_counts[piece][minimum]] = piece_mask; - next_cell[piece][minimum][piece_counts[piece][minimum]] = first_empty; - piece_counts[piece][minimum]++; -} - - -/* Fill the entire board going cell by cell. If any cells are "trapped" - * they will be left alone. - */ -void fill_contiguous_space(char *board, int index) { - if(board[index] == 1) - return; - board[index] = 1; - if(!out_of_bounds(index, E)) - fill_contiguous_space(board, shift(index, E)); - if(!out_of_bounds(index, SE)) - fill_contiguous_space(board, shift(index, SE)); - if(!out_of_bounds(index, SW)) - fill_contiguous_space(board, shift(index, SW)); - if(!out_of_bounds(index, W)) - fill_contiguous_space(board, shift(index, W)); - if(!out_of_bounds(index, NW)) - fill_contiguous_space(board, shift(index, NW)); - if(!out_of_bounds(index, NE)) - fill_contiguous_space(board, shift(index, NE)); -} - - -/* To thin the number of pieces, I calculate if any of them trap any empty - * cells at the edges. There are only a handful of exceptions where the - * the board can be solved with the trapped cells. For example: piece 8 can - * trap 5 cells in the corner, but piece 3 can fit in those cells, or piece 0 - * can split the board in half where both halves are viable. - */ -int has_island(char *cell, int piece) { - char temp_board[50]; - char c; - int i; - for(i = 0; i < 50; i++) - temp_board[i] = 0; - for(i = 0; i < 5; i++) - temp_board[((int)cell[i])] = 1; - i = 49; - while(temp_board[i] == 1) - i--; - fill_contiguous_space(temp_board, i); - c = 0; - for(i = 0; i < 50; i++) - if(temp_board[i] == 0) - c++; - if(c == 0 || (c == 5 && piece == 8) || (c == 40 && piece == 8) || - (c % 5 == 0 && piece == 0)) - return FALSE; - else - return TRUE; -} - - -/* Calculate all six rotations of the specified piece at the specified index. - * We calculate only half of piece 3's rotations. This is because any solution - * found has an identical solution rotated 180 degrees. Thus we can reduce the - * number of attempted pieces in the solve algorithm by not including the 180- - * degree-rotated pieces of ONE of the pieces. I chose piece 3 because it gave - * me the best time ;) - */ - void calc_six_rotations(char piece, char index) { - char rotation, cell[5]; - char minimum, first_empty; - unsigned long long piece_mask; - - for(rotation = 0; rotation < 6; rotation++) { - if(piece != 3 || rotation < 3) { - calc_cell_indices(cell, piece, index); - if(cells_fit_on_board(cell, piece) && !has_island(cell, piece)) { - minimum = minimum_of_cells(cell); - first_empty = first_empty_cell(cell, minimum); - piece_mask = bitmask_from_cells(cell); - record_piece(piece, minimum, first_empty, piece_mask); - } - } - rotate_piece(piece); - } -} - -/* Calculate every legal rotation for each piece at each board location. */ -void calc_pieces(void) { - char piece, index; - - for(piece = 0; piece < 10; piece++) { - for(index = 0; index < 50; index++) { - calc_six_rotations(piece, index); - flip_piece(piece); - calc_six_rotations(piece, index); - } - } -} - - - -/* Calculate all 32 possible states for a 5-bit row and all rows that will - * create islands that follow any of the 32 possible rows. These pre- - * calculated 5-bit rows will be used to find islands in a partially solved - * board in the solve function. - */ -#define ROW_MASK 0x1F -#define TRIPLE_MASK 0x7FFF -char all_rows[32] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; -int bad_even_rows[32][32]; -int bad_odd_rows[32][32]; -int bad_even_triple[32768]; -int bad_odd_triple[32768]; - -int rows_bad(char row1, char row2, int even) { - /* even is referring to row1 */ - int i, in_zeroes, group_okay; - char block, row2_shift; - /* Test for blockages at same index and shifted index */ - if(even) - row2_shift = ((row2 << 1) & ROW_MASK) | 0x01; - else - row2_shift = (row2 >> 1) | 0x10; - block = ((row1 ^ row2) & row2) & ((row1 ^ row2_shift) & row2_shift); - /* Test for groups of 0's */ - in_zeroes = FALSE; - group_okay = FALSE; - for(i = 0; i < 5; i++) { - if(row1 & (1 << i)) { - if(in_zeroes) { - if(!group_okay) - return TRUE; - in_zeroes = FALSE; - group_okay = FALSE; - } - } else { - if(!in_zeroes) - in_zeroes = TRUE; - if(!(block & (1 << i))) - group_okay = TRUE; - } - } - if(in_zeroes) - return !group_okay; - else - return FALSE; -} - -/* Check for cases where three rows checked sequentially cause a false - * positive. One scenario is when 5 cells may be surrounded where piece 5 - * or 7 can fit. The other scenario is when piece 2 creates a hook shape. - */ -int triple_is_okay(char row1, char row2, char row3, int even) { - if(even) { - /* There are four cases: - * row1: 00011 00001 11001 10101 - * row2: 01011 00101 10001 10001 - * row3: 011?? 00110 ????? ????? - */ - return ((row1 == 0x03) && (row2 == 0x0B) && ((row3 & 0x1C) == 0x0C)) || - ((row1 == 0x01) && (row2 == 0x05) && (row3 == 0x06)) || - ((row1 == 0x19) && (row2 == 0x11)) || - ((row1 == 0x15) && (row2 == 0x11)); - } else { - /* There are two cases: - * row1: 10011 10101 - * row2: 10001 10001 - * row3: ????? ????? - */ - return ((row1 == 0x13) && (row2 == 0x11)) || - ((row1 == 0x15) && (row2 == 0x11)); - } -} - - -void calc_rows(void) { - int row1, row2, row3; - int result1, result2; - for(row1 = 0; row1 < 32; row1++) { - for(row2 = 0; row2 < 32; row2++) { - bad_even_rows[row1][row2] = rows_bad(row1, row2, TRUE); - bad_odd_rows[row1][row2] = rows_bad(row1, row2, FALSE); - } - } - for(row1 = 0; row1 < 32; row1++) { - for(row2 = 0; row2 < 32; row2++) { - for(row3 = 0; row3 < 32; row3++) { - result1 = bad_even_rows[row1][row2]; - result2 = bad_odd_rows[row2][row3]; - if(result1 == FALSE && result2 == TRUE - && triple_is_okay(row1, row2, row3, TRUE)) - bad_even_triple[row1+(row2*32)+(row3*1024)] = FALSE; - else - bad_even_triple[row1+(row2*32)+(row3*1024)] = result1 || result2; - - result1 = bad_odd_rows[row1][row2]; - result2 = bad_even_rows[row2][row3]; - if(result1 == FALSE && result2 == TRUE - && triple_is_okay(row1, row2, row3, FALSE)) - bad_odd_triple[row1+(row2*32)+(row3*1024)] = FALSE; - else - bad_odd_triple[row1+(row2*32)+(row3*1024)] = result1 || result2; - } - } - } -} - - - -/* Calculate islands while solving the board. - */ -int boardHasIslands(char cell) { - /* Too low on board, don't bother checking */ - if(cell >= 40) - return FALSE; - int current_triple = (board >> ((cell / 5) * 5)) & TRIPLE_MASK; - if((cell / 5) % 2) - return bad_odd_triple[current_triple]; - else - return bad_even_triple[current_triple]; -} - - -/* The recursive solve algorithm. Try to place each permutation in the upper- - * leftmost empty cell. Mark off available pieces as it goes along. - * Because the board is a bit mask, the piece number and bit mask must be saved - * at each successful piece placement. This data is used to create a 50 char - * array if a solution is found. - */ -short avail = 0x03FF; -char sol_nums[10]; -unsigned long long sol_masks[10]; -signed char solutions[2100][50]; -int solution_count = 0; -int max_solutions = 2100; - -void record_solution(void) { - int sol_no, index; - unsigned long long sol_mask; - for(sol_no = 0; sol_no < 10; sol_no++) { - sol_mask = sol_masks[sol_no]; - for(index = 0; index < 50; index++) { - if(sol_mask & 1ULL) { - solutions[solution_count][index] = sol_nums[sol_no]; - /* Board rotated 180 degrees is a solution too! */ - solutions[solution_count+1][49-index] = sol_nums[sol_no]; - } - sol_mask = sol_mask >> 1; - } - } - solution_count += 2; -} - -void solve(int depth, int cell) { - int piece, rotation, max_rots; - unsigned long long *piece_mask; - short piece_no_mask; - - if(solution_count >= max_solutions) - return; - - while(board & (1ULL << cell)) - cell++; - - for(piece = 0; piece < 10; piece++) { - piece_no_mask = 1 << piece; - if(!(avail & piece_no_mask)) - continue; - avail ^= piece_no_mask; - max_rots = piece_counts[piece][cell]; - piece_mask = pieces[piece][cell]; - for(rotation = 0; rotation < max_rots; rotation++) { - if(!(board & *(piece_mask + rotation))) { - sol_nums[depth] = piece; - sol_masks[depth] = *(piece_mask + rotation); - if(depth == 9) { - /* Solution found!!!!!11!!ONE! */ - record_solution(); - avail ^= piece_no_mask; - return; - } - board |= *(piece_mask + rotation); - if(!boardHasIslands(next_cell[piece][cell][rotation])) - solve(depth + 1, next_cell[piece][cell][rotation]); - board ^= *(piece_mask + rotation); - } - } - avail ^= piece_no_mask; - } -} - - -/* qsort comparator - used to find first and last solutions */ -int solution_sort(const void *elem1, const void *elem2) { - signed char *char1 = (signed char *) elem1; - signed char *char2 = (signed char *) elem2; - int i = 0; - while(i < 50 && char1[i] == char2[i]) - i++; - return char1[i] - char2[i]; -} - - -/* pretty print a board in the specified hexagonal format */ -void pretty(signed char *b) { - int i; - for(i = 0; i < 50; i += 10) { - printf("%c %c %c %c %c \n %c %c %c %c %c \n", b[i]+'0', b[i+1]+'0', - b[i+2]+'0', b[i+3]+'0', b[i+4]+'0', b[i+5]+'0', b[i+6]+'0', - b[i+7]+'0', b[i+8]+'0', b[i+9]+'0'); - } - printf("\n"); -} - -int main(int argc, char **argv) { - if(argc > 1) - max_solutions = atoi(argv[1]); - calc_pieces(); - calc_rows(); - solve(0, 0); - printf("%d solutions found\n\n", solution_count); - qsort(solutions, solution_count, 50 * sizeof(signed char), solution_sort); - pretty(solutions[0]); - pretty(solutions[solution_count-1]); - return 0; -} |