github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/test/bench/shootout/meteor-contest.c (about)

     1  /*
     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  }