std::list<std::shared_ptr<Food>> Collision_detector::get_fo_coll(std::shared_ptr<Ant> p_ant) { //We get first the square where the ant is //Ant ant = *p_ant ; //Position pos = ant._pos; std::tuple<int,int> square = get_in_which_square ((*p_ant)._pos,_sub_size_olf); //Then we look in the squares arround its to search for collisions int x,z,i ; std::tie (x,z) = square; std::list<std::shared_ptr<Food>> res; for (i=0; i<9; i++) { std::tuple<int,int> sq (x+ i%3-1,z+ i/3-1) ; if (_map_food_for_ant.count(sq) == 1) { for (std::list<std::shared_ptr<Food>>::iterator it= (_map_food_for_ant.at(sq)).begin(); it != (_map_food_for_ant.at(sq)).end(); ++it) { double r = (*(*it)).get_size() + (*p_ant).get_size(); if ((square_distance ((*p_ant)._pos, (*(*it))._pos) < r*r) && (*(*it)).is_alive()) res.push_back(*it); } } } return res ; }
bool LineChart::on_chart(const QPoint& mouse_position, size_t& point_index) const { const double MinDistance = 8.0; const Vector2d mp(mouse_position.x(), mouse_position.y()); double closest_square_distance = numeric_limits<double>::max(); size_t closest_index = 0; for (size_t i = 0; i < m_points.size(); ++i) { const Vector2d p = convert_to_frame(m_points[i]); const double d = square_distance(mp, p); if (closest_square_distance > d) { closest_square_distance = d; closest_index = i; } } if (closest_square_distance < MinDistance * MinDistance) { point_index = closest_index; return true; } return false; }
Value EvaluationFunction<KBNK>::apply(const Position& pos) const { assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame + BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, KNIGHT) == 1); assert(pos.piece_count(strongerSide, PAWN) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Square bishopSquare = pos.piece_list(strongerSide, BISHOP, 0); // kbnk_mate_table() tries to drive toward corners A1 or H8, // if we have a bishop that cannot reach the above squares we // mirror the kings so to drive enemy toward corners A8 or H1. if (!same_color_squares(bishopSquare, SQ_A1)) { winnerKSq = flop_square(winnerKSq); loserKSq = flop_square(loserKSq); } Value result = VALUE_KNOWN_WIN + distance_bonus(square_distance(winnerKSq, loserKSq)) + kbnk_mate_table(loserKSq); return strongerSide == pos.side_to_move() ? result : -result; }
ScaleFactor ScalingFunction<KNPK>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == KnightValueMidgame); assert(pos.piece_count(strongerSide, KNIGHT) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN, 0); Square weakerKingSq = pos.king_square(weakerSide); if ( pawnSq == relative_square(strongerSide, SQ_A7) && square_distance(weakerKingSq, relative_square(strongerSide, SQ_A8)) <= 1) return SCALE_FACTOR_ZERO; if ( pawnSq == relative_square(strongerSide, SQ_H7) && square_distance(weakerKingSq, relative_square(strongerSide, SQ_H8)) <= 1) return SCALE_FACTOR_ZERO; return SCALE_FACTOR_NONE; }
void init_direction_table() { SquareDelta deltas[8] = { DELTA_E, DELTA_W, DELTA_N, DELTA_S, DELTA_NE, DELTA_SW, DELTA_NW, DELTA_SE }; for(Square s1 = SQ_A1; s1 <= SQ_H8; s1++) for(Square s2 = SQ_A1; s2 <= SQ_H8; s2++) { DirectionTable[s1][s2] = uint8_t(DIR_NONE); SignedDirectionTable[s1][s2] = uint8_t(SIGNED_DIR_NONE); if(s1 == s2) continue; for(SignedDirection d = SIGNED_DIR_E; d <= SIGNED_DIR_SE; d++) { SquareDelta delta = deltas[d]; Square s3, s4; for(s4 = s1 + delta, s3 = s1; square_distance(s4, s3) == 1 && s4 != s2 && square_is_ok(s4); s3 = s4, s4 += delta); if(s4 == s2 && square_distance(s4, s3) == 1) { SignedDirectionTable[s1][s2] = uint8_t(d); DirectionTable[s1][s2] = uint8_t(d/2); break; } } } }
ScaleFactor ScalingFunction<KBPKB>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == BishopValueMidgame); assert(pos.piece_count(weakerSide, BISHOP) == 1); assert(pos.piece_count(weakerSide, PAWN) == 0); Square pawnSq = pos.piece_list(strongerSide, PAWN, 0); Square strongerBishopSq = pos.piece_list(strongerSide, BISHOP, 0); Square weakerBishopSq = pos.piece_list(weakerSide, BISHOP, 0); Square weakerKingSq = pos.king_square(weakerSide); // Case 1: Defending king blocks the pawn, and cannot be driven away if ( square_file(weakerKingSq) == square_file(pawnSq) && relative_rank(strongerSide, pawnSq) < relative_rank(strongerSide, weakerKingSq) && ( !same_color_squares(weakerKingSq, strongerBishopSq) || relative_rank(strongerSide, weakerKingSq) <= RANK_6)) return SCALE_FACTOR_ZERO; // Case 2: Opposite colored bishops if (!same_color_squares(strongerBishopSq, weakerBishopSq)) { // We assume that the position is drawn in the following three situations: // // a. The pawn is on rank 5 or further back. // b. The defending king is somewhere in the pawn's path. // c. The defending bishop attacks some square along the pawn's path, // and is at least three squares away from the pawn. // // These rules are probably not perfect, but in practice they work // reasonably well. if (relative_rank(strongerSide, pawnSq) <= RANK_5) return SCALE_FACTOR_ZERO; else { Bitboard path = squares_in_front_of(strongerSide, pawnSq); if (path & pos.pieces(KING, weakerSide)) return SCALE_FACTOR_ZERO; if ( (pos.attacks_from<BISHOP>(weakerBishopSq) & path) && square_distance(weakerBishopSq, pawnSq) >= 3) return SCALE_FACTOR_ZERO; } } return SCALE_FACTOR_NONE; }
Value EvaluationFunction<KBBKN>::apply(const Position& pos) const { assert(pos.piece_count(strongerSide, BISHOP) == 2); assert(pos.non_pawn_material(strongerSide) == 2*BishopValueMidgame); assert(pos.piece_count(weakerSide, KNIGHT) == 1); assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame); assert(pos.pieces(PAWN) == EmptyBoardBB); Value result = BishopValueEndgame; Square wksq = pos.king_square(strongerSide); Square bksq = pos.king_square(weakerSide); Square nsq = pos.piece_list(weakerSide, KNIGHT, 0); // Bonus for attacking king close to defending king result += distance_bonus(square_distance(wksq, bksq)); // Bonus for driving the defending king and knight apart result += Value(square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility result += Value((8 - count_1s<CNT32_MAX15>(pos.attacks_from<KNIGHT>(nsq))) * 8); return strongerSide == pos.side_to_move() ? result : -result; }
ScaleFactor ScalingFunction<KBPsK>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == BishopValueMidgame); assert(pos.piece_count(strongerSide, BISHOP) == 1); assert(pos.piece_count(strongerSide, PAWN) >= 1); // No assertions about the material of weakerSide, because we want draws to // be detected even when the weaker side has some pawns. Bitboard pawns = pos.pieces(PAWN, strongerSide); File pawnFile = square_file(pos.piece_list(strongerSide, PAWN, 0)); // All pawns are on a single rook file ? if ( (pawnFile == FILE_A || pawnFile == FILE_H) && (pawns & ~file_bb(pawnFile)) == EmptyBoardBB) { Square bishopSq = pos.piece_list(strongerSide, BISHOP, 0); Square queeningSq = relative_square(strongerSide, make_square(pawnFile, RANK_8)); Square kingSq = pos.king_square(weakerSide); if ( !same_color_squares(queeningSq, bishopSq) && file_distance(square_file(kingSq), pawnFile) <= 1) { // The bishop has the wrong color, and the defending king is on the // file of the pawn(s) or the neighboring file. Find the rank of the // frontmost pawn. Rank rank; if (strongerSide == WHITE) { for (rank = RANK_7; (rank_bb(rank) & pawns) == EmptyBoardBB; rank--) {} assert(rank >= RANK_2 && rank <= RANK_7); } else { for (rank = RANK_2; (rank_bb(rank) & pawns) == EmptyBoardBB; rank++) {} rank = Rank(rank ^ 7); // HACK to get the relative rank assert(rank >= RANK_2 && rank <= RANK_7); } // If the defending king has distance 1 to the promotion square or // is placed somewhere in front of the pawn, it's a draw. if ( square_distance(kingSq, queeningSq) <= 1 || relative_rank(strongerSide, kingSq) >= rank) return SCALE_FACTOR_ZERO; } } return SCALE_FACTOR_NONE; }
Value EvaluationFunction<KQKR>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == QueenValueMidgame); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == RookValueMidgame); assert(pos.piece_count(weakerSide, PAWN) == 0); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = QueenValueEndgame - RookValueEndgame + mate_table(loserKSq) + distance_bonus(square_distance(winnerKSq, loserKSq)); return strongerSide == pos.side_to_move() ? result : -result; }
Value EvaluationFunction<KRKN>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.piece_count(strongerSide, PAWN) == 0); assert(pos.non_pawn_material(weakerSide) == KnightValueMidgame); assert(pos.piece_count(weakerSide, PAWN) == 0); assert(pos.piece_count(weakerSide, KNIGHT) == 1); Square defendingKSq = pos.king_square(weakerSide); Square nSq = pos.piece_list(weakerSide, KNIGHT, 0); int d = square_distance(defendingKSq, nSq); Value result = Value(10) + mate_table(defendingKSq) + krkn_king_knight_distance_penalty(d); return strongerSide == pos.side_to_move() ? result : -result; }
Value EvaluationFunction<KXK>::apply(const Position& pos) const { assert(pos.non_pawn_material(weakerSide) == VALUE_ZERO); assert(pos.piece_count(weakerSide, PAWN) == VALUE_ZERO); Square winnerKSq = pos.king_square(strongerSide); Square loserKSq = pos.king_square(weakerSide); Value result = pos.non_pawn_material(strongerSide) + pos.piece_count(strongerSide, PAWN) * PawnValueEndgame + mate_table(loserKSq) + distance_bonus(square_distance(winnerKSq, loserKSq)); if ( pos.piece_count(strongerSide, QUEEN) || pos.piece_count(strongerSide, ROOK) || pos.piece_count(strongerSide, BISHOP) > 1) // TODO: check for two equal-colored bishops! result += VALUE_KNOWN_WIN; return strongerSide == pos.side_to_move() ? result : -result; }
bool closer(point viewer, point const & a, point const & b) { return square_distance(a, viewer) < square_distance(b, viewer); }
point closest_from_two(point viewer, point const & a, point const & b) { return ((square_distance(a, viewer) < square_distance(b, viewer)) ? a : b); }
inline void calc_piece_value(struct t_board *board, struct t_chess_eval *eval) { t_chess_color color, opponent; t_chess_square square; t_chess_piece piece; t_chess_piece piece_type; t_bitboard b; t_bitboard attack_squares; t_bitboard moves; int move_count; struct t_pawn_hash_record *pawn_record = eval->pawn_evaluation; for (color = WHITE; color <= BLACK; color++) { t_chess_value middlegame = 0; t_chess_value endgame = 0; opponent = OPPONENT(color); //========================================================= //-- Rooks first //========================================================= piece = PIECEINDEX(color, ROOK); eval->attacklist[piece] = 0; b = board->piecelist[piece]; //-- Remove Rook and Queens (so we can easily evaluate rams) t_bitboard _all_pieces = board->all_pieces ^ board->pieces[color][QUEEN] ^ b; t_bitboard _not_occupied = ~(board->occupied[color] & _all_pieces); //-- Rooks on the 7th if ((b & rank_mask[color][6]) && (board->pieces[opponent][KING] & rank_mask[color][7])) { middlegame += MG_ROOK_ON_7TH; endgame += MG_ROOK_ON_7TH; } //-- Rooks on Open file if (b & pawn_record->open_file) { middlegame += popcount(b & pawn_record->open_file) * pawn_record->pawn_count[color] * MG_ROOK_ON_OPEN_FILE; } //-- Rooks on Semi-Open file if (b & pawn_record->semi_open_file[color]) { middlegame += popcount(b & pawn_record->semi_open_file[color]) * pawn_record->pawn_count[color] * MG_ROOK_ON_SEMI_OPEN_FILE; } //-- Loop around for all pieces while (b) { //-- Find the square it resides square = bitscan_reset(&b); //-- Generate moves moves = rook_magic_moves[square][((rook_magic[square].mask & _all_pieces) * rook_magic[square].magic) >> 52]; eval->attacks[color][ROOK] |= moves; moves &= _not_occupied; //-- Mobility (along ranks) move_count = popcount(moves & square_rank_mask[square]); middlegame += horizontal_rook_mobility[MIDDLEGAME][move_count]; endgame += horizontal_rook_mobility[ENDGAME][move_count]; //-- Mobility (along files) move_count = popcount(moves & square_column_mask[square]); middlegame += vertical_rook_mobility[MIDDLEGAME][move_count]; endgame += vertical_rook_mobility[ENDGAME][move_count]; //-- King safety if (attack_squares = (moves & eval->king_zone[opponent])) { eval->king_attack_count[opponent]++; eval->king_attack_pressure[opponent] += popcount(attack_squares) * 40; } assert(eval->king_zone[opponent] != 0); // piece-square tables middlegame += piece_square_table[piece][MIDDLEGAME][square]; endgame += piece_square_table[piece][ENDGAME][square]; } //========================================================= //-- Queens //========================================================= piece = PIECEINDEX(color, QUEEN); eval->attacklist[piece] = 0; b = board->piecelist[piece]; _all_pieces ^= board->pieces[color][BISHOP]; _not_occupied = ~(board->occupied[color] & _all_pieces); while (b) { //-- Find the square it resides square = bitscan_reset(&b); //-- Rook-like Moves t_bitboard rook_moves = rook_magic_moves[square][((rook_magic[square].mask & _all_pieces) * rook_magic[square].magic) >> 52]; eval->attacklist[piece] |= rook_moves; rook_moves &= _not_occupied; //-- Bishop-like moves t_bitboard bishop_moves = bishop_magic_moves[square][((bishop_magic[square].mask & _all_pieces) * bishop_magic[square].magic) >> 55]; eval->attacklist[piece] |= bishop_moves; bishop_moves &= _not_occupied; //-- Mobility move_count = popcount((rook_moves & square_column_mask[square]) | bishop_moves); middlegame += move_count; //-- King safety if (attack_squares = ((rook_moves | bishop_moves) & eval->king_zone[opponent])) { eval->king_attack_count[opponent]++; eval->king_attack_pressure[opponent] += 80 * popcount(attack_squares); } //-- piece-square tables middlegame += piece_square_table[piece][MIDDLEGAME][square]; endgame += piece_square_table[piece][ENDGAME][square]; } //-- Interaction of double pawns & major pieces if (pawn_record->double_pawns[color]) { int double_pawn_count = popcount(pawn_record->double_pawns[color]); int major_piece_count = popcount(board->pieces[color][ROOK] | board->pieces[color][QUEEN]); switch (major_piece_count) { case 0: break; case 1: middlegame += (double_pawn_count * 12) - pawn_record->semi_open_double_pawns[color] * 30; endgame += (double_pawn_count * 12) - pawn_record->semi_open_double_pawns[color] * 25; break; case 2: middlegame += (double_pawn_count * 24) - pawn_record->semi_open_double_pawns[color] * 35; endgame += (double_pawn_count * 24) - pawn_record->semi_open_double_pawns[color] * 30; break; case 3: middlegame += (double_pawn_count * 30) - pawn_record->semi_open_double_pawns[color] * 40; endgame += (double_pawn_count * 30) - pawn_record->semi_open_double_pawns[color] * 35; break; case 4: middlegame += (double_pawn_count * 30) - pawn_record->semi_open_double_pawns[color] * 40; endgame += (double_pawn_count * 30) - pawn_record->semi_open_double_pawns[color] * 35; break; case 5: middlegame += (double_pawn_count * 30) - pawn_record->semi_open_double_pawns[color] * 40; endgame += (double_pawn_count * 30) - pawn_record->semi_open_double_pawns[color] * 35; break; } } //========================================================= //-- Bishops //========================================================= piece = PIECEINDEX(color, BISHOP); eval->attacklist[piece] = 0; b = board->piecelist[piece]; //-- Bishop pair bonus if (b & (b - 1)) { middlegame += MG_BISHOP_PAIR; endgame += EG_BISHOP_PAIR; } //-- Remove Own Pieces (leave pawns) _all_pieces = board->all_pieces ^ board->pieces[color][KNIGHT] ^ board->pieces[color][QUEEN]; _not_occupied = ~(board->occupied[color] & _all_pieces); while (b) { //-- Find the square it resides square = bitscan_reset(&b); //-- Generate moves moves = bishop_magic_moves[square][((bishop_magic[square].mask & _all_pieces) * bishop_magic[square].magic) >> 55]; eval->attacklist[piece] |= moves; moves &= _not_occupied; //-- Mobility move_count = popcount(moves); middlegame += bishop_mobility[MIDDLEGAME][move_count]; endgame += bishop_mobility[ENDGAME][move_count]; //-- Trapped //middlegame -= trapped_bishop[MIDDLEGAME][move_count]; //endgame -= trapped_bishop[ENDGAME][move_count]; //-- King safety if (attack_squares = (moves & eval->king_zone[opponent])) { eval->king_attack_count[opponent]++; eval->king_attack_pressure[opponent] += 20 * popcount(attack_squares); } // piece-square tables middlegame += piece_square_table[piece][MIDDLEGAME][square]; endgame += piece_square_table[piece][ENDGAME][square]; } //========================================================= //-- Knights //========================================================= piece = PIECEINDEX(color, KNIGHT); eval->attacklist[piece] = 0; b = board->piecelist[piece]; _not_occupied = ~board->occupied[color] & ~eval->attacks[opponent][PAWN]; //-- Outposts t_bitboard knight_outpost = b & pawn_record->potential_outpost[color]; while (knight_outpost) { square = bitscan_reset(&knight_outpost); t_chess_color square_color = SQUARECOLOR(square); //-- Can it be taken by a minor piece? if ((board->pieces[opponent][KNIGHT] == 0) && ((board->pieces[opponent][BISHOP] & color_square_mask[square_color]) == 0)) { middlegame += 25 - square_distance(square, board->king_square[opponent]); endgame += 10; } else { middlegame += 15 - square_distance(square, board->king_square[opponent]); endgame += 8; } } while (b) { //-- Find the square it resides square = bitscan_reset(&b); //-- Opponents King Tropism middlegame -= square_distance(square, board->king_square[opponent]) * 2; //-- Generate moves moves = knight_mask[square]; eval->attacklist[piece] |= moves; //-- Connected to another knight if (moves & board->piecelist[piece]) { middlegame += MG_CONNECTED_KNIGHTS; endgame += EG_CONNECTED_KNIGHTS; } //-- King safety if (attack_squares = (moves & eval->king_zone[opponent])) { eval->king_attack_count[opponent]++; eval->king_attack_pressure[opponent] += 20 * popcount(attack_squares); } //-- Mobility (not including any squares attacked by enemy pawns) moves &= _not_occupied; move_count = popcount(moves); middlegame += knight_mobility[MIDDLEGAME][move_count]; endgame += knight_mobility[ENDGAME][move_count]; // piece-square tables middlegame += piece_square_table[piece][MIDDLEGAME][square]; endgame += piece_square_table[piece][ENDGAME][square]; } //========================================================= //-- King Attacks //========================================================= piece = PIECEINDEX(color, KING); eval->attacklist[piece] = king_mask[board->king_square[color]]; //========================================================= //-- Blocked Central Pawns //========================================================= if (b = (central_kq_pawns[color] & board->pieces[color][PAWN])){ b = ((b << 8) >> (color * 16)) & board->all_pieces; middlegame += -10 * popcount(b); } //-- Add to board scores eval->middlegame += middlegame * (1 - color * 2); eval->endgame += endgame * (1 - color * 2); //-- Create combined attacks eval->attacks[color][BLANK] = eval->attacks[color][PAWN] | eval->attacks[color][ROOK] | eval->attacks[color][BISHOP] | eval->attacks[color][KNIGHT] | eval->attacks[color][QUEEN] | eval->attacks[color][KING]; }
ScaleFactor ScalingFunction<KRPKR>::apply(const Position& pos) const { assert(pos.non_pawn_material(strongerSide) == RookValueMidgame); assert(pos.piece_count(strongerSide, PAWN) == 1); assert(pos.non_pawn_material(weakerSide) == RookValueMidgame); assert(pos.piece_count(weakerSide, PAWN) == 0); Square wksq = pos.king_square(strongerSide); Square wrsq = pos.piece_list(strongerSide, ROOK, 0); Square wpsq = pos.piece_list(strongerSide, PAWN, 0); Square bksq = pos.king_square(weakerSide); Square brsq = pos.piece_list(weakerSide, ROOK, 0); // Orient the board in such a way that the stronger side is white, and the // pawn is on the left half of the board. if (strongerSide == BLACK) { wksq = flip_square(wksq); wrsq = flip_square(wrsq); wpsq = flip_square(wpsq); bksq = flip_square(bksq); brsq = flip_square(brsq); } if (square_file(wpsq) > FILE_D) { wksq = flop_square(wksq); wrsq = flop_square(wrsq); wpsq = flop_square(wpsq); bksq = flop_square(bksq); brsq = flop_square(brsq); } File f = square_file(wpsq); Rank r = square_rank(wpsq); Square queeningSq = make_square(f, RANK_8); int tempo = (pos.side_to_move() == strongerSide); // If the pawn is not too far advanced and the defending king defends the // queening square, use the third-rank defence. if ( r <= RANK_5 && square_distance(bksq, queeningSq) <= 1 && wksq <= SQ_H5 && (square_rank(brsq) == RANK_6 || (r <= RANK_3 && square_rank(wrsq) != RANK_6))) return SCALE_FACTOR_ZERO; // The defending side saves a draw by checking from behind in case the pawn // has advanced to the 6th rank with the king behind. if ( r == RANK_6 && square_distance(bksq, queeningSq) <= 1 && square_rank(wksq) + tempo <= RANK_6 && (square_rank(brsq) == RANK_1 || (!tempo && abs(square_file(brsq) - f) >= 3))) return SCALE_FACTOR_ZERO; if ( r >= RANK_6 && bksq == queeningSq && square_rank(brsq) == RANK_1 && (!tempo || square_distance(wksq, wpsq) >= 2)) return SCALE_FACTOR_ZERO; // White pawn on a7 and rook on a8 is a draw if black's king is on g7 or h7 // and the black rook is behind the pawn. if ( wpsq == SQ_A7 && wrsq == SQ_A8 && (bksq == SQ_H7 || bksq == SQ_G7) && square_file(brsq) == FILE_A && (square_rank(brsq) <= RANK_3 || square_file(wksq) >= FILE_D || square_rank(wksq) <= RANK_5)) return SCALE_FACTOR_ZERO; // If the defending king blocks the pawn and the attacking king is too far // away, it's a draw. if ( r <= RANK_5 && bksq == wpsq + DELTA_N && square_distance(wksq, wpsq) - tempo >= 2 && square_distance(wksq, brsq) - tempo >= 2) return SCALE_FACTOR_ZERO; // Pawn on the 7th rank supported by the rook from behind usually wins if the // attacking king is closer to the queening square than the defending king, // and the defending king cannot gain tempi by threatening the attacking rook. if ( r == RANK_7 && f != FILE_A && square_file(wrsq) == f && wrsq != queeningSq && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo) && (square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo)) return ScaleFactor(SCALE_FACTOR_MAX - 2 * square_distance(wksq, queeningSq)); // Similar to the above, but with the pawn further back if ( f != FILE_A && square_file(wrsq) == f && wrsq < wpsq && (square_distance(wksq, queeningSq) < square_distance(bksq, queeningSq) - 2 + tempo) && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wpsq + DELTA_N) - 2 + tempo) && ( square_distance(bksq, wrsq) + tempo >= 3 || ( square_distance(wksq, queeningSq) < square_distance(bksq, wrsq) + tempo && (square_distance(wksq, wpsq + DELTA_N) < square_distance(bksq, wrsq) + tempo)))) return ScaleFactor( SCALE_FACTOR_MAX - 8 * square_distance(wpsq, queeningSq) - 2 * square_distance(wksq, queeningSq)); // If the pawn is not far advanced, and the defending king is somewhere in // the pawn's path, it's probably a draw. if (r <= RANK_4 && bksq > wpsq) { if (square_file(bksq) == square_file(wpsq)) return ScaleFactor(10); if ( abs(square_file(bksq) - square_file(wpsq)) == 1 && square_distance(wksq, bksq) > 2) return ScaleFactor(24 - 2 * square_distance(wksq, bksq)); } return SCALE_FACTOR_NONE; }