Esempio n. 1
0
//=================================================================
// Search for move function. (Negamax Driver)
//=================================================================
extern s32bit
search_for_move(char dir, s32bit *row, s32bit *col, u64bit *nodes)
{
  s32bit  d, i, value = 0, num_moves;
  Move    movelist[MAXMOVES];
  s32bit  whos_turn;
  Move    forcefirst;
    
  // Set who's turn it is.
  if(toupper(dir) == 'V')      whos_turn = VERTICAL;
  else if(toupper(dir) == 'H') whos_turn = HORIZONTAL;
  else { fatal_error(1, "Invalid player.\n"); exit(1); }
  
  // initialize the number of empty squares.
  g_empty_squares = 0;
  for(i = 0; i < g_board_size[0]; i++)
    g_empty_squares += countbits32( (~g_board[0][i+1]) );
  
  // zero out all the statistics variables.
  init_stats();
  
  // Can we already determine a winner?
  {
    s32bit opponent = whos_turn ^ PLAYER_MASK;
    
    // stop search if game over.
    if(g_info_totals[whos_turn].safe > g_info_totals[opponent].real){
      // current player wins.
      *col = *row = -1;
      *nodes = 0;
      return 5000;
    }
    
    if(g_info_totals[opponent].safe >= g_info_totals[whos_turn].real){
      // opponent wins.
      *col = *row = -1;
      *nodes = 0;
      return -5000;
    }
  }
  
  // generate all possible moves for current player given current position.
  num_moves = move_generator(movelist, whos_turn);

  // This should never happen.
  if(num_moves == 0) fatal_error(1, "No moves");

  // should possibly sort the whole list instead of just get first.
  forcefirst.array_index = -1;
  score_and_get_first(movelist, num_moves, whos_turn, forcefirst);
  sort_moves(movelist, 1, num_moves);

  // Really this is for iterative deepening.
  for(d = 1; d < 50; d += 44){

    // Initialize alpha and beta.
    s32bit alpha = -5000, beta = 5000;

    // Re-initialize the statistics for each iteration.
    g_num_nodes = 0;
    init_stats();

    // set what the starting max depth is.
    starting_depth = d;
        
    // iterate through all the possible moves.
    for(i = 0; i < num_moves; i++){

#ifdef DYNAMIC_POSITION_VALUES
      init_move_value();
      set_move_value(movelist[i], whos_turn);
#else
      set_position_values();
#endif
      
      g_move_number[0] = i;
#ifdef RECORD_MOVES
      g_move_player[0] = whos_turn;
      g_move_position[0] = movelist[i];
#endif
      
      g_empty_squares -= 2;
      toggle_move(movelist[i], whos_turn);
      toggle_hash_code
    (g_keyinfo[whos_turn][movelist[i].array_index][movelist[i].mask_index]);
      check_hash_code_sanity();
      
      value = -negamax(d-1, whos_turn^PLAYER_MASK, -beta, -alpha);
      
#ifdef DYNAMIC_POSITION_VALUES
      unset_move_value(movelist[i], whos_turn);
#endif

      g_empty_squares += 2;
      toggle_move(movelist[i], whos_turn);
      toggle_hash_code
    (g_keyinfo[whos_turn][movelist[i].array_index][movelist[i].mask_index]);
      check_hash_code_sanity();

      printf("Move (%d,%d), value %d: %s.\n",
             movelist[i].array_index, movelist[i].mask_index,
             value, u64bit_to_string(g_num_nodes));
      printf("alpha %d, beta %d.\n", alpha, beta);

      movelist[i].info = value;

      if(value >= beta){
        alpha = value;
        break;
      }
      if(value > alpha) {
        alpha = value;
      }
    }

    if(value >= 5000){
      printf("Winner found: %d.\n", value);
      if(whos_turn == HORIZONTAL){
        *row = movelist[i].array_index;
        *col = movelist[i].mask_index;
      } else if(whos_turn == VERTICAL){
        *col = movelist[i].array_index;
        *row = movelist[i].mask_index;
      } else {
        fatal_error(1, "oops.");
      }
      
      *nodes = g_num_nodes;

      print_stats();
      
      return value;
    }

    // remove lossing moves from movelist.
    {
      s32bit rem = 0;
      for(i = 0; i < num_moves; i++){
        if(movelist[i].info <= -5000) rem++;
        else if(rem > 0) movelist[i-rem] = movelist[i];
      }
      num_moves -= rem;
      /*
      for(i = 0; i < num_moves; i++){
        printf("(%d,%d): %d.\n",
               movelist[i].array_index, movelist[i].mask_index,
               movelist[i].info);
      }
      */
    }

    print_stats();
    
    if(num_moves == 0){
      break;
    }
    
    // use a stable sort algorithm
    {
      Move swp;
      s32bit max, index, j;
      
      for(i=0; i<num_moves; i++) {
        max = movelist[i].info;
        index = i;
        
        for(j=i+1; j < num_moves; j++)
          if(movelist[j].info > max){
            max = movelist[j].info;
            index = j;
          }
    
        if(index != i){
          swp = movelist[index];
          //          printf("%d %d\n", index, i);
          for(j = index; j != i; j--){
            movelist[j] = movelist[j-1];
          }
          movelist[i] = swp;
        }
      }
    }
    
    printf("The value is %d at a depth of %d.\n", value, d);
    printf("Nodes: %u.\n", (u32bit)g_num_nodes);
  }

  *col = *row = -1;
  *nodes = g_num_nodes;

  return value;
}
Esempio n. 2
0
//=================================================================
// Negamax Function.
//=================================================================
static s32bit
negamax(s32bit depth_remaining, s32bit whos_turn_t, s32bit alpha, s32bit beta)
{
  Move   movelist[MAXMOVES], best;
  s32bit whos_turn = whos_turn_t & PLAYER_MASK;
  s32bit opponent  = whos_turn_t ^ PLAYER_MASK;
  s32bit value;
  s32bit init_alpha = alpha, init_beta = beta;
  u32bit start_nodes = g_num_nodes;
  Move   forcefirst;
  s32bit who_wins_value;

  s32bit stage = 0, state = 0, true_count, i = 0, num_moves = 1;

#ifdef DYNAMIC_POSITION_VALUES
  s32bit dyn_set;
#endif

  // increment a couple of stats
  g_num_nodes++;
#ifdef COLLECT_STATS
  stat_nodes[starting_depth - depth_remaining]++;
#endif

  // if no depth remaining stop search.
  if( depth_remaining <= 0 ){
    s32bit a = 0, b = 0;

    if( (a = does_next_player_win(whos_turn, 0)) > 0 ) {
      // current player wins.
      return 5000;
    }

    if( (b = does_who_just_moved_win(opponent, 0)) >= 0 ) {
      // opponent wins.
      return -5000;
    }
  
    return a - b;
  }
  

  //------------------------------------------
  // Can we determine a winner yet (simple check).
  //------------------------------------------

  // does current player win
  if(g_info_totals[whos_turn].safe > g_info_totals[opponent].real){
#ifdef COLLECT_STATS
    cut1++;
#endif
    return 5000;
  }
  
  // does opponent win
  if(g_info_totals[opponent].safe >= g_info_totals[whos_turn].real){
#ifdef COLLECT_STATS
    cut2++;
#endif
    return -5000;
  }


  //------------------------------------------
  // check transposition table
  //------------------------------------------

  forcefirst.array_index = -1;
  if(hashlookup(&value, &alpha, &beta, depth_remaining,
                &forcefirst, whos_turn))
    return value;
  // since we aren't using iter deep not interested in forcefirst.
  forcefirst.array_index = -1;
  

  //------------------------------------------
  // Can we determine a winner yet (look harder).
  //------------------------------------------

  // does current player win
  if( (who_wins_value = does_next_player_win(whos_turn, 0)) > 0 ) {

#ifdef DEBUG_NEGAMAX
    if(random() % 1000000 == -1){
      does_next_player_win(whos_turn, 1);
      print_board(whos_turn);
    }
#endif

#ifdef COLLECT_STATS
    cut3++;
#endif
    return 5000;
  }
    
  // does opponent win
  if( (who_wins_value = does_who_just_moved_win(opponent, 0)) >= 0 ) {

#ifdef DEBUG_NEGAMAX
    if(who_wins_value < 3){ // && random() % 500 == -1){
      does_who_just_moved_win(opponent, 1);
      //  print_board(opponent);
    }
#endif  

#ifdef COLLECT_STATS
    cut4++;
#endif
    return -5000;
  }

#if 0
  {
    s32bit num;
    num = move_generator_stage1(movelist, whos_turn);
    num = move_generator_stage2(movelist, num, whos_turn);
    if(move_generator(movelist, whos_turn) != num)
      fatal_error(1, "NOPE\n");
  }
#endif


  //------------------------------------------
  // Generate child nodes and examine them.
  //------------------------------------------

  // initialize a few variables. (some of them don't really need to be.)
  stage = state = true_count = i = 0;
  num_moves = 1;

#ifdef TWO_STAGE_GENERATION
  true_count = move_generator_stage1(movelist, whos_turn);
  if(true_count == 0){
    true_count = move_generator_stage2(movelist, 0, whos_turn);
    stage = 1;
    if(true_count == 0) fatal_error(1, "Should always have a move.\n");
  }
#else
  true_count = move_generator(movelist, whos_turn);
  stage = 1;
  if(true_count == 0)   fatal_error(1, "Should always have a move.\n");
#endif
  
  // score all the moves and move the best to the front.
  score_and_get_first(movelist, true_count, whos_turn, forcefirst);
  
  best = movelist[0];
  
  // need to sort moves and generate more moves in certain situations.
  while(state < 3){
    if(state == 0) {
      state = 1;
    } else if(state == 1){
      sort_moves(movelist, 1, true_count);
      num_moves = true_count;
      if(stage == 0) state = 2;
      else           state = 3;
    } else {
      num_moves = move_generator_stage2(movelist, num_moves, whos_turn);
      state = 3;
    }
    
    // Iterate through all the moves.
    for(; i < num_moves; i++){

      // A few statistics
      g_move_number[starting_depth - depth_remaining] = i;
#ifdef RECORD_MOVES
      g_move_player[starting_depth - depth_remaining] = whos_turn;
      g_move_position[starting_depth - depth_remaining] = movelist[i];
#endif

      // make move.
      g_empty_squares -= 2;
      toggle_move(movelist[i], whos_turn);
      toggle_hash_code
    (g_keyinfo[whos_turn][movelist[i].array_index][movelist[i].mask_index]);
#ifdef DYNAMIC_POSITION_VALUES
      dyn_set = set_move_value(movelist[i], whos_turn);
#endif
      
      // recurse.
      value = -negamax(depth_remaining-1,whos_turn^PLAYER_MASK,
                       -beta, -alpha);
      
      // undo move.
      g_empty_squares += 2;
      toggle_move(movelist[i], whos_turn);
      toggle_hash_code
    (g_keyinfo[whos_turn][movelist[i].array_index][movelist[i].mask_index]);
#ifdef DYNAMIC_POSITION_VALUES
      if(dyn_set != 0) unset_move_value(movelist[i], whos_turn);
#endif

#if 0
      if(starting_depth - depth_remaining == 8) {
        s32bit g;
        
        printf("goof:");
        
        for(g = 0; g < 8; g++){
          printf(" :%c:%d(%d,%d)", 
                 (g_move_player[g] == VERTICAL) ? 'V' : 'H',
                 g_move_number[g],
                 g_move_position[g].array_index - 1,
                 g_move_position[g].mask_index - 1);
        }
        printf("\n");
      }
#endif

      // If this is a cutoff, break.
      if(value >= beta){
        alpha = value;
        best  = movelist[i];
        
#ifdef COLLECT_STATS
        stat_cutoffs[starting_depth - depth_remaining]++;
        if(i < 5) stat_nth_try[starting_depth - depth_remaining][i]++;
        else      stat_nth_try[starting_depth - depth_remaining][5]++;
#endif
        break;
      }
      
      // If the current value is greater than alpha, increase alpha.
      if(value > alpha) {
        alpha = value;
        best  = movelist[i];
      }
    }

    // If we have broken out of previous FOR loop make sure we break out
    //   of this loop as well.
    if(value >= beta) break;
  }
  
  // save the position in the hashtable
  hashstore(alpha, init_alpha, init_beta, (g_num_nodes - start_nodes) >> 5,
            depth_remaining, best, whos_turn);
  
  return alpha;
}
Esempio n. 3
0
void
ponder_move( int side_to_move, int book, int mid, int exact, int wld ) {
  EvaluationType eval_info;
  HashEntry entry;
  double move_start_time, move_stop_time;
  int i, j;
  int this_move, hash_move;
  int expect_count;
  int stored_echo;
  int best_pv_depth;
  int expect_list[64];
  int best_pv[61];

  /* Disable all time control mechanisms as it's the opponent's
     time we're using */

  toggle_abort_check( FALSE );
  toggle_midgame_abort_check( FALSE );
  start_move( 0, 0, disc_count( BLACKSQ ) + disc_count( WHITESQ ) );
  clear_ponder_times();
  determine_hash_values( side_to_move, board );

  reset_counter( &nodes );

  /* Find the scores for the moves available to the opponent. */

  hash_move = 0;
  find_hash( &entry, ENDGAME_MODE );
  if ( entry.draft != NO_HASH_MOVE )
    hash_move = entry.move[0];
  else {
    find_hash( &entry, MIDGAME_MODE );
    if ( entry.draft != NO_HASH_MOVE )
      hash_move = entry.move[0];
  }

  stored_echo = echo;
  echo = FALSE;
  (void) compute_move( side_to_move, FALSE, 0, 0, FALSE, FALSE,
		       MIN( PONDER_DEPTH, mid ), 0, 0, FALSE, &eval_info );
  echo = stored_echo;

  /* Sort the opponents on the score and push the table move (if any)
     to the front of the list */

  if ( force_return )
    expect_count = 0;
  else {
    sort_moves( move_count[disks_played] );
    (void) float_move( hash_move, move_count[disks_played] );

    expect_count = move_count[disks_played];
    for ( i = 0; i < expect_count; i++ )
      expect_list[i] = move_list[disks_played][i];

#if TEXT_BASED
    printf( "%s=%d\n", HASH_MOVE_TEXT, hash_move );
    for ( i = 0; i < expect_count; i++ ) {
      printf( "%c%c %-6.2f  ", TO_SQUARE( move_list[disks_played][i] ),
	      evals[disks_played][move_list[disks_played][i]] / 128.0 );
      if ( (i % 7 == 6) || (i == expect_count - 1) )
	puts( "" );
    }
#endif
  }

  /* Go through the expected moves in order and prepare responses. */

  best_pv_depth = 0;
  for ( i = 0; !force_return && (i < expect_count); i++ ) {
    move_start_time = get_real_timer();
    set_ponder_move( expect_list[i] );
    this_move = expect_list[i];
    prefix_move = this_move;
    (void) make_move( side_to_move, this_move, TRUE );
    (void) compute_move( OPP( side_to_move ), FALSE, 0, 0, TRUE, FALSE,
			 mid, exact, wld, FALSE, &eval_info );
    unmake_move( side_to_move, this_move );
    clear_ponder_move();
    move_stop_time =  get_real_timer();
    add_ponder_time( expect_list[i], move_stop_time - move_start_time );
    ponder_depth[expect_list[i]] =
      MAX( ponder_depth[expect_list[i]], max_depth_reached - 1 );
    if ( (i == 0) && !force_return ) {  /* Store the PV for the first move */
      best_pv_depth = pv_depth[0];
      for ( j = 0; j < pv_depth[0]; j++ )
	best_pv[j] = pv[0][j];
    }
  }

  /* Make sure the PV looks reasonable when leaving - either by
     clearing it altogether or, preferrably, using the stored PV for
     the first move if it is available. */

  max_depth_reached++;
  prefix_move = 0;
  if ( best_pv_depth == 0 )
    pv_depth[0] = 0;
  else {
    pv_depth[0] = best_pv_depth + 1;
    pv[0][0] = expect_list[0];
    for ( i = 0; i < best_pv_depth; i++ )
      pv[0][i + 1] = best_pv[i];
  }

  /* Don't forget to enable the time control mechanisms when leaving */

  toggle_abort_check( TRUE );
  toggle_midgame_abort_check( TRUE );
}