// File: /workspace/github_cpp_makefile_star2_O3/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, %ebx
movq %rsi, %r12
movq %rdi, %r15
incl 0x1c(%rsi)
movq 0x145543(%rip), %rcx    # 0x15a6a8
movq 0x145534(%rip), %rax    # 0x15a6a0
movq %rcx, %rdx
subq %rax, %rdx
cmpq $0x41, %rdx
jb 0x1519e
shlq $0x1c, %rdx
movabsq $-0x500000000, %rsi     # imm = 0xFFFFFFFB00000000
addq %rdx, %rsi
sarq $0x1c, %rsi
movq 0x8(%rax,%rsi), %rdx
xorl %eax, %eax
cmpq -0x8(%rcx), %rdx
je 0x153d4
movq %r15, %rdi
callq 0x186de
movl %eax, %ecx
xorl %eax, %eax
testb %cl, %cl
jne 0x153d4
cmpl $0x63, 0x8(%r15)
jg 0x153d4
movq %r12, 0x20(%rsp)
movq %rbx, 0x18(%rsp)
leaq 0x38(%rsp), %rbx
movq %rbx, %rdi
movq %r15, %rsi
callq 0xdff4
movq %rbx, %rdi
callq 0xeeae
cmpl %r14d, %eax
jge 0x153d1
movl %eax, %r13d
cmpl %ebp, %eax
cmovgl %eax, %ebp
leaq 0x1454a9(%rip), %rcx    # 0x15a6a0
leaq 0x5f0(%rsp), %rdi
movq %r15, %rsi
xorl %edx, %edx
movq 0x18(%rsp), %rbx
movl %ebx, %r8d
movl $0x1, %r9d
callq 0xfcfa
addl $0x64, %r13d
leal 0x1(%rbx), %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, %r14d
leaq 0x5f0(%rsp), %rdi
callq 0xffc4
movl %eax, %ebx
testw %ax, %ax
je 0x15390
cmpq $0x0, 0x28(%r15)
movzwl %bx, %r12d
jne 0x152d2
movq %r15, %rdi
movl %r12d, %esi
callq 0x17326
testb %al, %al
jne 0x152d2
movl %ebx, %eax
andl $0x3f, %eax
cmpl $0x0, 0x188(%r15,%rax,4)
je 0x1528c
testl $0x7000, %ebx           # imm = 0x7000
jne 0x152d2
movl %ebx, %eax
shrl $0x6, %eax
andl $0x3f, %eax
jmp 0x152ad
testl $0x7000, %ebx           # imm = 0x7000
jne 0x152d2
movl %ebx, %eax
shrl $0x6, %eax
andl $0x3f, %eax
movq 0x30(%r15), %rcx
leaq 0xe37c9(%rip), %rdx     # 0xf8a70
andq (%rdx,%rax,8), %rcx
jne 0x152d2
movl 0x188(%r15,%rax,4), %eax
leaq 0x8fe4(%rip), %rcx      # 0x1e2a0
movl (%rcx,%rax,4), %eax
addl %r13d, %eax
cmpl %ebp, %eax
jg 0x152d2
cmpl %eax, %r14d
cmovlel %eax, %r14d
jmp 0x15238
leaq 0xe8(%rsp), %rdi
movq %r15, %rsi
callq 0x1637c
leaq 0xe8(%rsp), %rdi
movl %r12d, %esi
callq 0x17a3a
movq 0x100(%rsp), %rax
movw %bx, 0x28(%rsp)
movq %rax, 0x30(%rsp)
movq 0x14539d(%rip), %rsi    # 0x15a6a8
cmpq 0x14539e(%rip), %rsi    # 0x15a6b0
je 0x15326
movups 0x28(%rsp), %xmm0
movups %xmm0, (%rsi)
addq $0x10, 0x145384(%rip)   # 0x15a6a8
jmp 0x15337
leaq 0x145373(%rip), %rdi    # 0x15a6a0
leaq 0x28(%rsp), %rdx
callq 0x14a78
movl %ebp, %r8d
negl %r8d
leaq 0xe8(%rsp), %rdi
movq 0x20(%rsp), %rsi
movl 0x14(%rsp), %edx
movl 0x10(%rsp), %ecx
callq 0x1513d
movq 0x14534a(%rip), %rcx    # 0x15a6a8
cmpq %rcx, 0x14533b(%rip)    # 0x15a6a0
je 0x15372
addq $-0x10, %rcx
movq %rcx, 0x145336(%rip)    # 0x15a6a8
negl %eax
cmpl %eax, %r14d
cmovgl %r14d, %eax
cmpl %eax, %ebp
cmovlel %eax, %ebp
movl 0xc(%rsp), %r14d
cmpl %r14d, %ebp
jl 0x15235
jmp 0x153b4
cmpl $0xffff3cb0, %r14d      # imm = 0xFFFF3CB0
jne 0x153b1
movq %r15, %rdi
callq 0x1629e
movq 0x18(%rsp), %rcx
addl $0xffff8001, %ecx       # imm = 0xFFFF8001
testb %al, %al
cmovnel %ecx, %ebp
movl %ebp, %r14d
movq 0xe20(%rsp), %rdi
testq %rdi, %rdi
je 0x153d1
movq 0xe30(%rsp), %rsi
subq %rdi, %rsi
callq 0x4250
movl %r14d, %eax
addq $0xe48, %rsp            # imm = 0xE48
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x153ec
jmp 0x153ec
jmp 0x153ec
movq %rax, %rbx
movq 0xe20(%rsp), %rdi
testq %rdi, %rdi
je 0x1540c
movq 0xe30(%rsp), %rsi
subq %rdi, %rsi
callq 0x4250
movq %rbx, %rdi
callq 0x43b0