// File: /workspace/github_cpp_makefile_star2_O2/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:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movabsq $0x10000000100, %rax    # imm = 0x10000000100
movq %rax, 0x18(%rsp)
movq %rdi, 0x8(%rsp)
leaq 0x190(%rdi), %rax
movq %rax, 0x38(%rsp)
movq %rsi, 0x40(%rsp)
leaq 0x10(%rsi), %rax
movq %rax, 0x50(%rsp)
xorl %r13d, %r13d
cmpq $0x2, %r13
je 0x118d9
movq 0x8(%rsp), %rax
movq 0x1938(%rax), %rax
movl %r13d, %ecx
xorq $0x1, %rcx
cmpl $0x0, 0x28(%rax,%rcx,4)
je 0x117b6
incq %r13
jmp 0x1178d
movq 0x40(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x8(%rax,%r13,8), %rax
movq %rax, 0x20(%rsp)
shlq $0x9, %rcx
movq 0x38(%rsp), %rdx
addq %rdx, %rcx
addq $0x180, %rcx            # imm = 0x180
movq %rcx, 0x10(%rsp)
movq %r13, %r14
shlq $0x6, %r14
addq 0x50(%rsp), %r14
imull $0x38, %r13d, %ecx
movl %ecx, (%rsp)
imull $0x7, %r13d, %ecx
movl %ecx, 0x28(%rsp)
movq %r13, %rcx
shlq $0x9, %rcx
movq %rcx, 0x58(%rsp)
testq %rax, %rax
je 0x117b1
leaq 0x20(%rsp), %rdi
callq 0x7b62
movslq %eax, %rcx
andl $0x7, %eax
leal 0x38(%rax), %esi
xorl (%rsp), %esi
leaq 0x109f26(%rip), %rax    # 0x11b750
movq 0x58(%rsp), %rdx
addq %rdx, %rax
movq (%rax,%rcx,8), %r15
sarl $0x3, %ecx
movl %esi, %eax
shrl $0x3, %eax
movl %ecx, %edx
subl %eax, %edx
movl %edx, %ebx
negl %ebx
cmovsl %edx, %ebx
xorl 0x28(%rsp), %ecx
xorl %eax, %eax
cmpl $0x1, %ecx
sete %al
subl %eax, %ebx
movq 0x10(%rsp), %rax
movl (%rax), %edi
callq 0x75ec
movl %eax, %ebp
movq 0x8(%rsp), %rax
movl 0x1090(%rax), %eax
xorl %ecx, %ecx
cmpq %rax, %r13
setne %cl
subl %ecx, %ebp
movq (%r14), %r12
andq %r15, %r12
cmpl %ebp, %ebx
jl 0x11889
cmpq %r15, %r12
jne 0x118cf
movq 0x8(%rsp), %rax
movq 0x140(%rax,%r13,8), %rdi
andq %r15, %rdi
callq 0x122c5
addl %ebx, %eax
cmpl %ebp, %eax
jl 0x118a9
cmpq %r15, %r12
jne 0x118cf
addl %eax, %eax
movq 0x8(%rsp), %rcx
movl 0x1090(%rcx), %ecx
xorl %edx, %edx
cmpq %rcx, %r13
sete %dl
subl %edx, %eax
movl 0x18(%rsp,%r13,4), %ecx
cmpl %eax, %ecx
cmovll %ecx, %eax
movl %eax, 0x18(%rsp,%r13,4)
movq 0x20(%rsp), %rax
jmp 0x11808
movl 0x18(%rsp), %ebp
movl 0x1c(%rsp), %r14d
movl %ebp, %eax
subl %r14d, %eax
movl %eax, %ecx
negl %ecx
cmovsl %eax, %ecx
cmpl $0x3, %ecx
jb 0x119ef
xorl %ecx, %ecx
xorl %eax, %eax
xorl %r15d, %r15d
cmpl %r14d, %ebp
setge %al
movq %rax, (%rsp)
setl %r15b
movq 0x8(%rsp), %rdx
movq 0x140(%rdx,%r15,8), %rax
pushq $-0x7
popq %r12
cmovll %ecx, %r12d
pushq $0x7
popq %rsi
cmovgel %ecx, %esi
movl %esi, 0x34(%rsp)
andq 0x108(%rdx), %rax
leaq 0x20(%rsp), %r13
movq %rax, (%r13)
leaq 0xffa6e(%rip), %rbx     # 0x1113b0
movq %rax, 0x10(%rsp)
testq %rax, %rax
je 0x119da
movq %r13, %rdi
callq 0x7b62
movslq %eax, %rcx
sarl $0x3, %eax
leal (%rax,%r12), %edx
movl %edx, %esi
negl %esi
cmovsl %edx, %esi
xorl 0x34(%rsp), %eax
xorl %edx, %edx
cmpl $0x1, %eax
sete %dl
subl %edx, %esi
addl %esi, %esi
xorl %eax, %eax
movq 0x8(%rsp), %rdx
cmpl %r15d, 0x1090(%rdx)
sete %al
subl %eax, %esi
movq (%rsp), %rax
movl 0x18(%rsp,%rax,4), %eax
addl $0x3, %eax
cmpl %esi, %eax
jle 0x119c2
movl %r15d, %eax
shll $0x9, %eax
addq 0x235e8(%rip), %rax     # 0x34f90
movq 0x8(%rsp), %rsi
movq 0x108(%rsi), %rdx
andq (%rax,%rcx,8), %rdx
testq %rdx, 0x140(%rsi,%r15,8)
je 0x119d0
movq 0x10(%rsp), %rax
andq (%rbx,%rcx,8), %rax
movq %rax, 0x10(%rsp)
movq 0x20(%rsp), %rax
jmp 0x11947
movq 0x40(%rsp), %rax
movq 0x8(%rax), %rax
movq 0x10(%rsp), %rcx
testq %rcx, 0x8(%rax,%r15,8)
je 0x11a03
xorl %eax, %eax
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rcx, %rax
movq %r12, 0x80(%rsp)
xorl %ecx, %ecx
movl %ebp, 0x64(%rsp)
movl %r14d, 0x60(%rsp)
cmpl %r14d, %ebp
setl %cl
leaq 0x20(%rsp), %rdx
movq %rax, (%rdx)
shll $0x4, %ecx
addl $-0x8, %ecx
movq %rcx, 0x98(%rsp)
movl %r15d, %edx
shll $0x9, %edx
movq 0x38(%rsp), %rcx
movq %rdx, 0x78(%rsp)
addq %rdx, %rcx
addq $0x180, %rcx            # imm = 0x180
movq %rcx, 0x50(%rsp)
leaq 0x48(%rsp), %r12
movq %r15, 0x70(%rsp)
testq %rax, %rax
je 0x11ca0
leaq 0x20(%rsp), %rdi
callq 0x7b62
movl %eax, %edx
movslq %eax, %rcx
andl $0x7, %eax
sarl $0x3, %edx
movq 0x80(%rsp), %rsi
addl %edx, %esi
movl %esi, %edi
negl %edi
cmovsl %esi, %edi
xorl 0x34(%rsp), %edx
xorl %esi, %esi
cmpl $0x1, %edx
sete %sil
subl %esi, %edi
movq %rdi, 0x90(%rsp)
xorl %esi, %esi
movq 0x8(%rsp), %rdx
cmpl %r15d, 0x1090(%rdx)
sete %sil
negl %esi
movq %rsi, 0x88(%rsp)
leaq 0xffb89(%rip), %rsi     # 0x111650
movq (%rsi,%rax,8), %rax
movq %rax, 0xa0(%rsp)
leaq 0x109c76(%rip), %rax    # 0x11b750
movq 0x78(%rsp), %rsi
addq %rsi, %rax
movq (%rax,%rcx,8), %rax
movq %rax, 0x58(%rsp)
movq (%rsp), %rax
movq 0x140(%rdx,%rax,8), %rdi
andq 0x108(%rdx), %rdi
leaq 0x10a04b(%rip), %rax    # 0x11bb50
addq %rsi, %rax
movq (%rax,%rcx,8), %rax
movq %rdi, 0x40(%rsp)
andq %rdi, %rax
movq %rax, 0x68(%rsp)
pushq $-0x2
popq %rdx
rolq %cl, %rdx
movq %rdx, 0x38(%rsp)
movl $0x100, %r14d           # imm = 0x100
movq $0x0, 0x28(%rsp)
xorl %ebp, %ebp
movl $0x100, %r15d           # imm = 0x100
testq %rax, %rax
je 0x11c56
leaq 0x68(%rsp), %rdi
callq 0x7b62
movl %eax, %r13d
movl $0x100, %ebx            # imm = 0x100
movq 0x40(%rsp), %rax
testq %rax, 0x58(%rsp)
je 0x11bf3
movslq %r13d, %rax
movq (%rsp), %rcx
shll $0x9, %ecx
addq 0x23449(%rip), %rcx     # 0x34fc0
movq (%rcx,%rax,8), %rax
andq 0x38(%rsp), %rax
andq 0x10(%rsp), %rax
movq %rax, 0x48(%rsp)
testq %rax, %rax
je 0x11bb0
movq %r12, %rdi
callq 0x7b62
movl %r13d, %edi
movl %eax, %esi
callq 0x75ec
addl $-0x2, %eax
cmpl %eax, %ebx
cmovgel %eax, %ebx
movq 0x48(%rsp), %rax
jmp 0x11b8a
testl %ebx, %ebx
jle 0x11be9
movq 0x28(%rsp), %rax
leal (%rax,%rbx,2), %eax
movq %rax, 0x28(%rsp)
leal 0x1(%rbp), %ebx
movq 0x50(%rsp), %rax
movl (%rax), %edi
movl %r13d, %esi
callq 0x75ec
cmpl %eax, %r14d
cmovll %r14d, %eax
leal (%rax,%rbp), %r15d
incl %r15d
addl %r15d, %r15d
movl %ebx, %ebp
movl %eax, %r14d
movq 0x68(%rsp), %rax
jmp 0x11b3b
movq 0x98(%rsp), %rax
addl %r13d, %eax
sarl $0x3, %eax
cltq
movq (%rsp), %rcx
shll $0x6, %ecx
addq 0x23337(%rip), %rcx     # 0x34f48
movq (%rcx,%rax,8), %rax
andq 0xa0(%rsp), %rax
andq 0x10(%rsp), %rax
movq %rax, 0x48(%rsp)
movl $0x100, %ebx            # imm = 0x100
testq %rax, %rax
je 0x11b66
movq %r12, %rdi
callq 0x7b62
movl %r13d, %edi
movl %eax, %esi
callq 0x75ec
addl $-0x2, %eax
cmpl %eax, %ebx
cmovgel %eax, %ebx
movq 0x48(%rsp), %rax
jmp 0x11c2c
movq 0x90(%rsp), %rax
movq 0x88(%rsp), %rcx
leal (%rcx,%rax,2), %edx
movq (%rsp), %rax
movl 0x18(%rsp,%rax,4), %ecx
addl $0x3, %ecx
movq 0x28(%rsp), %rsi
addl %edx, %esi
xorl %eax, %eax
cmpl %esi, %ecx
jg 0x119f1
addl %edx, %r15d
cmpl %r15d, %ecx
jg 0x119f1
movq 0x20(%rsp), %rax
movq 0x70(%rsp), %r15
jmp 0x11a5e
movq (%rsp), %rax
movl 0x18(%rsp,%rax,4), %eax
shll $0x5, %eax
movl $0x500, %ecx            # imm = 0x500
subl %eax, %ecx
movl %ecx, %eax
negl %eax
movl 0x60(%rsp), %edx
cmpl %edx, 0x64(%rsp)
cmovll %ecx, %eax
jmp 0x119f1