// File: SethKasmann[P]clever-girl/src/state.cpp
// Function: State::isValid(unsigned short, unsigned long long) const
bool State::isValid(Move pMove, U64 pValidMoves) const
{
    assert(getSrc(pMove) < no_sq);
    assert(getDst(pMove) < no_sq);

    Square src, dst;
    U64 ray;
    src = getSrc(pMove);
    dst = getDst(pMove);

// -------------------------------------------------------------------------- //
//                                                                            //
// The first line of defense is to simply check if the move is a null move.   //
// Killer moves are initialized as null moves, so this can occur if no killer //
// has been stored yet.                                                       //
//                                                                            //
// -------------------------------------------------------------------------- //
    if (pMove == nullMove)
        return false;

// -------------------------------------------------------------------------- //
//                                                                            //
// Check for a bad promotion. If the move is a promotion then the piece to be //
// moved must be a pawn.                                                      //
//                                                                            //
// -------------------------------------------------------------------------- //
    if (getPiecePromo(pMove) && (onSquare(src) != pawn))
        return false;

// -------------------------------------------------------------------------- //
//                                                                            //
// Confirm that if a move is a castle we are actually moving the king.        //
//                                                                            //
// -------------------------------------------------------------------------- //
    if (isCastle(pMove) && onSquare(src) != king)
        return false;

// -------------------------------------------------------------------------- //
//                                                                            //
// Three of the more obvious checks a move has to pass:                       //
//   1. We occupy the source square.                                          //
//   2. We do not occupy the destination square.                              //
//   3. We are not capturing the enemy king.                                  //
//                                                                            //
// -------------------------------------------------------------------------- //
    if (!(square_bb[src] & getOccupancyBB(mUs)) || 
        (square_bb[dst]  & getOccupancyBB(mUs)) ||
        dst == getKingSquare(mThem))
        return false;

    assert(dst != getKingSquare(mThem));
    assert(dst != getKingSquare(mUs));

    switch (onSquare(src))
    {

// -------------------------------------------------------------------------- //
//                                                                            //
// Pawns are the trickiest, so there are a number of cases to check.          //
//   1. If the pawn is promoting, make sure the move is a promotion.          //
//   2. If the move is en-passant, we need to confirm that the piece we are   //
//      capturing is a valid move square, and that capturing the enemy pawn   //
//      does not leave our king in check. This edge case will not be picked   //
//      up by the pin detection - since both pawns could be on the same       //
//      horizontal ray as the king.                                           //
//   3. If the pawn pushed, make sure the destination is empty and valid.     //
//   4. If the pawn double pushed, confirm the destination square is empty    //
//      and valid, and that the square between the source and destination is  //
//      empty.                                                                //
//   5. If the pawn is attacking, confirm the enemy occupys the destination.  //
//                                                                            //
// -------------------------------------------------------------------------- //
        case pawn:
        {
            if ((square_bb[dst] & RankPromo) && !getPiecePromo(pMove))
                return false;

            if (src < dst == mUs)
                return false;
            
            std::pair<Square, Square> advance = std::minmax(src, dst);
            switch (advance.second - advance.first)
            {
                case 8:
                    return square_bb[dst] & getEmptyBB() & pValidMoves;
                case 16:
                    return square_bb[dst] & getEmptyBB() & pValidMoves &&
                           between_hor[src][dst] & getEmptyBB() &&
                           square_bb[src] & RankPawnStart;
                case 7:
                case 9:
                    return square_bb[dst] & getOccupancyBB(mThem) & pValidMoves;
                default:
                    return false;
            }
        }

// -------------------------------------------------------------------------- //
//                                                                            //
// Knights, bishops, rooks, and queens are simple. Just check if the attack   //
// bitboard from the source square bitwise ANDs with the destination square   //
// and the valid moves bitboard.                                              //
//                                                                            //
// -------------------------------------------------------------------------- //
        case knight:
            return getAttackBB<knight>(src) & square_bb[dst] & pValidMoves;
        case bishop:
            return getAttackBB<bishop>(src) & square_bb[dst] & pValidMoves;
        case rook:
            return getAttackBB<rook>(src) & square_bb[dst] & pValidMoves;
        case queen:
            return getAttackBB<queen>(src) & square_bb[dst] & pValidMoves;

// -------------------------------------------------------------------------- //
//                                                                            //
// For king moves we first need to check if the move is a castling move. If   //
// so, there are four checks to confirm the move is valid in the current      //
// state:                                                                     //
//   1. The castle rights are valid.                                          //
//   2. There are no pieces between the king and rook.                        //
//   3. Confirm the square next to the king is not attacked (since you cannot //
//      castle through check).                                                //
//   4. Confirm the castle will not leave the king in check.                  //
//                                                                            //
// If the move is not a castling move, just make sure the destination will    //
// bitwise AND withe valid king moves bitboard.                               //
//                                                                            //
// -------------------------------------------------------------------------- //
        case king:
        {
            Square k = getKingSquare(mUs);
            if (isCastle(pMove))
            {
                if (src > dst)
                {
                    return (canCastleKingside() 
                    && !(between_hor[k][k-3] & getOccupancyBB())
                    && !attacked(k-1) 
                    && !attacked(k-2));
                }
                else
                {
                    return (canCastleQueenside()
                    && !(between_hor[k][k+4] & getOccupancyBB())
                    && !attacked(k+1)
                    && !attacked(k+2));
                }
            }
            return square_bb[dst];
        }
    }
// -------------------------------------------------------------------------- //
//                                                                            //
// If we didn't return inside the switch, something went wrong.               //
//                                                                            //
// -------------------------------------------------------------------------- //
    assert(false);
}

// Assembly:
subq $0xd8, %rsp
movw %si, %ax
movq %rdi, 0xc8(%rsp)
movw %ax, 0xc6(%rsp)
movq %rdx, 0xb8(%rsp)
movq 0xc8(%rsp), %rax
movq %rax, 0x80(%rsp)
movzwl 0xc6(%rsp), %edi
callq 0x26810
movl %eax, 0xb4(%rsp)
movzwl 0xc6(%rsp), %edi
callq 0x26830
movl %eax, 0xb0(%rsp)
movzwl 0xc6(%rsp), %eax
cmpl $0x0, %eax
jne 0x372e4
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
movzwl 0xc6(%rsp), %edi
callq 0x268e0
cmpl $0x0, %eax
je 0x3731c
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
callq 0x29bd0
cmpl $0x0, %eax
je 0x3731c
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
movzwl 0xc6(%rsp), %edi
callq 0x3a1d0
testb $0x1, %al
jne 0x3732f
jmp 0x37355
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
callq 0x29bd0
cmpl $0x5, %eax
je 0x37355
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %eax
movl %eax, %ecx
leaq 0x11d7a3(%rip), %rax    # 0x154b10
movq (%rax,%rcx,8), %rax
movq %rax, 0x78(%rsp)
movl (%rdi), %esi
callq 0x25740
movq %rax, %rcx
movq 0x78(%rsp), %rax
andq %rcx, %rax
cmpq $0x0, %rax
je 0x373ec
movq 0x80(%rsp), %rdi
movl 0xb0(%rsp), %eax
movl %eax, %ecx
leaq 0x11d76a(%rip), %rax    # 0x154b10
movq (%rax,%rcx,8), %rax
movq %rax, 0x70(%rsp)
movl (%rdi), %esi
callq 0x25740
movq %rax, %rcx
movq 0x70(%rsp), %rax
andq %rcx, %rax
cmpq $0x0, %rax
jne 0x373ec
movq 0x80(%rsp), %rdi
movl 0xb0(%rsp), %eax
movl %eax, 0x6c(%rsp)
movl 0x4(%rdi), %esi
callq 0x24ea0
movl %eax, %ecx
movl 0x6c(%rsp), %eax
cmpl %ecx, %eax
jne 0x373f9
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
callq 0x29bd0
movl %eax, %ecx
movq %rcx, 0x60(%rsp)
subl $0x5, %eax
ja 0x379cc
movq 0x60(%rsp), %rax
leaq 0xbff7(%rip), %rcx      # 0x43420
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl 0xb0(%rsp), %eax
movl %eax, %edx
leaq 0x11d6ce(%rip), %rcx    # 0x154b10
movabsq $-0xffffffffffff01, %rax # imm = 0xFF000000000000FF
andq (%rcx,%rdx,8), %rax
cmpq $0x0, %rax
je 0x37475
movzwl 0xc6(%rsp), %edi
callq 0x268e0
cmpl $0x0, %eax
jne 0x37475
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rcx
movl 0xb4(%rsp), %eax
cmpl 0xb0(%rsp), %eax
setb %al
andb $0x1, %al
movzbl %al, %eax
cmpl (%rcx), %eax
jne 0x374a4
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
leaq 0xb4(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0x3a480
movq %rax, 0x90(%rsp)
movq %rdx, 0x98(%rsp)
leaq 0xa0(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x3a4e0
movl 0xa0(%rsp), %esi
movl 0xa4(%rsp), %edi
callq 0x3a510
addl $-0x7, %eax
movl %eax, %ecx
movq %rcx, 0x58(%rsp)
subl $0x9, %eax
ja 0x3767d
movq 0x58(%rsp), %rax
leaq 0xbf28(%rip), %rcx      # 0x43438
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x80(%rsp), %rdi
movl 0xb0(%rsp), %eax
movl %eax, %ecx
leaq 0x11d5df(%rip), %rax    # 0x154b10
movq (%rax,%rcx,8), %rax
movq %rax, 0x50(%rsp)
callq 0x24ef0
movq %rax, %rcx
movq 0x50(%rsp), %rax
andq %rcx, %rax
andq 0xb8(%rsp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb0(%rsp), %eax
movl %eax, %ecx
leaq 0x11d591(%rip), %rax    # 0x154b10
movq (%rax,%rcx,8), %rax
movq %rax, 0x40(%rsp)
callq 0x24ef0
movq 0x40(%rsp), %rcx
andq %rax, %rcx
andq 0xb8(%rsp), %rcx
xorl %eax, %eax
cmpq $0x0, %rcx
movb %al, 0x4f(%rsp)
je 0x3761a
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %eax
movl %eax, %ecx
leaq 0x12674f(%rip), %rax    # 0x15dd10
shlq $0x9, %rcx
addq %rcx, %rax
movl 0xb0(%rsp), %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x38(%rsp)
callq 0x24ef0
movq 0x38(%rsp), %rcx
andq %rax, %rcx
xorl %eax, %eax
cmpq $0x0, %rcx
movb %al, 0x4f(%rsp)
je 0x3761a
movl 0xb4(%rsp), %eax
movl %eax, %edx
leaq 0x11d50f(%rip), %rcx    # 0x154b10
movabsq $0xff00000000ff00, %rax # imm = 0xFF00000000FF00
andq (%rcx,%rdx,8), %rax
cmpq $0x0, %rax
setne %al
movb %al, 0x4f(%rsp)
movb 0x4f(%rsp), %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb0(%rsp), %eax
movl %eax, %ecx
leaq 0x11d4cc(%rip), %rax    # 0x154b10
movq (%rax,%rcx,8), %rax
movq %rax, 0x30(%rsp)
movl 0x4(%rdi), %esi
callq 0x25740
movq %rax, %rcx
movq 0x30(%rsp), %rax
andq %rcx, %rax
andq 0xb8(%rsp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movb $0x0, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
xorl %edx, %edx
callq 0x25160
movl 0xb0(%rsp), %ecx
movl %ecx, %edx
leaq 0x11d460(%rip), %rcx    # 0x154b10
andq (%rcx,%rdx,8), %rax
andq 0xb8(%rsp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
xorl %edx, %edx
callq 0x25370
movl 0xb0(%rsp), %ecx
movl %ecx, %edx
leaq 0x11d419(%rip), %rcx    # 0x154b10
andq (%rcx,%rdx,8), %rax
andq 0xb8(%rsp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
xorl %edx, %edx
callq 0x25480
movl 0xb0(%rsp), %ecx
movl %ecx, %edx
leaq 0x11d3d2(%rip), %rcx    # 0x154b10
andq (%rcx,%rdx,8), %rax
andq 0xb8(%rsp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl 0xb4(%rsp), %esi
xorl %edx, %edx
callq 0x25630
movl 0xb0(%rsp), %ecx
movl %ecx, %edx
leaq 0x11d38b(%rip), %rcx    # 0x154b10
andq (%rcx,%rdx,8), %rax
andq 0xb8(%rsp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
movl (%rdi), %esi
callq 0x24ea0
movl %eax, 0x8c(%rsp)
movzwl 0xc6(%rsp), %edi
callq 0x3a1d0
testb $0x1, %al
jne 0x377d2
jmp 0x379a9
movl 0xb4(%rsp), %eax
cmpl 0xb0(%rsp), %eax
jbe 0x378ca
movq 0x80(%rsp), %rdi
callq 0x2b1c0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x2f(%rsp)
jne 0x37805
jmp 0x378b8
movl 0x8c(%rsp), %eax
movl %eax, %ecx
leaq 0x1264fb(%rip), %rax    # 0x15dd10
shlq $0x9, %rcx
addq %rcx, %rax
movq %rax, 0x18(%rsp)
movl 0x8c(%rsp), %edi
movl $0x3, %esi
callq 0x24e80
movq 0x80(%rsp), %rdi
movl %eax, %ecx
movq 0x18(%rsp), %rax
movl %ecx, %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x20(%rsp)
callq 0x24bc0
movq 0x20(%rsp), %rcx
andq %rax, %rcx
xorl %eax, %eax
cmpq $0x0, %rcx
movb %al, 0x2f(%rsp)
jne 0x378b8
movl 0x8c(%rsp), %edi
movl $0x1, %esi
callq 0x24e80
movq 0x80(%rsp), %rdi
movl %eax, %esi
callq 0x2b210
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x2f(%rsp)
jne 0x378b8
movl 0x8c(%rsp), %edi
movl $0x2, %esi
callq 0x24e80
movq 0x80(%rsp), %rdi
movl %eax, %esi
callq 0x2b210
xorb $-0x1, %al
movb %al, 0x2f(%rsp)
movb 0x2f(%rsp), %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movq 0x80(%rsp), %rdi
callq 0x2b380
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x17(%rsp)
jne 0x378e9
jmp 0x3799a
movl 0x8c(%rsp), %eax
movl %eax, %ecx
leaq 0x126417(%rip), %rax    # 0x15dd10
shlq $0x9, %rcx
addq %rcx, %rax
movq %rax, (%rsp)
movl 0x8c(%rsp), %edi
movl $0x4, %esi
callq 0x24e60
movq 0x80(%rsp), %rdi
movl %eax, %ecx
movq (%rsp), %rax
movl %ecx, %ecx
movq (%rax,%rcx,8), %rax
movq %rax, 0x8(%rsp)
callq 0x24bc0
movq 0x8(%rsp), %rcx
andq %rax, %rcx
xorl %eax, %eax
cmpq $0x0, %rcx
movb %al, 0x17(%rsp)
jne 0x3799a
movl 0x8c(%rsp), %edi
movl $0x1, %esi
callq 0x24e60
movq 0x80(%rsp), %rdi
movl %eax, %esi
callq 0x2b210
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, 0x17(%rsp)
jne 0x3799a
movl 0x8c(%rsp), %edi
movl $0x2, %esi
callq 0x24e60
movq 0x80(%rsp), %rdi
movl %eax, %esi
callq 0x2b210
xorb $-0x1, %al
movb %al, 0x17(%rsp)
movb 0x17(%rsp), %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
movl 0xb0(%rsp), %eax
movl %eax, %ecx
leaq 0x11d157(%rip), %rax    # 0x154b10
cmpq $0x0, (%rax,%rcx,8)
setne %al
andb $0x1, %al
movb %al, 0xd7(%rsp)
jmp 0x379ce
ud2
movb 0xd7(%rsp), %al
andb $0x1, %al
addq $0xd8, %rsp
retq
nop