// File: ATOMIC-LICHESS[P]ATOMKRAFT/endgame.cpp
// Function: Endgame<ScaleFactor, (EndgameType)12>::apply(Position const&) const
ScaleFactor Endgame<ScaleFactor, 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;
}

// Assembly:
subq $0x88, %rsp
movq %rdi, 0x78(%rsp)
movq %rsi, 0x70(%rsp)
movq 0x78(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0x70(%rsp), %rdi
movl 0x8(%rax), %esi
callq 0x1b250
movl %eax, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x6c(%rsp)
movq 0x70(%rsp), %rdi
movl 0x8(%rax), %esi
movl $0x4, %edx
xorl %ecx, %ecx
callq 0x164f0
movl %eax, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x68(%rsp)
movq 0x70(%rsp), %rdi
movl 0x8(%rax), %esi
movl $0x1, %edx
xorl %ecx, %ecx
callq 0x164f0
movl %eax, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x64(%rsp)
movq 0x70(%rsp), %rdi
movl 0xc(%rax), %esi
callq 0x1b250
movl %eax, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x60(%rsp)
movq 0x70(%rsp), %rdi
movl 0xc(%rax), %esi
movl $0x4, %edx
xorl %ecx, %ecx
callq 0x164f0
movl %eax, %ecx
movq 0x40(%rsp), %rax
movl %ecx, 0x5c(%rsp)
cmpl $0x1, 0x8(%rax)
jne 0x17f1f
movl 0x6c(%rsp), %edi
callq 0x1b2f0
movl %eax, 0x6c(%rsp)
movl 0x68(%rsp), %edi
callq 0x1b2f0
movl %eax, 0x68(%rsp)
movl 0x64(%rsp), %edi
callq 0x1b2f0
movl %eax, 0x64(%rsp)
movl 0x60(%rsp), %edi
callq 0x1b2f0
movl %eax, 0x60(%rsp)
movl 0x5c(%rsp), %edi
callq 0x1b2f0
movl %eax, 0x5c(%rsp)
movl 0x64(%rsp), %edi
callq 0xce10
cmpl $0x3, %eax
jle 0x17f6e
movl 0x6c(%rsp), %edi
callq 0x1b4a0
movl %eax, 0x6c(%rsp)
movl 0x68(%rsp), %edi
callq 0x1b4a0
movl %eax, 0x68(%rsp)
movl 0x64(%rsp), %edi
callq 0x1b4a0
movl %eax, 0x64(%rsp)
movl 0x60(%rsp), %edi
callq 0x1b4a0
movl %eax, 0x60(%rsp)
movl 0x5c(%rsp), %edi
callq 0x1b4a0
movl %eax, 0x5c(%rsp)
movl 0x64(%rsp), %edi
callq 0xce10
movl %eax, 0x58(%rsp)
movl 0x64(%rsp), %edi
callq 0xce40
movl %eax, 0x54(%rsp)
movl 0x58(%rsp), %edi
movl $0x7, %esi
callq 0xd740
movl %eax, 0x50(%rsp)
movq 0x70(%rsp), %rdi
callq 0xf5d0
movq 0x40(%rsp), %rcx
cmpl 0x8(%rcx), %eax
sete %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, 0x4c(%rsp)
cmpl $0x4, 0x54(%rsp)
jg 0x1800b
movl 0x60(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
cmpl $0x1, %eax
jg 0x1800b
cmpl $0x27, 0x6c(%rsp)
jg 0x1800b
movl 0x5c(%rsp), %edi
callq 0xce40
cmpl $0x5, %eax
je 0x17ffb
cmpl $0x2, 0x54(%rsp)
jg 0x1800b
movl 0x68(%rsp), %edi
callq 0xce40
cmpl $0x5, %eax
je 0x1800b
movl $0x0, 0x84(%rsp)
jmp 0x1846f
cmpl $0x5, 0x54(%rsp)
jne 0x1807b
movl 0x60(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
cmpl $0x1, %eax
jg 0x1807b
movl 0x6c(%rsp), %edi
callq 0xce40
addl 0x4c(%rsp), %eax
cmpl $0x5, %eax
jg 0x1807b
movl 0x5c(%rsp), %edi
callq 0xce40
cmpl $0x0, %eax
je 0x1806b
cmpl $0x0, 0x4c(%rsp)
jne 0x1807b
movl 0x5c(%rsp), %edi
callq 0xce10
movl %eax, %edi
movl 0x58(%rsp), %esi
callq 0xcdf0
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cmpl $0x3, %eax
jl 0x1807b
movl $0x0, 0x84(%rsp)
jmp 0x1846f
cmpl $0x5, 0x54(%rsp)
jl 0x180c3
movl 0x60(%rsp), %eax
cmpl 0x50(%rsp), %eax
jne 0x180c3
movl 0x5c(%rsp), %edi
callq 0xce40
cmpl $0x0, %eax
jne 0x180c3
cmpl $0x0, 0x4c(%rsp)
je 0x180b3
movl 0x6c(%rsp), %edi
movl 0x64(%rsp), %esi
callq 0xcd00
cmpl $0x2, %eax
jl 0x180c3
movl $0x0, 0x84(%rsp)
jmp 0x1846f
cmpl $0x30, 0x64(%rsp)
jne 0x18127
cmpl $0x38, 0x68(%rsp)
jne 0x18127
cmpl $0x37, 0x60(%rsp)
je 0x180df
cmpl $0x36, 0x60(%rsp)
jne 0x18127
movl 0x5c(%rsp), %edi
callq 0xce10
cmpl $0x0, %eax
jne 0x18127
movl 0x5c(%rsp), %edi
callq 0xce40
cmpl $0x2, %eax
jle 0x18117
movl 0x6c(%rsp), %edi
callq 0xce10
cmpl $0x3, %eax
jge 0x18117
movl 0x6c(%rsp), %edi
callq 0xce40
cmpl $0x4, %eax
jg 0x18127
movl $0x0, 0x84(%rsp)
jmp 0x1846f
cmpl $0x4, 0x54(%rsp)
jg 0x1818a
movl 0x60(%rsp), %eax
movl %eax, 0x3c(%rsp)
movl 0x64(%rsp), %edi
movl $0x8, %esi
callq 0xd780
movl %eax, %ecx
movl 0x3c(%rsp), %eax
cmpl %ecx, %eax
jne 0x1818a
movl 0x6c(%rsp), %edi
movl 0x64(%rsp), %esi
callq 0xcd00
subl 0x4c(%rsp), %eax
cmpl $0x2, %eax
jl 0x1818a
movl 0x6c(%rsp), %edi
movl 0x5c(%rsp), %esi
callq 0xcd00
subl 0x4c(%rsp), %eax
cmpl $0x2, %eax
jl 0x1818a
movl $0x0, 0x84(%rsp)
jmp 0x1846f
cmpl $0x6, 0x54(%rsp)
jne 0x1823c
cmpl $0x0, 0x58(%rsp)
je 0x1823c
movl 0x68(%rsp), %edi
callq 0xce10
cmpl 0x58(%rsp), %eax
jne 0x1823c
movl 0x68(%rsp), %eax
cmpl 0x50(%rsp), %eax
je 0x1823c
movl 0x6c(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, 0x38(%rsp)
movl 0x60(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
movl 0x38(%rsp), %eax
subl $0x2, %ecx
addl 0x4c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x1823c
movl 0x6c(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, 0x34(%rsp)
movl 0x60(%rsp), %edi
movl 0x68(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
movl 0x34(%rsp), %eax
addl 0x4c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x1823c
movl 0x6c(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
shll %ecx
movl $0x80, %eax
subl %ecx, %eax
movl %eax, 0x84(%rsp)
jmp 0x1846f
cmpl $0x0, 0x58(%rsp)
je 0x183bc
movl 0x68(%rsp), %edi
callq 0xce10
cmpl 0x58(%rsp), %eax
jne 0x183bc
movl 0x68(%rsp), %eax
cmpl 0x64(%rsp), %eax
jge 0x183bc
movl 0x6c(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, 0x30(%rsp)
movl 0x60(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
movl 0x30(%rsp), %eax
subl $0x2, %ecx
addl 0x4c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x183bc
movl 0x6c(%rsp), %eax
movl %eax, 0x24(%rsp)
movl 0x64(%rsp), %edi
movl $0x8, %esi
callq 0xd780
movl 0x24(%rsp), %edi
movl %eax, %esi
callq 0xcd00
movl %eax, 0x2c(%rsp)
movl 0x60(%rsp), %eax
movl %eax, 0x28(%rsp)
movl 0x64(%rsp), %edi
movl $0x8, %esi
callq 0xd780
movl 0x28(%rsp), %edi
movl %eax, %esi
callq 0xcd00
movl %eax, %ecx
movl 0x2c(%rsp), %eax
subl $0x2, %ecx
addl 0x4c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x183bc
movl 0x60(%rsp), %edi
movl 0x68(%rsp), %esi
callq 0xcd00
addl 0x4c(%rsp), %eax
cmpl $0x3, %eax
jge 0x1837c
movl 0x6c(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, 0x20(%rsp)
movl 0x60(%rsp), %edi
movl 0x68(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
movl 0x20(%rsp), %eax
addl 0x4c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x183bc
movl 0x6c(%rsp), %eax
movl %eax, 0x18(%rsp)
movl 0x64(%rsp), %edi
movl $0x8, %esi
callq 0xd780
movl 0x18(%rsp), %edi
movl %eax, %esi
callq 0xcd00
movl %eax, 0x1c(%rsp)
movl 0x60(%rsp), %edi
movl 0x68(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
movl 0x1c(%rsp), %eax
addl 0x4c(%rsp), %ecx
cmpl %ecx, %eax
jge 0x183bc
movl 0x64(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
shll $0x3, %ecx
movl $0x80, %eax
subl %ecx, %eax
movl %eax, 0x14(%rsp)
movl 0x6c(%rsp), %edi
movl 0x50(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
movl 0x14(%rsp), %eax
shll %ecx
subl %ecx, %eax
movl %eax, 0x84(%rsp)
jmp 0x1846f
cmpl $0x3, 0x54(%rsp)
jg 0x18464
movl 0x60(%rsp), %eax
cmpl 0x64(%rsp), %eax
jle 0x18464
movl 0x60(%rsp), %edi
callq 0xce10
movl %eax, 0x10(%rsp)
movl 0x64(%rsp), %edi
callq 0xce10
movl %eax, %ecx
movl 0x10(%rsp), %eax
cmpl %ecx, %eax
jne 0x18402
movl $0xa, 0x84(%rsp)
jmp 0x1846f
movl 0x60(%rsp), %edi
callq 0xce10
movl %eax, 0xc(%rsp)
movl 0x64(%rsp), %edi
callq 0xce10
movl 0xc(%rsp), %edi
movl %eax, %esi
callq 0xcdf0
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cmpl $0x1, %eax
jne 0x18462
movl 0x6c(%rsp), %edi
movl 0x60(%rsp), %esi
callq 0xcd00
cmpl $0x2, %eax
jle 0x18462
movl 0x6c(%rsp), %edi
movl 0x60(%rsp), %esi
callq 0xcd00
movl %eax, %ecx
shll %ecx
movl $0x18, %eax
subl %ecx, %eax
movl %eax, 0x84(%rsp)
jmp 0x1846f
jmp 0x18464
movl $0xff, 0x84(%rsp)
movl 0x84(%rsp), %eax
addq $0x88, %rsp
retq
nop