Пример #1
0
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 ;

}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
        }
      }
    }
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
bool closer(point viewer, point const & a, point const & b) {
	return square_distance(a, viewer) < square_distance(b, viewer);
}
Пример #13
0
point closest_from_two(point viewer, point const & a, point const & b) {
	return ((square_distance(a, viewer) < square_distance(b, viewer)) ? a : b);
}
Пример #14
0
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];

    }
Пример #15
0
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;
}