// File: /workspace/github_cpp_makefile_star2_O2/SethKasmann[P]clever-girl/src/search.cpp
// Function: qsearch(State&, SearchInfo&, int, int, int)
int qsearch(State& s, SearchInfo& si, int ply, int alpha, int beta)
{
    si.nodes++;
    assert(ply < Max_ply);

    if (history.isThreefoldRepetition(s) ||
        s.insufficientMaterial() ||
        s.getFiftyMoveRule() > 99)
        return Draw;

    Evaluate evaluate(s);

    int qscore = evaluate.getScore();

    // If a beta cutoff is found, return the qscore.
    if (qscore >= beta)
        return beta;

    // Update alpha.
    alpha = std::max(alpha, qscore);

    // Generate moves and create the movelist.
    MoveList mlist(s, nullMove, &history, ply, true);

    int bestScore = Neg_inf;
    int score;
    Move m;

    while (m = mlist.getBestMove())
    {
// -------------------------------------------------------------------------- //
//                                                                            //
// Futility pruning. Do not search subtrees that are unlikely to improve      //
// alpha. To avoid pruning away tactical positions, there are a few things    //
// we need to check:                                                          //
//   1. Side to move is not in check.                                         //
//   2. Move itself doesn't give check.                                       //
//   3. Move is not en passant. I want to be sure to calculate the fScore     //
//      properly, but en passant could throw a wrench by adding a 0 piece     //
//      value. Insead of a separate check to cover en passant moves, I am     //
//      currently just not cosidering them.                                   //
//                                                                            //
// -------------------------------------------------------------------------- //
        if (!s.inCheck() &&
            !s.givesCheck(m) &&
            !s.isEnPassant(m) &&
            !isPromotion(m))
        {
            // TODO:
            // Can I simply include en passant in this calculation?
            // Add a "gives check" function, so I dont have to make the move.
            int fScore = qscore + 100 + PieceValue[s.onSquare(getDst(m))];
            if (fScore <= alpha)
            {
                bestScore = std::max(bestScore, fScore);
                continue;
            }
        }

        State c(s);
        c.make_t(m);

        history.push(std::make_pair(m, c.getKey()));
        score = -qsearch(c, si, ply + 1, -beta, -alpha);
        history.pop();
        if (score >= bestScore)
            bestScore = score;

        alpha = std::max(alpha, bestScore);

        if (alpha >= beta)
            return beta;
    }

    if (bestScore == Neg_inf && s.check())
        return -Checkmate + ply;

    return alpha;                                // Fail-Hard alpha beta score.
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xe48, %rsp            # imm = 0xE48
movl %r8d, %r14d
movl %ecx, %ebp
movl %edx, %r12d
movq %rsi, %r13
movq %rdi, %r15
incl 0x1c(%rsi)
leaq 0x1d6dda(%rip), %rdi    # 0x1e86b0
movq %r15, %rsi
callq 0x1271a
xorl %ebx, %ebx
testb %al, %al
jne 0x11abc
movq %r15, %rdi
callq 0x139a8
testb %al, %al
jne 0x11abc
cmpl $0x63, 0x8(%r15)
jg 0x11abc
movq %r13, 0x20(%rsp)
leaq 0x38(%rsp), %rbx
movq %rbx, %rdi
movq %r15, %rsi
callq 0xb7f8
movq %rbx, %rdi
callq 0xc5d0
cmpl %r14d, %eax
jge 0x11ab9
movl %eax, %r13d
cmpl %ebp, %eax
cmovgl %eax, %ebp
leaq 0x1d6d78(%rip), %rcx    # 0x1e86b0
leaq 0x5f0(%rsp), %rdi
pushq $0x1
popq %r9
movq %r15, %rsi
xorl %edx, %edx
movl %r12d, %r8d
callq 0xd1d6
addl $0x64, %r13d
movq %r12, 0x18(%rsp)
leal 0x1(%r12), %eax
movl %eax, 0x14(%rsp)
movl %r14d, %eax
negl %eax
movl %eax, 0x10(%rsp)
movl $0xffff3cb0, %eax       # imm = 0xFFFF3CB0
movl %r14d, 0xc(%rsp)
movl %eax, %r12d
leaq 0x5f0(%rsp), %rdi
callq 0xd48e
movl %eax, %ebx
testw %ax, %ax
je 0x11a88
cmpq $0x0, 0x28(%r15)
movzwl %bx, %r14d
jne 0x119ec
movq %r15, %rdi
movl %r14d, %esi
callq 0x132fa
testb %al, %al
jne 0x119ec
movq %r15, %rdi
movl %r14d, %esi
callq 0x12752
testw $0x7000, %bx            # imm = 0x7000
setne %cl
orb %al, %cl
jne 0x119ec
movl %ebx, %eax
shrl $0x6, %eax
andl $0x3f, %eax
movl 0x188(%r15,%rax,4), %eax
leaq 0x78f7(%rip), %rcx      # 0x192d0
movl (%rcx,%rax,4), %eax
addl %r13d, %eax
cmpl %ebp, %eax
jg 0x119ec
cmpl %eax, %r12d
cmovlel %eax, %r12d
jmp 0x11979
leaq 0xe8(%rsp), %rdi
movq %r15, %rsi
callq 0x12874
leaq 0xe8(%rsp), %rdi
movl %r14d, %esi
callq 0x13694
movq 0x100(%rsp), %rax
movw %bx, 0x28(%rsp)
movq %rax, 0x30(%rsp)
leaq 0x1d6c8b(%rip), %rdi    # 0x1e86b0
leaq 0x28(%rsp), %rsi
callq 0x1121a
movl %ebp, %r8d
negl %r8d
leaq 0xe8(%rsp), %rdi
movq 0x20(%rsp), %rsi
movl 0x14(%rsp), %edx
movl 0x10(%rsp), %ecx
callq 0x118ad
movq 0x1d6c62(%rip), %rcx    # 0x1e86b8
cmpq %rcx, 0x1d6c53(%rip)    # 0x1e86b0
je 0x11a6a
addq $-0x10, %rcx
movq %rcx, 0x1d6c4e(%rip)    # 0x1e86b8
negl %eax
cmpl %eax, %r12d
cmovgl %r12d, %eax
cmpl %eax, %ebp
cmovlel %eax, %ebp
movl 0xc(%rsp), %r14d
cmpl %r14d, %ebp
jl 0x11976
jmp 0x11aac
cmpl $0xffff3cb0, %r12d      # imm = 0xFFFF3CB0
jne 0x11aa9
movq %r15, %rdi
callq 0x1277e
movq 0x18(%rsp), %rcx
addl $0xffff8001, %ecx       # imm = 0xFFFF8001
testb %al, %al
cmovnel %ecx, %ebp
movl %ebp, %r14d
leaq 0xe20(%rsp), %rdi
callq 0xd138
movl %r14d, %ebx
movl %ebx, %eax
addq $0xe48, %rsp            # imm = 0xE48
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x11ad6
jmp 0x11ad6
jmp 0x11ad6
movq %rax, %rbx
leaq 0xe20(%rsp), %rdi
callq 0xd138
movq %rbx, %rdi
callq 0x43d0