// File: 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:
subq $0xed8, %rsp            # imm = 0xED8
movq %rdi, 0xec8(%rsp)
movq %rsi, 0xec0(%rsp)
movl %edx, 0xebc(%rsp)
movl %ecx, 0xeb8(%rsp)
movl %r8d, 0xeb4(%rsp)
movq 0xec0(%rsp), %rax
movl 0x1c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x1c(%rax)
movq 0xec8(%rsp), %rsi
leaq 0x1e2b93(%rip), %rdi    # 0x216740
callq 0x35570
testb $0x1, %al
jne 0x33bd9
movq 0xec8(%rsp), %rdi
callq 0x38990
testb $0x1, %al
jne 0x33bd9
movq 0xec8(%rsp), %rdi
callq 0x30090
cmpl $0x63, %eax
jle 0x33be9
movl $0x0, 0xed4(%rsp)
jmp 0x33fc6
movq 0xec8(%rsp), %rsi
leaq 0xe00(%rsp), %rdi
callq 0x21910
leaq 0xe00(%rsp), %rdi
callq 0x237f0
movl %eax, 0xdfc(%rsp)
movl 0xdfc(%rsp), %eax
cmpl 0xeb4(%rsp), %eax
jl 0x33c35
movl 0xeb4(%rsp), %eax
movl %eax, 0xed4(%rsp)
jmp 0x33fc6
leaq 0xeb8(%rsp), %rdi
leaq 0xdfc(%rsp), %rsi
callq 0x35600
movl (%rax), %eax
movl %eax, 0xeb8(%rsp)
movq 0xec8(%rsp), %rsi
movl 0xebc(%rsp), %r8d
leaq 0x5a0(%rsp), %rdi
xorl %edx, %edx
leaq 0x1e2acc(%rip), %rcx    # 0x216740
movl $0x1, %r9d
callq 0x26ba0
movl $0xffff3cb0, 0x59c(%rsp) # imm = 0xFFFF3CB0
leaq 0x5a0(%rsp), %rdi
callq 0x27210
movw %ax, 0x5a(%rsp)
jmp 0x33c9e
movw 0x5a(%rsp), %ax
movw %ax, 0x596(%rsp)
cmpw $0x0, %ax
je 0x33f5c
movq 0xec8(%rsp), %rdi
callq 0x28680
movb %al, 0x59(%rsp)
jmp 0x33cc8
movb 0x59(%rsp), %al
testb $0x1, %al
jne 0x33e0f
jmp 0x33cd6
movq 0xec8(%rsp), %rdi
movzwl 0x596(%rsp), %esi
callq 0x379e0
movb %al, 0x58(%rsp)
jmp 0x33cf1
movb 0x58(%rsp), %al
testb $0x1, %al
jne 0x33e0f
jmp 0x33cff
movq 0xec8(%rsp), %rdi
movzwl 0x596(%rsp), %esi
callq 0x35640
movb %al, 0x57(%rsp)
jmp 0x33d1a
movb 0x57(%rsp), %al
testb $0x1, %al
jne 0x33e0f
jmp 0x33d28
movzwl 0x596(%rsp), %edi
callq 0x2a0c0
movb %al, 0x56(%rsp)
jmp 0x33d3b
movb 0x56(%rsp), %al
testb $0x1, %al
jne 0x33e0f
jmp 0x33d49
movl 0xdfc(%rsp), %eax
addl $0x64, %eax
movl %eax, 0x44(%rsp)
movq 0xec8(%rsp), %rax
movq %rax, 0x48(%rsp)
movzwl 0x596(%rsp), %edi
callq 0x26830
movl %eax, 0x50(%rsp)
jmp 0x33d77
movl 0x50(%rsp), %esi
movq 0x48(%rsp), %rdi
callq 0x29bd0
movl %eax, 0x40(%rsp)
jmp 0x33d8b
movl 0x44(%rsp), %eax
movl 0x40(%rsp), %ecx
movl %ecx, %ecx
movl %ecx, %edx
leaq 0xf652(%rip), %rcx      # 0x433f0
addl (%rcx,%rdx,4), %eax
movl %eax, 0x580(%rsp)
movl 0x580(%rsp), %eax
cmpl 0xeb8(%rsp), %eax
jg 0x33e0d
leaq 0x59c(%rsp), %rdi
leaq 0x580(%rsp), %rsi
callq 0x35600
movq %rax, 0x38(%rsp)
jmp 0x33dd4
movq 0x38(%rsp), %rax
movl (%rax), %eax
movl %eax, 0x59c(%rsp)
jmp 0x33c8a
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x588(%rsp)
movl %eax, 0x584(%rsp)
leaq 0x5a0(%rsp), %rdi
callq 0x263d0
jmp 0x33fd5
jmp 0x33e0f
movq 0xec8(%rsp), %rsi
leaq 0x78(%rsp), %rdi
callq 0x36210
jmp 0x33e23
movzwl 0x596(%rsp), %esi
leaq 0x78(%rsp), %rdi
callq 0x38340
jmp 0x33e37
leaq 0x78(%rsp), %rdi
callq 0x308b0
movq %rax, 0x30(%rsp)
jmp 0x33e48
movq 0x30(%rsp), %rax
movq %rax, 0x60(%rsp)
leaq 0x596(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x356c0
movq %rdx, 0x20(%rsp)
movw %ax, 0x2e(%rsp)
jmp 0x33e70
movq 0x20(%rsp), %rax
movw 0x2e(%rsp), %cx
movw %cx, 0x68(%rsp)
movq %rax, 0x70(%rsp)
leaq 0x1e28b5(%rip), %rdi    # 0x216740
leaq 0x68(%rsp), %rsi
callq 0x30840
jmp 0x33e97
movq 0xec0(%rsp), %rsi
movl 0xebc(%rsp), %edx
incl %edx
movl 0xeb4(%rsp), %ecx
negl %ecx
movl 0xeb8(%rsp), %r8d
negl %r8d
leaq 0x78(%rsp), %rdi
callq 0x33b60
movl %eax, 0x1c(%rsp)
jmp 0x33ecc
movl 0x1c(%rsp), %eax
negl %eax
movl %eax, 0x598(%rsp)
leaq 0x1e2860(%rip), %rdi    # 0x216740
callq 0x35700
jmp 0x33ee7
movl 0x598(%rsp), %eax
cmpl 0x59c(%rsp), %eax
jl 0x33f05
movl 0x598(%rsp), %eax
movl %eax, 0x59c(%rsp)
leaq 0xeb8(%rsp), %rdi
leaq 0x59c(%rsp), %rsi
callq 0x35600
movq %rax, 0x10(%rsp)
jmp 0x33f21
movq 0x10(%rsp), %rax
movl (%rax), %eax
movl %eax, 0xeb8(%rsp)
movl 0xeb8(%rsp), %eax
cmpl 0xeb4(%rsp), %eax
jl 0x33f57
movl 0xeb4(%rsp), %eax
movl %eax, 0xed4(%rsp)
movl $0x1, 0x5c(%rsp)
jmp 0x33fb9
jmp 0x33c8a
cmpl $0xffff3cb0, 0x59c(%rsp) # imm = 0xFFFF3CB0
jne 0x33fa3
movq 0xec8(%rsp), %rdi
callq 0x35730
movb %al, 0xf(%rsp)
jmp 0x33f7c
movb 0xf(%rsp), %al
testb $0x1, %al
jne 0x33f86
jmp 0x33fa3
movl 0xebc(%rsp), %eax
addl $0xffff8001, %eax       # imm = 0xFFFF8001
movl %eax, 0xed4(%rsp)
movl $0x1, 0x5c(%rsp)
jmp 0x33fb9
movl 0xeb8(%rsp), %eax
movl %eax, 0xed4(%rsp)
movl $0x1, 0x5c(%rsp)
leaq 0x5a0(%rsp), %rdi
callq 0x263d0
movl 0xed4(%rsp), %eax
addq $0xed8, %rsp            # imm = 0xED8
retq
movq 0x588(%rsp), %rdi
callq 0x54b0
nopw %cs:(%rax,%rax)