golang.org/x/exp@v0.0.0-20240506185415-9bf2ced13842/shootout/meteor-contest.c (about)

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