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  }