// File: /workspace/github_cpp_makefile_star2_O3/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:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
testl %esi, %esi
je 0x170bc
movq %rdx, %r14
movl %esi, %eax
movq %rdi, %rbx
andl $0x3f, %esi
movl %esi, %ecx
testl $0x7000, %eax           # imm = 0x7000
je 0x17069
cmpl $0x0, 0x188(%rbx,%rcx,4)
jne 0x170bc
testw %ax, %ax
jns 0x17078
cmpl $0x5, 0x188(%rbx,%rcx,4)
jne 0x170bc
leaq 0xe19f1(%rip), %r12     # 0xf8a70
movq (%r12,%rcx,8), %rdi
movl (%rbx), %r8d
movq 0x78(%rbx,%r8,8), %r10
testq %rdi, %r10
je 0x170bc
movl %eax, %r9d
shrl $0x6, %r9d
andl $0x3f, %r9d
movl %r9d, %r15d
movq (%r12,%r15,8), %rdx
testq %r10, %rdx
jne 0x170bc
movl 0x4(%rbx), %r10d
imulq $0xf0, %r10, %r11
cmpl %r9d, 0x3f0(%rbx,%r11)
jne 0x170c8
xorl %eax, %eax
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
retq
movl 0x188(%rbx,%rcx,4), %r11d
leaq 0x7279(%rip), %r13      # 0x1e350
movslq (%r13,%r11,4), %r11
addq %r13, %r11
jmpq *%r11
testl $0x7000, %eax           # imm = 0x7000
jne 0x170f8
movabsq $-0xffffffffffff01, %rax # imm = 0xFF000000000000FF
andq %rdx, %rax
jne 0x170bc
cmpw %r9w, %si
sbbl $0x0, %r8d
je 0x170bc
cmpw %si, %r9w
movl %esi, %eax
cmovbl %r9d, %eax
cmoval %r9d, %esi
subl %eax, %esi
xorl %eax, %eax
addl $-0x7, %esi
cmpl $0x9, %esi
ja 0x170be
leaq 0x7245(%rip), %r8       # 0x1e368
movslq (%r8,%rsi,4), %rsi
addq %r8, %rsi
jmpq *%rsi
andq 0x78(%rbx,%r10,8), %r14
jmp 0x171db
movq %rbx, %rdi
xorl %edx, %edx
callq 0x18bfa
andq (%r12,%r15,8), %rax
testq %r14, %rax
jmp 0x171de
movq 0x80(%rbx), %rax
orq 0x78(%rbx), %rax
leal (,%rcx,8), %esi
leaq 0xe0ab(%rip), %rdi      # 0x25210
movq (%rdi,%rsi), %rdi
leaq 0x46d0(%rip), %r8       # 0x1b840
andq (%r8,%rsi), %rax
leaq 0x44c5(%rip), %r8       # 0x1b640
imulq (%r8,%rsi), %rax
leaq 0x43b9(%rip), %rsi      # 0x1b540
jmp 0x171c4
movq 0x80(%rbx), %rax
orq 0x78(%rbx), %rax
leal (,%rcx,8), %esi
leaq 0xe26e(%rip), %rdi      # 0x25410
movq (%rdi,%rsi), %rdi
leaq 0x4193(%rip), %r8       # 0x1b340
andq (%r8,%rsi), %rax
leaq 0x3f88(%rip), %r8       # 0x1b140
imulq (%r8,%rsi), %rax
leaq 0x3e7c(%rip), %rsi      # 0x1b040
movb (%rsi,%rcx,4), %cl
shrq %cl, %rax
andq (%rdi,%rax,8), %r14
jmp 0x171db
leaq 0x4869(%rip), %rax      # 0x1ba40
andq (%rax,%rcx,8), %r14
testq %rdx, %r14
setne %al
jmp 0x170be
testw %ax, %ax
js 0x171f0
testq %rdx, %rdx
jmp 0x171de
leaq 0x328(%rbx), %rax
imulq $0xf0, %r8, %rcx
movl 0xc8(%rax,%rcx), %r14d
movl 0xc(%rbx), %eax
cmpw %r9w, %si
jbe 0x17266
xorl %ecx, %ecx
testl %r8d, %r8d
setne %cl
leal (%rcx,%rcx,2), %ecx
incl %ecx
testl %ecx, %eax
je 0x170bc
leal -0x3(%r14), %eax
movq %r14, %rcx
shlq $0x9, %rcx
addq 0xdd8a(%rip), %rcx      # 0x24fc0
movq 0x80(%rbx), %rdx
orq 0x78(%rbx), %rdx
testq %rdx, (%rcx,%rax,8)
jne 0x170bc
movl %r14d, %esi
decl %esi
movq %rbx, %rdi
callq 0x18c72
testb %al, %al
jne 0x170bc
leal -0x2(%r14), %esi
jmp 0x172be
testl %r8d, %r8d
movl $0x2, %ecx
movl $0x8, %edx
cmovel %ecx, %edx
testl %edx, %eax
je 0x170bc
leal 0x4(%r14), %eax
movq %r14, %rcx
shlq $0x9, %rcx
addq 0xdd30(%rip), %rcx      # 0x24fc0
movq 0x80(%rbx), %rdx
orq 0x78(%rbx), %rdx
testq %rdx, (%rcx,%rax,8)
jne 0x170bc
movl %r14d, %esi
incl %esi
movq %rbx, %rdi
callq 0x18c72
testb %al, %al
jne 0x170bc
leal 0x2(%r14), %esi
movq %rbx, %rdi
callq 0x18c72
xorb $0x1, %al
jmp 0x170be
movq 0x80(%rbx), %rax
orq 0x78(%rbx), %rax
notq %rax
andq %r14, %rdx
testq %rax, %rdx
je 0x170bc
shll $0x9, %ecx
addq 0xdccf(%rip), %rcx      # 0x24fc0
testq %rax, (%rcx,%r15,8)
je 0x170bc
movabsq $0xff00000000ff00, %rax # imm = 0xFF00000000FF00
testq %rax, %rdi
jmp 0x171de
movq 0x80(%rbx), %rax
orq 0x78(%rbx), %rax
notq %rax
andq %r14, %rax
testq %rdx, %rax
jmp 0x171de