// PBETWEEN heuristic: Bonus for Pawn at (f, r) in rectangle defined by Kings at the corners ev_score_t pbetween(position_t *p, rnk_t r, fil_t f, full_board_t* board) { bool is_between = between(f, fil_of(board->pieces[WHITE][0]), fil_of(board->pieces[BLACK][0])) && between(r, rnk_of(board->pieces[WHITE][0]), rnk_of(board->pieces[BLACK][0])); // return is_between ? PBETWEEN : 0; // changed for better branch prediction return (-((int) is_between)) & PBETWEEN; }
// Harmonic-ish distance: 1/(|dx|+1) + 1/(|dy|+1) float h_dist_old(square_t a, square_t b) { // printf("a = %d, FIL(a) = %d, RNK(a) = %d\n", a, FIL(a), RNK(a)); // printf("b = %d, FIL(b) = %d, RNK(b) = %d\n", b, FIL(b), RNK(b)); int delta_fil = abs(fil_of(a) - fil_of(b)); int delta_rnk = abs(rnk_of(a) - rnk_of(b)); float x = (1.0 / (delta_fil + 1)) + (1.0 / (delta_rnk + 1)); // printf("max_dist = %d\n\n", x); return x; }
// 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)); }
// 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); }
// 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)); }
// 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); }
// converts a square to string notation, returns number of characters printed int square_to_str(square_t sq, char *buf, size_t bufsize) { fil_t f = fil_of(sq); rnk_t r = rnk_of(sq); if (f >= 0) { return snprintf(buf, bufsize, "%c%d", 'a'+ f, r); } else { return snprintf(buf, bufsize, "%c%d", 'z' + f + 1, r); } }
int mobility_list(position_t *p, color_t color, square_t* laser_list, int laser_list_len, full_board_t* board) { int mobility = 0; square_t king_sq = board->pieces[color][0]; mobility++; for (int i = 0; i < laser_list_len-1; i++){ square_t start = laser_list[i]; square_t end = laser_list[i+1]; //check if the square is between laser_list[i] and laser_list[i+1]. if so add to mobility if(between(rnk_of(king_sq), rnk_of(start), rnk_of(end)) && between(fil_of(king_sq), fil_of(start), fil_of(end))) { mobility--; break; } } for (int d = 0; d < 8; ++d) { square_t sq = king_sq + dir_of(d); if (in_bounds(sq)) { mobility++; //decrement if it is in laser path for (int i = 0; i < laser_list_len-1; i++){ //check if the square is between laser_list[i] and laser_list[i+1]. if so add to mobility square_t start = laser_list[i]; square_t end = laser_list[i+1]; if(between(rnk_of(sq), rnk_of(start), rnk_of(end)) && between(fil_of(sq), fil_of(start), fil_of(end))) { mobility--; break; } } } } return mobility; }
//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)]; } }
// H_SQUARES_ATTACKABLE heuristic: for shooting the enemy king float h_squares_attackable(position_t *p, color_t c, square_t* laser_list, int laser_list_length, full_board_t* board) { square_t o_king_sq = board->pieces[opp_color(c)][0]; rnk_t k_rnk = rnk_of(o_king_sq); fil_t k_fil = fil_of(o_king_sq); float h_attackable = 0; for (int i = 0; i < laser_list_length - 1; i++) { h_attackable += fast_h_dist(laser_list[i], laser_list[i+1], k_rnk, k_fil); } if (in_bounds(laser_list[laser_list_length - 1])) { h_attackable += fast_h_dist(laser_list[laser_list_length - 1], laser_list[laser_list_length - 1] + 1, k_rnk, k_fil); } return h_attackable; }
// 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; }
// PBETWEEN heuristic: Bonus for Pawn at (f, r) in rectangle defined by Kings at the corners ev_score_t pbetween(position_t *p, fil_t f, rnk_t r) { bool is_between = between(f, fil_of(p->kloc[WHITE]), fil_of(p->kloc[BLACK])) && between(r, rnk_of(p->kloc[WHITE]), rnk_of(p->kloc[BLACK])); return is_between ? PBETWEEN : 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; }