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