// MOBILITY heuristic: safe squares around king of color color.
int mobility(position_t *p, color_t color) {
  char* laser_map;
  if (color == WHITE) {
    laser_map = laser_map_black;
  } else {
    laser_map = laser_map_white;
  }
  int mobility = 0;
  square_t king_sq = p->kloc[color];
  tbassert(ptype_of(p->board[king_sq]) == KING,
           "ptype: %d\n", ptype_of(p->board[king_sq]));
  tbassert(color_of(p->board[king_sq]) == color,
           "color: %d\n", color_of(p->board[king_sq]));

  if (laser_map[king_sq] == 0) {
    mobility++;
  }
  for (int d = 0; d < 8; ++d) {
    square_t sq = king_sq + dir_of(d);
    if (laser_map[sq] == 0) {
      mobility++;
    }
  }
  return mobility;
}
static void update_best_move_history(position_t *p, int index_of_best,
                                     sortable_move_t* lst, int count) {
  tbassert(ENABLE_TABLES, "Tables weren't enabled.\n");

  int color_to_move = color_to_move_of(p);

  for (int i = 0; i < count; i++) {
    move_t   mv  = get_move(lst[i]);
    ptype_t  pce = ptype_mv_of(mv);
    rot_t    ro  = rot_of(mv);  // rotation
    square_t fs  = from_square(mv);
    int      ot  = ORI_MASK & (ori_of(p->board[fs]) + ro);
    square_t ts  = to_square(mv);

    int  s = best_move_history[BMH(color_to_move, pce, ts, ot)];

    if (index_of_best == i) {
      s = s + 11200;  // number will never exceed 1017
    }
    s = s * 0.90;  // decay score over time

    tbassert(s < 102000, "s = %d\n", s);  // or else sorting will fail

    best_move_history[BMH(color_to_move, pce, ts, ot)] = s;
  }
}
// Marks the path of the laser until it hits a piece or goes off the board. 
// Returns the number of unpinned pawns.
//
// p : current board state
// laser_map : end result will be stored here. Every square on the
//             path of the laser is marked with mark_mask
// c : color of king shooting laser
// mark_mask: what each square is marked with
int mark_laser_path(position_t *p, char *laser_map, color_t c,
                     char mark_mask) {
  int pinned_pawns = 0;
  uint8_t total_pawns;
  color_t color = opp_color(c);
  square_t o_king_sq = p->kloc[color];

  if (c == WHITE) { // opposing king pins our pawns 
    total_pawns = p->pawn_count[BLACK];
  } else {
    total_pawns = p->pawn_count[WHITE];
  }

  // Fire laser, recording in laser_map
  square_t sq = p->kloc[c];
  int bdir = ori_of(p->board[sq]);
  int beam = beam_of(bdir);

  tbassert(ptype_of(p->board[sq]) == KING,
           "ptype: %d\n", ptype_of(p->board[sq]));
  laser_map[sq] |= mark_mask;

  // we update h_attackable here
  h_attackable = h_dist(sq, o_king_sq);

  while (true) {
    sq += beam;
    laser_map[sq] |= mark_mask;
    tbassert(sq < ARR_SIZE && sq >= 0, "sq: %d\n", sq);

    switch (ptype_of(p->board[sq])) {
      case EMPTY:  // empty square
        h_attackable += h_dist(sq, o_king_sq);
        break;
      case PAWN:  // Pawn
        h_attackable += h_dist(sq, o_king_sq);
        if (color_of(p->board[sq]) == color) {
          pinned_pawns += 1;
        }
        bdir = reflect_of(bdir, ori_of(p->board[sq]));
        if (bdir < 0) {  // Hit back of Pawn
          return total_pawns - pinned_pawns;
        }
        beam = beam_of(bdir);
        break;
      case KING:  // King
        h_attackable += h_dist(sq, o_king_sq);
          return total_pawns - pinned_pawns;
        break;
      case INVALID:  // Ran off edge of board
        return total_pawns - pinned_pawns;
        break;
      default:  // Shouldna happen, man!
        tbassert(false, "Not cool, man.  Not cool.\n");
        break;
    }
  }
}
Esempio n. 4
0
// Translate a position struct into a fen string
// NOTE: When you use the test framework in search.c, you should modify this
// function to match your optimized board representation in move_gen.c
//
// Input:   (populated) position struct
//          empty string where FEN characters will be written
// Output:   null
int pos_to_fen(position_t *p, char *fen) {
  int pos = 0;
  int i;

  for (rnk_t r = BOARD_WIDTH - 1; r >=0 ; --r) {
    int empty_in_a_row = 0;
    for (fil_t f = 0; f < BOARD_WIDTH; ++f) {
      piece_t piece = get_piece(p, r, f, &base_board);
      if (ptype_of(piece) == INVALID) {     // invalid square
        tbassert(false, "Bad news, yo.\n");        // This is bad!
      }

      if (ptype_of(piece) == EMPTY) {       // empty square
        empty_in_a_row++;
        continue;
      } else {
        if (empty_in_a_row) fen[pos++] = '0' + empty_in_a_row;
        empty_in_a_row = 0;
        int ori = ori_of(piece);  // orientation
        color_t c = color_of(piece);

        if (ptype_of(piece) == KING) {
          for (i = 0; i < 2; i++) fen[pos++] = king_ori_to_rep[c][ori][i];
          continue;
        }

        if (ptype_of(piece) == PAWN) {
          for (i = 0; i < 2; i++) fen[pos++] = pawn_ori_to_rep[c][ori][i];
          continue;
        }
      }
    }
    // assert: for larger boards, we need more general solns
    tbassert(BOARD_WIDTH <= 10, "BOARD_WIDTH = %d\n", BOARD_WIDTH);
    if (empty_in_a_row == 10) {
      fen[pos++] = '1';
      fen[pos++] = '0';
    } else if (empty_in_a_row) {
      fen[pos++] = '0' + empty_in_a_row;
    }
    if (r) fen[pos++] = '/';
  }
  fen[pos++] = ' ';
  fen[pos++] = 'W';
  fen[pos++] = '\0';

  return pos;
}
Esempio n. 5
0
// converts a move to string notation for FEN
void move_to_str(move_t mv, char *buf, size_t bufsize) {
  square_t f = from_square(mv);  // from-square
  square_t t = to_square(mv);    // to-square
  rot_t r = rot_of(mv);          // rotation
  const char *orig_buf = buf;

  buf += square_to_str(f, buf, bufsize);
  if (f != t) {
    buf += square_to_str(t, buf, bufsize - (buf - orig_buf));
  } else {
    switch (r) {
      case NONE:
        buf += square_to_str(t, buf, bufsize - (buf - orig_buf));
        break;
      case RIGHT:
        buf += snprintf(buf, bufsize - (buf - orig_buf), "R");
        break;
      case UTURN:
        buf += snprintf(buf, bufsize - (buf - orig_buf), "U");
        break;
      case LEFT:
        buf += snprintf(buf, bufsize - (buf - orig_buf), "L");
        break;
      default:
        tbassert(false, "Whoa, now.  Whoa, I say.\n");  // Bad, bad, bad
        break;
    }
  }
}
// KAGGRESSIVE heuristic: bonus for King with more space to back
ev_score_t kaggressive_old(position_t *p, fil_t f, rnk_t r) {
  square_t sq = square_of(f, r);
  piece_t x = p->board[sq];
  color_t c = color_of(x);
  tbassert(ptype_of(x) == KING, "ptype_of(x) = %d\n", ptype_of(x));

  square_t opp_sq = p->kloc[opp_color(c)];
  fil_t of = fil_of(opp_sq);
  rnk_t _or = (rnk_t) rnk_of(opp_sq);

  int delta_fil = of - f;
  int delta_rnk = _or - r;

  int bonus = 0;

  if (delta_fil >= 0 && delta_rnk >= 0) {
    bonus = (f + 1) * (r + 1);
  } else if (delta_fil <= 0 && delta_rnk >= 0) {
    bonus = (BOARD_WIDTH - f) * (r + 1);
  } else if (delta_fil <= 0 && delta_rnk <= 0) {
    bonus = (BOARD_WIDTH - f) * (BOARD_WIDTH - r);
  } else if (delta_fil >= 0 && delta_rnk <= 0) {
    bonus = (f + 1) * (BOARD_WIDTH - r);
  }

  return (KAGGRESSIVE * bonus) / (BOARD_WIDTH * BOARD_WIDTH);
}
Esempio n. 7
0
// KFACE heuristic: bonus (or penalty) for King facing toward the other King
ev_score_t kface(position_t *p, rnk_t r, fil_t f, full_board_t* board) {
  piece_t x = get_piece(p, r, f, board);
  color_t c = color_of(x);
  square_t opp_sq = board->pieces[opp_color(c)][0];
  int delta_fil = fil_of(opp_sq) - f;
  int delta_rnk = rnk_of(opp_sq) - r;
  int bonus;

  switch (ori_of(x)) {
    case NN:
      bonus = delta_rnk;
      break;

    case EE:
      bonus = delta_fil;
      break;

    case SS:
      bonus = -delta_rnk;
      break;

    case WW:
      bonus = -delta_fil;
      break;

    default:
      bonus = 0;
      tbassert(false, "Illegal King orientation.\n");
  }

  return (bonus * KFACE) / (abs(delta_rnk) + abs(delta_fil));
}
Esempio n. 8
0
// Helper method that finds all "small" primes -- primes in [0, 2^32).
static sieve_t* find_small_primes(void) {
    int64_t upper_bound = (int64_t)((double)1.42 * ((int64_t)1 << 31));
    sieve_t *sieve = create_sieve(upper_bound);
    if (NULL == sieve) {
        fprintf(stderr, "Failed to create SMALL_PRIMES sieve of length %"PRId64".\n"\
                "This failure can occur if there is insufficient physical memory on the system.\n"\
                "Aborting.\n", upper_bound);
        exit(1);
    }

    init_sieve(sieve);

    mark_composite(sieve, 0);
    mark_composite(sieve, 1);

    // Scan the entries of the sieve from 2 to UPPER_BOUND
    for (int64_t i = 2; i < upper_bound; ++i) {
        tbassert(trialdiv_prime_p(i) == prime_p(sieve, i),
                 "Incorrect primality recorded for %"PRId64" (%d vs %d)\n",
                 i, trialdiv_prime_p(i), prime_p(sieve, i));

        // Skip any I marked as composite
        if (!prime_p(sieve, i)) {
            continue;
        }

        // At this point, I is prime.
        // Mark all multiples of I as composite.
        for (int64_t j = 2; i * j < upper_bound; ++j) {
            mark_composite(sieve, i * j);
        }
    }

    return sieve;
}
Esempio n. 9
0
// KAGGRESSIVE heuristic: bonus for King with more space to back
ev_score_t kaggressive(position_t *p, rnk_t r, fil_t f, full_board_t* board) {
  piece_t x = get_piece(p, r, f, board);
  color_t c = color_of(x);
  tbassert(ptype_of(x) == KING, "ptype_of(x) = %d\n", ptype_of(x));

  square_t opp_sq = board->pieces[opp_color(c)][0];
  fil_t of = fil_of(opp_sq);
  rnk_t _or = (rnk_t) rnk_of(opp_sq);

  int delta_fil = of - f;
  int delta_rnk = _or - r;

  int bonus = 0;

  if (delta_fil >= 0 && delta_rnk >= 0) {
    bonus = (f + 1) * (r + 1);
  } else if (delta_fil <= 0 && delta_rnk >= 0) {
    bonus = (BOARD_WIDTH - f) * (r + 1);
  } else if (delta_fil <= 0 && delta_rnk <= 0) {
    bonus = (BOARD_WIDTH - f) * (BOARD_WIDTH - r);
  } else if (delta_fil >= 0 && delta_rnk <= 0) {
    bonus = (f + 1) * (BOARD_WIDTH - r);
  }

  return (KAGGRESSIVE * bonus) / (BOARD_WIDTH * BOARD_WIDTH);
}
Esempio n. 10
0
static void set_sort_key(sortable_move_t *mv, sort_key_t key) {
  // sort keys must not exceed SORT_MASK
  //  assert ((0 <= key) && (key <= SORT_MASK));
  tbassert(*mv <= SORT_MASK, "set_sort_key assumes high bits of mv are 0");
  *mv |= ((uint64_t)key & SORT_MASK) << SORT_SHIFT;
  return;
}
Esempio n. 11
0
// check the victim pieces returned by the move to determine if it's a
// game-over situation.  If so, also calculate the score depending on
// the pov (which player's point of view)
static bool is_game_over(victims_t victims, int pov, int ply) {
  tbassert(ptype_of(victims.stomped) != KING, "Stomped a king.\n");
  if (ptype_of(victims.zapped) == KING) {
    return true;
  }
  return false;
}
Esempio n. 12
0
// KFACE heuristic: bonus (or penalty) for King facing toward the other King
ev_score_t kface(position_t *p, fil_t f, rnk_t r) {
  square_t sq = square_of(f, r);
  piece_t x = p->board[sq];
  color_t c = color_of(x);
  square_t opp_sq = p->kloc[opp_color(c)];
  int delta_fil = fil_of(opp_sq) - f;
  int delta_rnk = rnk_of(opp_sq) - r;
  int bonus;

  switch (ori_of(x)) {
    case NN:
      bonus = delta_rnk;
      break;

    case EE:
      bonus = delta_fil;
      break;

    case SS:
      bonus = -delta_rnk;
      break;

    case WW:
      bonus = -delta_fil;
      break;

    default:
      bonus = 0;
      tbassert(false, "Illegal King orientation.\n");
  }

  return (bonus * KFACE) / (abs(delta_rnk) + abs(delta_fil));
}
Esempio n. 13
0
// MOBILITY heuristic: safe squares around king of color color.
int mobility(position_t *p, color_t color, char* laser_map, full_board_t* board) {
  int mobility = 0;
  square_t king_sq = board->pieces[color][0];
  tbassert(ptype_of(board->board[king_sq]) == KING,
           "ptype: %d\n", ptype_of(board->board[king_sq]));
  tbassert(color_of(board->board[king_sq]) == color,
           "color: %d\n", color_of(board->board[king_sq]));

  if (laser_map[king_sq] == 0) {
    mobility++;
  }
  for (int d = 0; d < 8; ++d) {
    square_t sq = king_sq + dir_of(d);
    if (in_bounds(sq) && laser_map[sq] == 0) {
      mobility++;
    }
  }
  return mobility;
}
Esempio n. 14
0
static score_t get_game_over_score(victims_t victims, int pov, int ply) {
  tbassert(ptype_of(victims.stomped) != KING, "Stomped a king.\n");
  score_t score;
  if (color_of(victims.zapped) == WHITE) {
    score = -WIN * pov;
  } else {
    score = WIN * pov;
  }
  if (score < 0) {
    score += ply;
  } else {
    score -= ply;
  }
  return score;
}
Esempio n. 15
0
// H_SQUARES_ATTACKABLE heuristic: for shooting the enemy king
int h_squares_attackable(position_t *p, color_t c) {
  char* laser_map;
  if (c == WHITE) {
    laser_map = laser_map_white;
  } else {
    laser_map = laser_map_black;
  }
  square_t o_king_sq = p->kloc[opp_color(c)];
  tbassert(ptype_of(p->board[o_king_sq]) == KING,
           "ptype: %d\n", ptype_of(p->board[o_king_sq]));
  tbassert(color_of(p->board[o_king_sq]) != c,
           "color: %d\n", color_of(p->board[o_king_sq]));

  float h_attackable_temp = 0;
  for (fil_t f = 0; f < BOARD_WIDTH; f++) {
    for (rnk_t r = 0; r < BOARD_WIDTH; r++) {
      square_t sq = square_of(f, r);
      if (laser_map[sq] != 0) {
        h_attackable_temp += h_dist(sq, o_king_sq);
      }
    }
  }
  return h_attackable_temp;
}
Esempio n. 16
0
//TODO: make euphoric by just subtracting 2 values in a sum table instead
static inline float fast_h_dist(square_t start, square_t end, rnk_t k_rnk, fil_t k_fil) {
  tbassert(start >= 4, "olooloo\n");

  rnk_t start_r = rnk_of(start);
  rnk_t end_r = rnk_of(end);
  fil_t start_f = fil_of(start);
  fil_t end_f = fil_of(end);
  if (start_r == end_r) {
    float length = abs(start_f - end_f);

    int firstDist = k_fil - start_f;
    int secondDist = k_fil - end_f;
    secondDist += ((firstDist > secondDist) - (secondDist > firstDist));

    float partial_sum;
    if(firstDist*secondDist > 0){ //same sign, disjoint segment
      partial_sum = fabsf(harmonicSum[abs(firstDist)] - harmonicSum[abs(secondDist)]) + h_table[MIN(abs(firstDist), abs(secondDist))];
    } else {
      partial_sum = harmonicSum[abs(firstDist)] + harmonicSum[abs(secondDist)] - 1;
    }

    return partial_sum + length * h_table[abs(start_r - k_rnk)];
  } else {
    float length = abs(start_r - end_r);

    int firstDist = k_rnk - start_r;
    int secondDist = k_rnk - end_r;
    secondDist += ((firstDist > secondDist) - (secondDist > firstDist));

    float partial_sum;
    if(firstDist*secondDist > 0){ //same sign, disjoint segment
      partial_sum = fabsf(harmonicSum[abs(firstDist)] - harmonicSum[abs(secondDist)]) + h_table[MIN(abs(firstDist), abs(secondDist))];
    } else {
      partial_sum = harmonicSum[abs(firstDist)] + harmonicSum[abs(secondDist)] - 1;
    }

    return partial_sum + length * h_table[abs(start_f - k_fil)];
  }
}
Esempio n. 17
0
// Static evaluation.  Returns score
score_t eval(position_t *p, bool verbose, full_board_t* board) {
  // seed rand_r with a value of 1, as per
  // http://linux.die.net/man/3/rand_r
  static __thread unsigned int seed = 1;
  // verbose = true: print out components of score
  ev_score_t score[2] = { 0, 0 };
  //  int corner[2][2] = { {INF, INF}, {INF, INF} };
  ev_score_t bonus;

  color_t c = WHITE;
  while (true) {
    for (pnum_t pnum = 0; pnum <= board->pawn_count[c]; pnum++) {
      square_t sq = board->pieces[c][pnum];
      rnk_t r = rnk_of(sq);
      fil_t f = fil_of(sq);
      piece_t x = board->board[sq];

      switch (ptype_of(x)) {
        case EMPTY:
          tbassert(false, "Jose says: no way!\n");   // No way, Jose!
        case PAWN:
          // PBETWEEN heuristic
          bonus = pbetween(p, r, f, board);
          score[c] += bonus;

          // PCENTRAL heuristic
          bonus = pcentral(r, f);
          score[c] += bonus;
          break;

        case KING:
          // KFACE heuristic
          bonus = kface(p, r, f, board);
          score[c] += bonus;

          // KAGGRESSIVE heuristic
          bonus = kaggressive(p, r, f, board);
          score[c] += bonus;
          break;
        case INVALID:
          tbassert(false, "Jose says: no way!\n");   // No way, Jose!
        default:
          tbassert(false, "Jose says: no way!\n");   // No way, Jose!
      }
    }
    if (c == BLACK)
      break;
    c = BLACK;
  }

  score[WHITE] += board->pawn_count[WHITE] * PAWN_EV_VALUE;
  score[BLACK] += board->pawn_count[BLACK] * PAWN_EV_VALUE;

  square_t white_laser_list[MAX_NUM_PIECES];
  square_t black_laser_list[MAX_NUM_PIECES];

  int whitePathCount = get_laser_path_list(p, white_laser_list, WHITE, board);
  int blackPathCount = get_laser_path_list(p, black_laser_list, BLACK, board);

  ev_score_t w_hattackable = HATTACK * h_squares_attackable(p, WHITE, white_laser_list, whitePathCount, board);
  score[WHITE] += w_hattackable;
  ev_score_t b_hattackable = HATTACK * h_squares_attackable(p, BLACK, black_laser_list, blackPathCount, board);
  score[BLACK] += b_hattackable;

  int w_mobility_list = MOBILITY * mobility_list(p, WHITE, black_laser_list, blackPathCount, board);
  score[WHITE] += w_mobility_list;

  int b_mobility_list = MOBILITY * mobility_list(p, BLACK, white_laser_list, whitePathCount, board);
  score[BLACK] += b_mobility_list;

  // PAWNPIN Heuristic --- is a pawn immobilized by the enemy laser.
  int w_pawnpin = PAWNPIN * pawnpin(p, WHITE, black_laser_list, blackPathCount, board); //use other color's laser map
  score[WHITE] += w_pawnpin;
  int b_pawnpin = PAWNPIN * pawnpin(p, BLACK, white_laser_list, whitePathCount, board); //use other color's laser map
  score[BLACK] += b_pawnpin;

  // score from WHITE point of view
  ev_score_t tot = score[WHITE] - score[BLACK];

  if (RANDOMIZE) {
    ev_score_t  z = rand_r(&seed) % (RANDOMIZE*2+1);
    tot = tot + z - RANDOMIZE;
  }

  if (color_to_move_of(p) == BLACK) {
    tot = -tot;
  }



  return tot / EV_SCORE_RATIO;
}
Esempio n. 18
0
// Helper function for COUNT_PRIMES_IN_INTERVAL() to count the number
// of primes in [START, START+LENGTH) where 0 < LENGTH <=
// MAX_SIEVE_LENGTH.  Returns the number of primes in [START,
// START+LENGTH).
//
//   START -- The low endpoint of the interval.
//
//   LENGTH -- The length of the interval.
//
//   SMALL_PRIMES -- Sieve recording all primes in [0,2^32).
//
static int64_t count_primes_in_interval_helper(int64_t start, int64_t length,
        const sieve_t* small_primes) {
    int64_t num_primes;

    // Create LARGE_PRIMES structures to record the primes in
    // [START,START+LENGTH), where index I in LARGE_PRIMES corresponds
    // to the integer LOW+I.
    sieve_t *large_primes = create_sieve(length);
    if (NULL == large_primes) {
        fprintf(stderr, "Failed to create LARGE_PRIMES sieve of length %"PRId64".\n"\
                "This can happen if there is insufficient physical memory on the system.\n"\
                "Aborting.\n", length);
        exit(1);
    }

    init_sieve(large_primes);

    // Scan all of the potentially prime entries in the SMALL_PRIMES
    // sieve.
    for (int64_t p = 2; p < small_primes->length; ++p) {
        tbassert(trialdiv_prime_p(p) == prime_p(small_primes, p),
                 "Incorrect primality recorded for %"PRId64" in small_primes\n",
                 p);

        // Skip any entry in SMALL_PRIMES marked as composite.
        if (!prime_p(small_primes, p)) {
            continue;
        }

        // At this point, P is a prime.
        /* DEBUG_EPRINTF("p = %ld\n", p); */

        // Find index KP_INDEX of smallest multiple of <p> in range
        // [START,START+LENGTH).
        int64_t kp_index = start % p;
        if (0 != kp_index) {
            kp_index = p - kp_index;
        }
        if (start + kp_index == p) {
            kp_index += p;
        }

        /* DEBUG_EPRINTF("kp_index = %"PRId64"\n", kp_index); */

        // Mark all multiples of P in [KP_INDEX, KP_INDEX+LENGTH) as
        // composite.
        for ( ; kp_index < length; kp_index += p) {
            mark_composite(large_primes, kp_index);
        }
    }

    // Count number of primes in LARGE_PRIMES.
    num_primes = 0;
    for (int64_t i = 0; i < length; ++i) {
        tbassert(trialdiv_prime_p(i + start) == prime_p(large_primes, i),
                 "Incorrect primality recorded for %"PRId64" in large_primes (index %"PRId64")\n",
                 i + start, i);

        if (prime_p(large_primes, i)) {
            ++num_primes;
        }
    }

    // Free LARGE_PRIMES structure
    destroy_sieve(large_primes);

    return num_primes;
}
Esempio n. 19
0
static score_t get_game_over_score(victims_t* victims, int pov, int ply) {
  tbassert(ptype_of(victims->stomped) != KING, "Stomped a king.\n");
  // score negative when victims.zapped == WHITE
  score_t score = -1*(1 - 2*(color_of(victims->zapped)))*WIN*pov;
  return score + (1 - 2*(score >= 0))*ply;
}
static score_t scout_search(searchNode *node, int depth,
                            uint64_t *node_count_serial) {
  // Initialize the search node.
  initialize_scout_node(node, depth);

  // check whether we should abort
  if (should_abort_check() || parallel_parent_aborted(node)) {
    return 0;
  }

  // Pre-evaluate this position.
  leafEvalResult pre_evaluation_result = evaluate_as_leaf(node, SEARCH_SCOUT);

  // If we decide to stop searching, return the pre-evaluation score.
  if (pre_evaluation_result.type == MOVE_EVALUATED) {
    return pre_evaluation_result.score;
  }

  // Populate some of the fields of this search node, using some
  //  of the information provided by the pre-evaluation.
  int hash_table_move = pre_evaluation_result.hash_table_move;
  node->best_score = pre_evaluation_result.score;
  node->quiescence = pre_evaluation_result.should_enter_quiescence;

  // Grab the killer-moves for later use.
  move_t killer_a = killer[KMT(node->ply, 0)];
  move_t killer_b = killer[KMT(node->ply, 1)];

  // Store the sorted move list on the stack.
  //   MAX_NUM_MOVES is all that we need.
  sortable_move_t move_list[MAX_NUM_MOVES];

  // Obtain the sorted move list.
  int num_of_moves = get_sortable_move_list(node, move_list, hash_table_move);

  int number_of_moves_evaluated = 0;


  // A simple mutex. See simple_mutex.h for implementation details.
  simple_mutex_t node_mutex;
  init_simple_mutex(&node_mutex);

  // Sort the move list.
  sort_incremental(move_list, num_of_moves, 0);
  
  moveEvaluationResult result;

  for (int mv_index = 0; mv_index < num_of_moves; mv_index++) {
    if (mv_index == 1) {
      sort_full(move_list, num_of_moves);
     // sortable_move_t new_move_list[MAX_NUM_MOVES];
      //memcpy(new_move_list, move_list, num_of_moves*sizeof(sortable_move_t));
     //: sort_incremental_full(move_list,num_of_moves);
    }
    // Get the next move from the move list.
    int local_index = number_of_moves_evaluated++;
    move_t mv = get_move(move_list[local_index]);

    if (TRACE_MOVES) {
      print_move_info(mv, node->ply);
    }

    // increase node count
    __sync_fetch_and_add(node_count_serial, 1);

    evaluateMove(&result, node, mv, killer_a, killer_b,
                 SEARCH_SCOUT,
                 node_count_serial);
    undo_move(&result.next_node, mv);

    if (result.type == MOVE_ILLEGAL || result.type == MOVE_IGNORE
        || abortf || parallel_parent_aborted(node)) {
      continue;
    }

    // A legal move is a move that's not KO, but when we are in quiescence
    // we only want to count moves that has a capture.
    if (result.type == MOVE_EVALUATED) {
      node->legal_move_count++;
    }

    // process the score. Note that this mutates fields in node.
    bool cutoff = search_process_score(node, mv, local_index, &result, SEARCH_SCOUT);

    if (cutoff) {
      node->abort = true;
      break;
    }
  }

  if (parallel_parent_aborted(node)) {
    return 0;
  }

  if (node->quiescence == false) {
    update_best_move_history(node->position, node->best_move_index,
                             move_list, number_of_moves_evaluated);
  }

  tbassert(abs(node->best_score) != -INF, "best_score = %d\n",
           node->best_score);

  // Reads node->position->key, node->depth, node->best_score, and node->ply
  update_transposition_table(node);

  return node->best_score;
}
Esempio n. 21
0
// Static evaluation.  Returns score
score_t eval(position_t *p, bool verbose) {
  // seed rand_r with a value of 1, as per
  // http://linux.die.net/man/3/rand_r
  static __thread unsigned int seed = 1;
  // verbose = true: print out components of score
  ev_score_t score[2] = { 0, 0 };
  //  int corner[2][2] = { {INF, INF}, {INF, INF} };
  ev_score_t bonus;

  //char buf[MAX_CHARS_IN_MOVE];
  color_t c;
  for (fil_t f = 0; f < BOARD_WIDTH; f++) {
    for (rnk_t r = 0; r < BOARD_WIDTH; r++) {
      square_t sq = square_of(f, r);
      piece_t x = p->board[sq];

      //if (verbose) {
      //  square_to_str(sq, buf, MAX_CHARS_IN_MOVE);
      //}

      switch (ptype_of(x)) {
        case EMPTY:
          break;
        case PAWN:
          c = color_of(x);

          // MATERIAL heuristic: Bonus for each Pawn
          bonus = PAWN_EV_VALUE;
          // if (verbose) {
          //  printf("MATERIAL bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf);
          // }
          score[c] += bonus;

          // PBETWEEN heuristic
          bonus = pbetween(p, f, r);
          // if (verbose) {
          //   printf("PBETWEEN bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf);
          // }
          score[c] += bonus;

          // PCENTRAL heuristic
          bonus = pcentral(f, r);
          // if (verbose) {
          //   printf("PCENTRAL bonus %d for %s Pawn on %s\n", bonus, color_to_str(c), buf);
         //  }
          score[c] += bonus;
          break;

        case KING:
          c = color_of(x);

          // KFACE heuristic
          bonus = kface(p, f, r);
          // if (verbose) {
          //   printf("KFACE bonus %d for %s King on %s\n", bonus,
          //          color_to_str(c), buf);
          // }
          score[c] += bonus;

          // KAGGRESSIVE heuristic
          color_t othercolor = opp_color(c);
          square_t otherking = p->kloc[othercolor];
          fil_t otherf = fil_of(otherking);
          rnk_t otherr = rnk_of(otherking);
          bonus = kaggressive(f, r, otherf, otherr);
          assert(bonus == kaggressive_old(p, f, r));

          // if (verbose) {
          //   printf("KAGGRESSIVE bonus %d for %s King on %s\n", bonus, color_to_str(c), buf);
         //  }
          score[c] += bonus;
          break;
        case INVALID:
          break;
        default:
          tbassert(false, "Jose says: no way!\n");   // No way, Jose!
      }
      laser_map_black[sq] = 0;
      laser_map_white[sq] = 0;
    }
  }
   
  int black_pawns_unpinned = mark_laser_path(p, laser_map_white, WHITE, 1);  // 1 = path of laser with no moves
  
  ev_score_t w_hattackable = HATTACK * (int) h_attackable;
  score[WHITE] += w_hattackable;
  // if (verbose) {
  //   printf("HATTACK bonus %d for White\n", w_hattackable);
  // }

  // PAWNPIN Heuristic --- is a pawn immobilized by the enemy laser.
  int b_pawnpin = PAWNPIN * black_pawns_unpinned;
  score[BLACK] += b_pawnpin;

  int b_mobility = MOBILITY * mobility(p, BLACK);
  score[BLACK] += b_mobility;
  // if (verbose) {
  //   printf("MOBILITY bonus %d for Black\n", b_mobility);
  // }

  int white_pawns_unpinned = mark_laser_path(p, laser_map_black, BLACK, 1);  // 1 = path of laser with no moves
  
  ev_score_t b_hattackable = HATTACK * (int) h_attackable;
  score[BLACK] += b_hattackable;
  // if (verbose) {
  //   printf("HATTACK bonus %d for Black\n", b_hattackable);
  // }

  int w_mobility = MOBILITY * mobility(p, WHITE);
  score[WHITE] += w_mobility;
  // if (verbose) {
  //   printf("MOBILITY bonus %d for White\n", w_mobility);
  // }
  int w_pawnpin = PAWNPIN * white_pawns_unpinned;
  score[WHITE] += w_pawnpin;


  // score from WHITE point of view
  ev_score_t tot = score[WHITE] - score[BLACK];

  if (RANDOMIZE) {
    ev_score_t  z = rand_r(&seed) % (RANDOMIZE*2+1);
    tot = tot + z - RANDOMIZE;
  }

  if (color_to_move_of(p) == BLACK) {
    tot = -tot;
  }

  return tot / EV_SCORE_RATIO;
}
Esempio n. 22
0
int beam_of(int direction) {
  tbassert(direction >= 0 && direction < NUM_ORI, "dir: %d\n", direction);
  return beam[direction];
}
Esempio n. 23
0
// check the victim pieces returned by the move to determine if it's a
// game-over situation.  If so, also calculate the score depending on
// the pov (which player's point of view)
static bool is_game_over(victims_t* victims, int pov, int ply) {
  tbassert(ptype_of(victims->stomped) != KING, "Stomped a king.\n");
  return ptype_of(victims->zapped) == KING;
}
Esempio n. 24
0
int dir_of(int i) {
  tbassert(i >= 0 && i < 8, "i: %d\n", i);
  return dir[i];
}
Esempio n. 25
0
// Evaluate the move by performing a search.
void evaluateMove(searchNode *node, move_t mv, move_t killer_a,
                  move_t killer_b, searchType_t type,
                  uint64_t *node_count_serial, moveEvaluationResult* result) {
  int ext = 0;  // extensions
  bool blunder = false;  // shoot our own piece

  result->next_node.subpv[0] = 0;
  result->next_node.parent = node;

  // Make the move, and get any victim pieces.
  bool isko = make_move(&(node->position), &(result->next_node.position), mv);

  // Check whether this move changes the board state.
  //   such moves are not legal.
  if (isko) {
    result->type = MOVE_ILLEGAL;
    return;
  }

  victims_t* victims = &result->next_node.position.victims;

  // Check whether the game is over.
  if (is_game_over(victims, node->pov, node->ply)) {
    // Compute the end-game score.
    result->type = MOVE_GAMEOVER;
    result->score = get_game_over_score(victims, node->pov, node->ply);
    return;
  }

  // Ignore noncapture moves when in quiescence.
  if (zero_victims(victims) && node->quiescence) {
    result->type = MOVE_IGNORE;
    return;
  }

  // Check whether the board state has been repeated, this results in a draw.
  if (is_repeated(&(result->next_node.position), node->ply)) {
    result->type = MOVE_GAMEOVER;
    result->score = get_draw_score(&(result->next_node.position), node->ply);
    return;
  }

  tbassert(victims->stomped == 0
           || color_of(victims->stomped) != node->fake_color_to_move,
           "stomped = %d, color = %d, fake_color_to_move = %d\n",
           victims->stomped, color_of(victims->stomped),
           node->fake_color_to_move);


  // Check whether we caused our own piece to be zapped. This isn't considered
  //   a blunder if we also managed to stomp an enemy piece in the process.
  if (victims->stomped == 0 &&
      victims->zapped > 0 &&
      color_of(victims->zapped) == node->fake_color_to_move) {
    blunder = true;
  }

  // Do not consider moves that are blunders while in quiescence.
  if (node->quiescence && blunder) {
    result->type = MOVE_IGNORE;
    return;
  }

  // Extend the search-depth by 1 if we captured a piece, since that means the
  //   move was interesting.
  if (victim_exists(victims) && !blunder) {
    ext = 1;
  }

  // Late move reductions - or LMR. Only done in scout search.
  int next_reduction = 0;
  if (type == SEARCH_SCOUT && node->legal_move_count + 1 >= LMR_R1 && node->depth > 2 &&
      zero_victims(victims) && mv != killer_a && mv != killer_b) {
    if (node->legal_move_count + 1 >= LMR_R2) {
      next_reduction = 2;
    } else {
      next_reduction = 1;
    }
  }

  result->type = MOVE_EVALUATED;
  int search_depth = ext + node->depth - 1;

  // Check if we need to perform a reduced-depth search.
  //
  // After a reduced-depth search, a full-depth search will be performed if the
  //  reduced-depth search did not trigger a cut-off.
  if (next_reduction > 0) {
    search_depth -= next_reduction;
    int reduced_depth_score = -scout_search(&(result->next_node), search_depth,
                                            node_count_serial);
    if (reduced_depth_score < node->beta) {
      result->score = reduced_depth_score;
      return;
    }
    search_depth += next_reduction;
  }

  // Check if we should abort due to time control.
  if (abortf) {
    result->score = 0;
    result->type = MOVE_IGNORE;
    return;
  }


  if (type == SEARCH_SCOUT) {
    result->score = -scout_search(&(result->next_node), search_depth,
                                 node_count_serial);
  } else {
    if (node->legal_move_count == 0 || node->quiescence) {
      result->score = -searchPV(&(result->next_node), search_depth, node_count_serial);
    } else {
      result->score = -scout_search(&(result->next_node), search_depth,
                            node_count_serial);
      if (result->score > node->alpha) {
        result->score = -searchPV(&(result->next_node), node->depth + ext - 1, node_count_serial);
      }
    }
  }
}
Esempio n. 26
0
score_t searchRoot(position_t *p, score_t alpha, score_t beta, int depth,
                   int ply, move_t *pv, uint64_t *node_count_serial,
                   FILE *OUT) {
  static int num_of_moves = 0;  // number of moves in list
  // hopefully, more than we will need
  static sortable_move_t move_list[MAX_NUM_MOVES];

  if (depth == 1) {
    // we are at depth 1; generate all possible moves
    num_of_moves = generate_all_opt(p, move_list, false);
    // shuffle the list of moves
    for (int i = 0; i < num_of_moves; i++) {
      int r = myrand() % num_of_moves;
      sortable_move_t tmp = move_list[i];
      move_list[i] = move_list[r];
      move_list[r] = tmp;
    }
  }

  searchNode rootNode;
  rootNode.parent = NULL;
  initialize_root_node(&rootNode, alpha, beta, depth, ply, p);


  assert(rootNode.best_score == alpha);  // initial conditions

  searchNode next_node;
  next_node.subpv[0] = 0;
  next_node.parent = &rootNode;

  score_t score;

  for (int mv_index = 0; mv_index < num_of_moves; mv_index++) {
    move_t mv = get_move(move_list[mv_index]);

    if (TRACE_MOVES) {
      print_move_info(mv, ply);
    }

    (*node_count_serial)++;

    // make the move.
    victims_t x = make_move(&(rootNode.position), &(next_node.position), mv);

    if (is_KO(x)) {
      continue;  // not a legal move
    }

    if (is_game_over(x, rootNode.pov, rootNode.ply)) {
      score = get_game_over_score(x, rootNode.pov, rootNode.ply);
      next_node.subpv[0] = 0;
      goto scored;
    }

    if (is_repeated(&(next_node.position), rootNode.ply)) {
      score = get_draw_score(&(next_node.position), rootNode.ply);
      next_node.subpv[0] = 0;
      goto scored;
    }

    if (mv_index == 0 || rootNode.depth == 1) {
      // We guess that the first move is the principle variation
      score = -searchPV(&next_node, rootNode.depth-1, node_count_serial);

      // Check if we should abort due to time control.
      if (abortf) {
        return 0;
      }
    } else {
      score = -scout_search(&next_node, rootNode.depth-1, node_count_serial);

      // Check if we should abort due to time control.
      if (abortf) {
        return 0;
      }

      // If its score exceeds the current best score,
      if (score > rootNode.alpha) {
        score = -searchPV(&next_node, rootNode.depth-1, node_count_serial);
        // Check if we should abort due to time control.
        if (abortf) {
          return 0;
        }
      }
    }

  scored:
    // only valid for the root node:
    tbassert((score > rootNode.best_score) == (score > rootNode.alpha),
             "score = %d, best = %d, alpha = %d\n", score, rootNode.best_score, rootNode.alpha);

    if (score > rootNode.best_score) {
      tbassert(score > rootNode.alpha, "score: %d, alpha: %d\n", score, rootNode.alpha);

      rootNode.best_score = score;
      pv[0] = mv;
      memcpy(pv+1, next_node.subpv, sizeof(move_t) * (MAX_PLY_IN_SEARCH - 1));
      pv[MAX_PLY_IN_SEARCH - 1] = 0;

      // Print out based on UCI (universal chess interface)
      double et = elapsed_time();
      char   pvbuf[MAX_PLY_IN_SEARCH * MAX_CHARS_IN_MOVE];
      getPV(pv, pvbuf, MAX_PLY_IN_SEARCH * MAX_CHARS_IN_MOVE);
      if (et < 0.00001) {
        et = 0.00001;  // hack so that we don't divide by 0
      }

      uint64_t nps = 1000 * *node_count_serial / et;
      fprintf(OUT, "info depth %d move_no %d time (microsec) %d nodes %" PRIu64
              " nps %" PRIu64 "\n",
              depth, mv_index + 1, (int) (et * 1000), *node_count_serial, nps);
      fprintf(OUT, "info score cp %d pv %s\n", score, pvbuf);

      // Slide this move to the front of the move list
      for (int j = mv_index; j > 0; j--) {
        move_list[j] = move_list[j - 1];
      }
      move_list[0] = mv;
    }

    // Normal alpha-beta logic: if the current score is better than what the
    // maximizer has been able to get so far, take that new value.  Likewise,
    // score >= beta is the beta cutoff condition
    if (score > rootNode.alpha) {
      rootNode.alpha = score;
    }
    if (score >= rootNode.beta) {
      tbassert(0, "score: %d, beta: %d\n", score, rootNode.beta);
      break;
    }
  }

  return rootNode.best_score;
}
Esempio n. 27
0
int reflect_of(int beam_dir, int pawn_ori) {
  tbassert(beam_dir >= 0 && beam_dir < NUM_ORI, "beam-dir: %d\n", beam_dir);
  tbassert(pawn_ori >= 0 && pawn_ori < NUM_ORI, "pawn-ori: %d\n", pawn_ori);
  return reflect[beam_dir][pawn_ori];
}
Esempio n. 28
0
// Perform a Principle Variation Search
//   https://chessprogramming.wikispaces.com/Principal+Variation+Search
static score_t searchPV(searchNode *node, int depth, uint64_t *node_count_serial) {
  // Initialize the searchNode data structure.
  initialize_pv_node(node, depth);

  // Pre-evaluate the node to determine if we need to search further.
  leafEvalResult pre_evaluation_result = evaluate_as_leaf(node, SEARCH_PV);

  // use some information from the pre-evaluation
  int hash_table_move = pre_evaluation_result.hash_table_move;

  if (pre_evaluation_result.type == MOVE_EVALUATED) {
    return pre_evaluation_result.score;
  }
  if (pre_evaluation_result.score > node->best_score) {
    node->best_score = pre_evaluation_result.score;
    if (node->best_score > node->alpha) {
      node->alpha = node->best_score;
    }
  }

  // Get the killer moves at this node.
  move_t killer_a = killer[KMT(node->ply, 0)];
  move_t killer_b = killer[KMT(node->ply, 1)];


  // sortable_move_t move_list
  //
  // Contains a list of possible moves at this node. These moves are "sortable"
  //   and can be compared as integers. This is accomplished by using high-order
  //   bits to store a sort key.
  //
  // Keep track of the number of moves that we have considered at this node.
  //   After we finish searching moves at this node the move_list array will
  //   be organized in the following way:
  //
  //   m0, m1, ... , m_k-1, m_k, ... , m_N-1
  //
  //  where k = num_moves_tried, and N = num_of_moves
  //
  //  This will allow us to update the best_move_history table easily by
  //  scanning move_list from index 0 to k such that we update the table
  //  only for moves that we actually considered at this node.
  sortable_move_t move_list[MAX_NUM_MOVES];
  int num_of_moves = get_sortable_move_list(node, move_list, hash_table_move);
  int num_moves_tried = 0;

  // Start searching moves.
  for (int mv_index = 0; mv_index < num_of_moves; mv_index++) {
    // Incrementally sort the move list.
    sort_incremental(move_list, num_of_moves, mv_index);

    move_t mv = get_move(move_list[mv_index]);

    num_moves_tried++;
    (*node_count_serial)++;

    moveEvaluationResult result = evaluateMove(node, mv, killer_a, killer_b,
                                               SEARCH_PV,
                                               node_count_serial);

    if (result.type == MOVE_ILLEGAL || result.type == MOVE_IGNORE) {
      continue;
    }

    // A legal move is a move that's not KO, but when we are in quiescence
    // we only want to count moves that has a capture.
    if (result.type == MOVE_EVALUATED) {
      node->legal_move_count++;
    }

    // Check if we should abort due to time control.
    if (abortf) {
      return 0;
    }

    bool cutoff = search_process_score(node, mv, mv_index, &result, SEARCH_PV);
    if (cutoff) {
      break;
    }
  }

  if (node->quiescence == false) {
    update_best_move_history(&(node->position), node->best_move_index,
                             move_list, num_moves_tried);
  }

  tbassert(abs(node->best_score) != -INF, "best_score = %d\n",
           node->best_score);

  // Update the transposition table.
  //
  // Note: This function reads node->best_score, node->orig_alpha,
  //   node->position.key, node->depth, node->ply, node->beta,
  //   node->alpha, node->subpv
  update_transposition_table(node);

  return node->best_score;
}