// File: ATOMIC-LICHESS[P]ATOMKRAFT/evaluate.cpp
// Function: Score (anonymous namespace)::evaluate_unstoppable_pawns<false>(Position const&, (anonymous namespace)::EvalInfo&)
Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei) {

    const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15;

    Bitboard b, b2, blockers, supporters, queeningPath, candidates;
    Square s, blockSq, queeningSquare;
    Color c, winnerSide, loserSide;
    bool pathDefended, opposed;
    int pliesToGo, movesToGo, oppMovesToGo, sacptg, blockersCount, minKingDist, kingptg, d;
    int pliesToQueen[] = { 256, 256 };

    // Step 1. Hunt for unstoppable passed pawns. If we find at least one,
    // record how many plies are required for promotion.
    for (c = WHITE; c <= BLACK; c++)
    {
        // Skip if other side has non-pawn pieces
        if (pos.non_pawn_material(opposite_color(c)))
            continue;

        b = ei.pi->passed_pawns(c);

        while (b)
        {
            s = pop_1st_bit(&b);
            queeningSquare = relative_square(c, make_square(square_file(s), RANK_8));
            queeningPath = squares_in_front_of(c, s);

            // Compute plies to queening and check direct advancement
            movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(c, s) == RANK_2);
            oppMovesToGo = square_distance(pos.king_square(opposite_color(c)), queeningSquare) - int(c != pos.side_to_move());
            pathDefended = ((ei.attackedBy[c][0] & queeningPath) == queeningPath);

            if (movesToGo >= oppMovesToGo && !pathDefended)
                continue;

            // Opponent king cannot block because path is defended and position
            // is not in check. So only friendly pieces can be blockers.
            NEW // opponent king can block if he is adjacent to enemy king
            
            assert(!pos.in_check());
            OLD assert((queeningPath & pos.occupied_squares()) == (queeningPath & pos.pieces_of_color(c)));
            STARTNEW
            assert(
            	((queeningPath & pos.occupied_squares()) == (queeningPath & pos.pieces_of_color(c)))
              || squares_touch
              	  [pos.king_square(pos.side_to_move())]
              	   [pos.king_square(opposite_color(pos.side_to_move()))]);
            ENDNEW

            // Add moves needed to free the path from friendly pieces and retest condition
            movesToGo += count_1s<Max15>(queeningPath & pos.pieces_of_color(c));

            if (movesToGo >= oppMovesToGo && !pathDefended)
                continue;

            pliesToGo = 2 * movesToGo - int(c == pos.side_to_move());
            pliesToQueen[c] = Min(pliesToQueen[c], pliesToGo);
        }
    }

    // Step 2. If either side cannot promote at least three plies before the other side then situation
    // becomes too complex and we give up. Otherwise we determine the possibly "winning side"
    if (abs(pliesToQueen[WHITE] - pliesToQueen[BLACK]) < 3)
        return SCORE_ZERO;

    winnerSide = (pliesToQueen[WHITE] < pliesToQueen[BLACK] ? WHITE : BLACK);
    loserSide = opposite_color(winnerSide);

    // Step 3. Can the losing side possibly create a new passed pawn and thus prevent the loss?
    b = candidates = pos.pieces(PAWN, loserSide);

    while (b)
    {
        s = pop_1st_bit(&b);

        // Compute plies from queening
        queeningSquare = relative_square(loserSide, make_square(square_file(s), RANK_8));
        movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(loserSide, s) == RANK_2);
        pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move());

        // Check if (without even considering any obstacles) we're too far away or doubled
        if (   pliesToQueen[winnerSide] + 3 <= pliesToGo
            || (squares_in_front_of(loserSide, s) & pos.pieces(PAWN, loserSide)))
            clear_bit(&candidates, s);
    }

    // If any candidate is already a passed pawn it _may_ promote in time. We give up.
    if (candidates & ei.pi->passed_pawns(loserSide))
        return SCORE_ZERO;

    // Step 4. Check new passed pawn creation through king capturing and pawn sacrifices
    b = candidates;

    while (b)
    {
        s = pop_1st_bit(&b);
        sacptg = blockersCount = 0;
        minKingDist = kingptg = 256;

        // Compute plies from queening
        queeningSquare = relative_square(loserSide, make_square(square_file(s), RANK_8));
        movesToGo = rank_distance(s, queeningSquare) - int(relative_rank(loserSide, s) == RANK_2);
        pliesToGo = 2 * movesToGo - int(loserSide == pos.side_to_move());

        // Generate list of blocking pawns and supporters
        supporters = neighboring_files_bb(s) & candidates;
        opposed = squares_in_front_of(loserSide, s) & pos.pieces(PAWN, winnerSide);
        blockers = passed_pawn_mask(loserSide, s) & pos.pieces(PAWN, winnerSide);

        assert(blockers);

        // How many plies does it take to remove all the blocking pawns?
        while (blockers)
        {
            blockSq = pop_1st_bit(&blockers);
            movesToGo = 256;

            // Check pawns that can give support to overcome obstacle, for instance
            // black pawns: a4, b4 white: b2 then pawn in b4 is giving support.
            if (!opposed)
            {
                b2 = supporters & in_front_bb(winnerSide, blockSq + pawn_push(winnerSide));

                while (b2) // This while-loop could be replaced with LSB/MSB (depending on color)
                {
                    d = square_distance(blockSq, pop_1st_bit(&b2)) - 2;
                    movesToGo = Min(movesToGo, d);
                }
            }

            // Check pawns that can be sacrificed against the blocking pawn
            b2 = attack_span_mask(winnerSide, blockSq) & candidates & ~(1ULL << s);

            while (b2) // This while-loop could be replaced with LSB/MSB (depending on color)
            {
                d = square_distance(blockSq, pop_1st_bit(&b2)) - 2;
                movesToGo = Min(movesToGo, d);
            }

            // If obstacle can be destroyed with an immediate pawn exchange / sacrifice,
            // it's not a real obstacle and we have nothing to add to pliesToGo.
            if (movesToGo <= 0)
                continue;

            // Plies needed to sacrifice against all the blocking pawns
            sacptg += movesToGo * 2;
            blockersCount++;

            // Plies needed for the king to capture all the blocking pawns
            d = square_distance(pos.king_square(loserSide), blockSq);
            minKingDist = Min(minKingDist, d);
            kingptg = (minKingDist + blockersCount) * 2;
        }

        // Check if pawn sacrifice plan _may_ save the day
        if (pliesToQueen[winnerSide] + 3 > pliesToGo + sacptg)
            return SCORE_ZERO;

        // Check if king capture plan _may_ save the day (contains some false positives)
        if (pliesToQueen[winnerSide] + 3 > pliesToGo + kingptg)
            return SCORE_ZERO;
    }

    // Winning pawn is unstoppable and will promote as first, return big score
    Score score = make_score(0, (Value) 0x500 - 0x20 * pliesToQueen[winnerSide]);
    return winnerSide == WHITE ? score : -score;
  }

// Assembly:
subq $0x138, %rsp            # imm = 0x138
movq %rdi, 0x128(%rsp)
movq %rsi, 0x120(%rsp)
movl $0x3, 0x11c(%rsp)
movq 0x37927(%rip), %rax     # 0x59d80
movq %rax, 0xa4(%rsp)
movl $0x0, 0xd8(%rsp)
cmpl $0x1, 0xd8(%rsp)
jg 0x2276b
movq 0x128(%rsp), %rax
movq %rax, 0x98(%rsp)
movl 0xd8(%rsp), %edi
callq 0x122b0
movq 0x98(%rsp), %rdi
movl %eax, %esi
callq 0x298e0
cmpl $0x0, %eax
je 0x224af
jmp 0x22757
movq 0x120(%rsp), %rax
movq 0x8(%rax), %rdi
movl 0xd8(%rsp), %esi
callq 0x29bf0
movq %rax, 0x110(%rsp)
cmpq $0x0, 0x110(%rsp)
je 0x22755
leaq 0x110(%rsp), %rdi
callq 0xd940
movl %eax, 0xe4(%rsp)
movl 0xd8(%rsp), %eax
movl %eax, 0x80(%rsp)
movl 0xe4(%rsp), %edi
callq 0xce10
movl %eax, %edi
movl $0x7, %esi
callq 0xd740
movl 0x80(%rsp), %edi
movl %eax, %esi
callq 0x1b380
movl %eax, 0xdc(%rsp)
movl 0xd8(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1b520
movq %rax, 0xf0(%rsp)
movl 0xe4(%rsp), %edi
movl 0xdc(%rsp), %esi
callq 0xcdb0
movl %eax, 0x84(%rsp)
movl 0xd8(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1b2c0
movl %eax, %ecx
movl 0x84(%rsp), %eax
cmpl $0x1, %ecx
sete %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc4(%rsp)
movq 0x128(%rsp), %rax
movq %rax, 0x88(%rsp)
movl 0xd8(%rsp), %edi
callq 0x122b0
movq 0x88(%rsp), %rdi
movl %eax, %esi
callq 0x1b250
movl %eax, %edi
movl 0xdc(%rsp), %esi
callq 0xcd00
movl %eax, 0x94(%rsp)
movl 0xd8(%rsp), %eax
movl %eax, 0x90(%rsp)
movq 0x128(%rsp), %rdi
callq 0xf5d0
movl 0x90(%rsp), %ecx
movl %eax, %edx
movl 0x94(%rsp), %eax
cmpl %edx, %ecx
setne %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc0(%rsp)
movq 0x120(%rsp), %rax
addq $0x10, %rax
movl 0xd8(%rsp), %ecx
shlq $0x6, %rcx
addq %rcx, %rax
movq (%rax), %rax
andq 0xf0(%rsp), %rax
cmpq 0xf0(%rsp), %rax
sete %al
andb $0x1, %al
movb %al, 0xcf(%rsp)
movl 0xc4(%rsp), %eax
cmpl 0xc0(%rsp), %eax
jl 0x2266a
testb $0x1, 0xcf(%rsp)
jne 0x2266a
jmp 0x224cf
movq 0xf0(%rsp), %rax
movq %rax, 0x78(%rsp)
movq 0x128(%rsp), %rdi
movl 0xd8(%rsp), %esi
callq 0x298c0
movq 0x78(%rsp), %rdi
andq %rax, %rdi
callq 0x29a00
addl 0xc4(%rsp), %eax
movl %eax, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
cmpl 0xc0(%rsp), %eax
jl 0x226c5
testb $0x1, 0xcf(%rsp)
jne 0x226c5
jmp 0x224cf
movl 0xc4(%rsp), %eax
shll %eax
movl %eax, 0x74(%rsp)
movl 0xd8(%rsp), %eax
movl %eax, 0x70(%rsp)
movq 0x128(%rsp), %rdi
callq 0xf5d0
movl 0x70(%rsp), %ecx
movl %eax, %edx
movl 0x74(%rsp), %eax
cmpl %edx, %ecx
sete %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc8(%rsp)
movl 0xd8(%rsp), %eax
movl 0xa4(%rsp,%rax,4), %eax
cmpl 0xc8(%rsp), %eax
jge 0x22733
movl 0xd8(%rsp), %eax
movl 0xa4(%rsp,%rax,4), %eax
movl %eax, 0x6c(%rsp)
jmp 0x2273e
movl 0xc8(%rsp), %eax
movl %eax, 0x6c(%rsp)
movl 0x6c(%rsp), %ecx
movl 0xd8(%rsp), %eax
movl %ecx, 0xa4(%rsp,%rax,4)
jmp 0x224cf
jmp 0x22757
leaq 0xd8(%rsp), %rdi
xorl %esi, %esi
callq 0xe6a0
jmp 0x2246c
movl 0xa4(%rsp), %eax
subl 0xa8(%rsp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cmpl $0x3, %eax
jge 0x22795
movl $0x0, 0x134(%rsp)
jmp 0x22e72
movl 0xa4(%rsp), %edx
movl 0xa8(%rsp), %esi
movl $0x1, %eax
xorl %ecx, %ecx
cmpl %esi, %edx
cmovll %ecx, %eax
movl %eax, 0xd4(%rsp)
movl 0xd4(%rsp), %edi
callq 0x122b0
movl %eax, 0xd0(%rsp)
movq 0x128(%rsp), %rdi
movl 0xd0(%rsp), %edx
movl $0x1, %esi
callq 0x16530
movq %rax, 0xe8(%rsp)
movq %rax, 0x110(%rsp)
cmpq $0x0, 0x110(%rsp)
je 0x22947
leaq 0x110(%rsp), %rdi
callq 0xd940
movl %eax, 0xe4(%rsp)
movl 0xd0(%rsp), %eax
movl %eax, 0x5c(%rsp)
movl 0xe4(%rsp), %edi
callq 0xce10
movl %eax, %edi
movl $0x7, %esi
callq 0xd740
movl 0x5c(%rsp), %edi
movl %eax, %esi
callq 0x1b380
movl %eax, 0xdc(%rsp)
movl 0xe4(%rsp), %edi
movl 0xdc(%rsp), %esi
callq 0xcdb0
movl %eax, 0x60(%rsp)
movl 0xd0(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1b2c0
movl %eax, %ecx
movl 0x60(%rsp), %eax
cmpl $0x1, %ecx
sete %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
shll %eax
movl %eax, 0x68(%rsp)
movl 0xd0(%rsp), %eax
movl %eax, 0x64(%rsp)
movq 0x128(%rsp), %rdi
callq 0xf5d0
movl 0x64(%rsp), %ecx
movl %eax, %edx
movl 0x68(%rsp), %eax
cmpl %edx, %ecx
sete %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc8(%rsp)
movl 0xd4(%rsp), %eax
movl 0xa4(%rsp,%rax,4), %eax
addl $0x3, %eax
cmpl 0xc8(%rsp), %eax
jle 0x2292e
movl 0xd0(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1b520
movq %rax, 0x50(%rsp)
movq 0x128(%rsp), %rdi
movl 0xd0(%rsp), %edx
movl $0x1, %esi
callq 0x16530
movq %rax, %rcx
movq 0x50(%rsp), %rax
andq %rcx, %rax
cmpq $0x0, %rax
je 0x22942
movl 0xe4(%rsp), %esi
leaq 0xe8(%rsp), %rdi
callq 0x29eb0
jmp 0x227f2
movq 0xe8(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x120(%rsp), %rax
movq 0x8(%rax), %rdi
movl 0xd0(%rsp), %esi
callq 0x29bf0
movq %rax, %rcx
movq 0x48(%rsp), %rax
andq %rcx, %rax
cmpq $0x0, %rax
je 0x2298d
movl $0x0, 0x134(%rsp)
jmp 0x22e72
movq 0xe8(%rsp), %rax
movq %rax, 0x110(%rsp)
cmpq $0x0, 0x110(%rsp)
je 0x22e18
leaq 0x110(%rsp), %rdi
callq 0xd940
movl %eax, 0xe4(%rsp)
movl $0x0, 0xb8(%rsp)
movl $0x0, 0xbc(%rsp)
movl $0x100, 0xb0(%rsp) # imm = 0x100
movl $0x100, 0xb4(%rsp) # imm = 0x100
movl 0xd0(%rsp), %eax
movl %eax, 0x28(%rsp)
movl 0xe4(%rsp), %edi
callq 0xce10
movl %eax, %edi
movl $0x7, %esi
callq 0xd740
movl 0x28(%rsp), %edi
movl %eax, %esi
callq 0x1b380
movl %eax, 0xdc(%rsp)
movl 0xe4(%rsp), %edi
movl 0xdc(%rsp), %esi
callq 0xcdb0
movl %eax, 0x2c(%rsp)
movl 0xd0(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1b2c0
movl %eax, %ecx
movl 0x2c(%rsp), %eax
cmpl $0x1, %ecx
sete %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc4(%rsp)
movl 0xc4(%rsp), %eax
shll %eax
movl %eax, 0x34(%rsp)
movl 0xd0(%rsp), %eax
movl %eax, 0x30(%rsp)
movq 0x128(%rsp), %rdi
callq 0xf5d0
movl 0x30(%rsp), %ecx
movl %eax, %edx
movl 0x34(%rsp), %eax
cmpl %edx, %ecx
sete %cl
andb $0x1, %cl
movzbl %cl, %ecx
subl %ecx, %eax
movl %eax, 0xc8(%rsp)
movl 0xe4(%rsp), %edi
callq 0xe680
andq 0xe8(%rsp), %rax
movq %rax, 0xf8(%rsp)
movl 0xd0(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1b520
movq %rax, 0x38(%rsp)
movq 0x128(%rsp), %rdi
movl 0xd4(%rsp), %edx
movl $0x1, %esi
callq 0x16530
movq %rax, %rcx
movq 0x38(%rsp), %rax
andq %rcx, %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xce(%rsp)
movl 0xd0(%rsp), %edi
movl 0xe4(%rsp), %esi
callq 0x1bd00
movq %rax, 0x40(%rsp)
movq 0x128(%rsp), %rdi
movl 0xd4(%rsp), %edx
movl $0x1, %esi
callq 0x16530
movq %rax, %rcx
movq 0x40(%rsp), %rax
andq %rcx, %rax
movq %rax, 0x100(%rsp)
cmpq $0x0, 0x100(%rsp)
je 0x22db0
leaq 0x100(%rsp), %rdi
callq 0xd940
movl %eax, 0xe0(%rsp)
movl $0x100, 0xc4(%rsp) # imm = 0x100
testb $0x1, 0xce(%rsp)
jne 0x22c58
movq 0xf8(%rsp), %rax
movq %rax, 0x20(%rsp)
movl 0xd4(%rsp), %eax
movl %eax, 0x1c(%rsp)
movl 0xe0(%rsp), %eax
movl %eax, 0x18(%rsp)
movl 0xd4(%rsp), %edi
callq 0x1b580
movl 0x18(%rsp), %edi
movl %eax, %esi
callq 0xd780
movl 0x1c(%rsp), %edi
movl %eax, %esi
callq 0xe5f0
movq %rax, %rcx
movq 0x20(%rsp), %rax
andq %rcx, %rax
movq %rax, 0x108(%rsp)
cmpq $0x0, 0x108(%rsp)
je 0x22c56
movl 0xe0(%rsp), %eax
movl %eax, 0x14(%rsp)
leaq 0x108(%rsp), %rdi
callq 0xd940
movl 0x14(%rsp), %edi
movl %eax, %esi
callq 0xcd00
subl $0x2, %eax
movl %eax, 0xac(%rsp)
movl 0xc4(%rsp), %eax
cmpl 0xac(%rsp), %eax
jge 0x22c3e
movl 0xc4(%rsp), %eax
movl %eax, 0x10(%rsp)
jmp 0x22c49
movl 0xac(%rsp), %eax
movl %eax, 0x10(%rsp)
movl 0x10(%rsp), %eax
movl %eax, 0xc4(%rsp)
jmp 0x22be9
jmp 0x22c58
movl 0xd4(%rsp), %edi
movl 0xe0(%rsp), %esi
callq 0x29ee0
andq 0xe8(%rsp), %rax
movl 0xe4(%rsp), %ecx
movl $0x1, %edx
shlq %cl, %rdx
movq %rdx, %rcx
xorq $-0x1, %rcx
andq %rcx, %rax
movq %rax, 0x108(%rsp)
cmpq $0x0, 0x108(%rsp)
je 0x22d01
movl 0xe0(%rsp), %eax
movl %eax, 0xc(%rsp)
leaq 0x108(%rsp), %rdi
callq 0xd940
movl 0xc(%rsp), %edi
movl %eax, %esi
callq 0xcd00
subl $0x2, %eax
movl %eax, 0xac(%rsp)
movl 0xc4(%rsp), %eax
cmpl 0xac(%rsp), %eax
jge 0x22ce9
movl 0xc4(%rsp), %eax
movl %eax, 0x8(%rsp)
jmp 0x22cf4
movl 0xac(%rsp), %eax
movl %eax, 0x8(%rsp)
movl 0x8(%rsp), %eax
movl %eax, 0xc4(%rsp)
jmp 0x22c94
cmpl $0x0, 0xc4(%rsp)
jg 0x22d10
jmp 0x22b55
movl 0xc4(%rsp), %eax
shll %eax
addl 0xbc(%rsp), %eax
movl %eax, 0xbc(%rsp)
movl 0xb8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb8(%rsp)
movq 0x128(%rsp), %rdi
movl 0xd0(%rsp), %esi
callq 0x1b250
movl %eax, %edi
movl 0xe0(%rsp), %esi
callq 0xcd00
movl %eax, 0xac(%rsp)
movl 0xb4(%rsp), %eax
cmpl 0xac(%rsp), %eax
jge 0x22d7e
movl 0xb4(%rsp), %eax
movl %eax, 0x4(%rsp)
jmp 0x22d89
movl 0xac(%rsp), %eax
movl %eax, 0x4(%rsp)
movl 0x4(%rsp), %eax
movl %eax, 0xb4(%rsp)
movl 0xb4(%rsp), %eax
addl 0xb8(%rsp), %eax
shll %eax
movl %eax, 0xb0(%rsp)
jmp 0x22b55
movl 0xd4(%rsp), %eax
movl 0xa4(%rsp,%rax,4), %eax
addl $0x3, %eax
movl 0xc8(%rsp), %ecx
addl 0xbc(%rsp), %ecx
cmpl %ecx, %eax
jle 0x22de3
movl $0x0, 0x134(%rsp)
jmp 0x22e72
movl 0xd4(%rsp), %eax
movl 0xa4(%rsp,%rax,4), %eax
addl $0x3, %eax
movl 0xc8(%rsp), %ecx
addl 0xb0(%rsp), %ecx
cmpl %ecx, %eax
jle 0x22e13
movl $0x0, 0x134(%rsp)
jmp 0x22e72
jmp 0x2299d
movl 0xd4(%rsp), %eax
movl 0xa4(%rsp,%rax,4), %esi
shll $0x5, %esi
movl $0x500, %edi            # imm = 0x500
callq 0x29ca0
movl %eax, %esi
xorl %edi, %edi
callq 0x27f40
movl %eax, 0xa0(%rsp)
cmpl $0x0, 0xd4(%rsp)
jne 0x22e59
movl 0xa0(%rsp), %eax
movl %eax, (%rsp)
jmp 0x22e68
movl 0xa0(%rsp), %edi
callq 0x29f10
movl %eax, (%rsp)
movl (%rsp), %eax
movl %eax, 0x134(%rsp)
movl 0x134(%rsp), %eax
addq $0x138, %rsp            # imm = 0x138
retq
nopw %cs:(%rax,%rax)