// File: jswaff[P]prophet3/src/perft.cpp
// Function: perft_test_fast()
void perft_test_fast() {
    print("starting perft_test_fast\n");
    int32 start_time = milli_timer();
    uint64 total_nodes = 0;

    position pos;
    total_nodes += test_case(&pos,"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",4,197281);
    total_nodes += test_case(&pos,"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1",3,97862);
    total_nodes += test_case(&pos,"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1",6,11030083L);
    total_nodes += test_case(&pos,"r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1",5,15833292L);
    total_nodes += test_case(&pos,"rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8",4,2103487);
    total_nodes += test_case(&pos,"r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10",4,3894594L);

    // illegal EP
    total_nodes += test_case(&pos,"3k4/3p4/8/K1P4r/8/8/8/8 b - - 0 1", 6, 1134888);
    total_nodes += test_case(&pos,"8/8/8/8/k1p4R/8/3P4/3K4 w - - 0 1", 6, 1134888);
    total_nodes += test_case(&pos,"8/8/4k3/8/2p5/8/B2P2K1/8 w - - 0 1", 6, 1015133);
    total_nodes += test_case(&pos,"8/b2p2k1/8/2P5/8/4K3/8/8 b - - 0 1", 6, 1015133);

    // ep capture checks opponent
    total_nodes += test_case(&pos,"8/8/1k6/2b5/2pP4/8/5K2/8 b - d3 0 1", 6, 1440467);
    total_nodes += test_case(&pos,"8/5k2/8/2Pp4/2B5/1K6/8/8 w - d6 0 1", 6, 1440467);

    // short castle gives check
    total_nodes += test_case(&pos,"5k2/8/8/8/8/8/8/4K2R w K - 0 1", 6, 661072);
    total_nodes += test_case(&pos,"4k2r/8/8/8/8/8/8/5K2 b k - 0 1", 6, 661072);

    // long castle gives check
    total_nodes += test_case(&pos,"3k4/8/8/8/8/8/8/R3K3 w Q - 0 1", 6, 803711);
    total_nodes += test_case(&pos,"r3k3/8/8/8/8/8/8/3K4 b q - 0 1", 6, 803711);

    // losing castling rights
    total_nodes += test_case(&pos,"r3k2r/1b4bq/8/8/8/8/7B/R3K2R w KQkq - 0 1", 4, 1274206);
    total_nodes += test_case(&pos,"r3k2r/7b/8/8/8/8/1B4BQ/R3K2R b KQkq - 0 1", 4, 1274206);

    // castling prevented
    total_nodes += test_case(&pos,"r3k2r/8/3Q4/8/8/5q2/8/R3K2R b KQkq - 0 1", 4, 1720476);
    total_nodes += test_case(&pos,"r3k2r/8/5Q2/8/8/3q4/8/R3K2R w KQkq - 0 1", 4, 1720476);

    // promote out of check
    total_nodes += test_case(&pos,"2K2r2/4P3/8/8/8/8/8/3k4 w - - 0 1", 6, 3821001);
    total_nodes += test_case(&pos,"3K4/8/8/8/8/8/4p3/2k2R2 b - - 0 1", 6, 3821001);

    // discovered check
    total_nodes += test_case(&pos,"8/8/1P2K3/8/2n5/1q6/8/5k2 b - - 0 1", 5, 1004658);
    total_nodes += test_case(&pos,"5K2/8/1Q6/2N5/8/1p2k3/8/8 w - - 0 1", 5, 1004658);

    // promote to give check
    total_nodes += test_case(&pos,"4k3/1P6/8/8/8/8/K7/8 w - - 0 1", 6, 217342);
    total_nodes += test_case(&pos,"8/k7/8/8/8/8/1p6/4K3 b - - 0 1", 6, 217342);

    // unpromote to check
    total_nodes += test_case(&pos,"8/P1k5/K7/8/8/8/8/8 w - - 0 1", 6, 92683);
    total_nodes += test_case(&pos,"8/8/8/8/8/k7/p1K5/8 b - - 0 1", 6, 92683);

    // self stalemate
    total_nodes += test_case(&pos,"K1k5/8/P7/8/8/8/8/8 w - - 0 1", 6, 2217);
    total_nodes += test_case(&pos,"8/8/8/8/8/p7/8/k1K5 b - - 0 1", 6, 2217);

    // stalemate checkmate
    total_nodes += test_case(&pos,"8/k1P5/8/1K6/8/8/8/8 w - - 0 1", 7, 567584);
    total_nodes += test_case(&pos,"8/8/8/8/1k6/8/K1p5/8 b - - 0 1", 7, 567584);

    // double check
    total_nodes += test_case(&pos,"8/8/2k5/5q2/5n2/8/5K2/8 b - - 0 1", 4, 23527);
    total_nodes += test_case(&pos,"8/5k2/8/5N2/5Q2/2K5/8/8 w - - 0 1", 4, 23527);

    int32 elapsed = milli_timer() - start_time + 1; // div by 0
    print("\n\naverage nps: %lu\n\n",total_nodes*1000/elapsed);

    print("... perft_test_fast complete!\n");
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1e0, %rsp            # imm = 0x1E0
leaq 0x29185(%rip), %rdi     # 0x370c7
movb $0x0, %al
callq 0x8c60
callq 0x14080
movl %eax, -0x4(%rbp)
movq $0x0, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x2917a(%rip), %rsi     # 0x370e1
movl $0x4, %edx
movl $0x302a1, %ecx          # imm = 0x302A1
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x2918e(%rip), %rsi     # 0x3711a
movl $0x3, %edx
movl $0x17e46, %ecx          # imm = 0x17E46
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291ae(%rip), %rsi     # 0x3715f
movl $0x6, %edx
movl $0xa84e43, %ecx         # imm = 0xA84E43
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291b3(%rip), %rsi     # 0x37189
movl $0x5, %edx
movl $0xf198cc, %ecx         # imm = 0xF198CC
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291cf(%rip), %rsi     # 0x371ca
movl $0x4, %edx
movl $0x2018bf, %ecx         # imm = 0x2018BF
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291e4(%rip), %rsi     # 0x37204
movl $0x4, %edx
movl $0x3b6d42, %ecx         # imm = 0x3B6D42
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x29208(%rip), %rsi     # 0x3724d
movl $0x6, %edx
movl $0x115128, %ecx         # imm = 0x115128
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x29205(%rip), %rsi     # 0x3726f
movl $0x6, %edx
movl $0x115128, %ecx         # imm = 0x115128
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x29202(%rip), %rsi     # 0x37291
movl $0x6, %edx
movl $0xf7d5d, %ecx          # imm = 0xF7D5D
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x29200(%rip), %rsi     # 0x372b4
movl $0x6, %edx
movl $0xf7d5d, %ecx          # imm = 0xF7D5D
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291fe(%rip), %rsi     # 0x372d7
movl $0x6, %edx
movl $0x15fad3, %ecx         # imm = 0x15FAD3
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291fd(%rip), %rsi     # 0x372fb
movl $0x6, %edx
movl $0x15fad3, %ecx         # imm = 0x15FAD3
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291fc(%rip), %rsi     # 0x3731f
movl $0x6, %edx
movl $0xa1650, %ecx          # imm = 0xA1650
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291f6(%rip), %rsi     # 0x3733e
movl $0x6, %edx
movl $0xa1650, %ecx          # imm = 0xA1650
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291f0(%rip), %rsi     # 0x3735d
movl $0x6, %edx
movl $0xc437f, %ecx          # imm = 0xC437F
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291ea(%rip), %rsi     # 0x3737c
movl $0x6, %edx
movl $0xc437f, %ecx          # imm = 0xC437F
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291e4(%rip), %rsi     # 0x3739b
movl $0x4, %edx
movl $0x13715e, %ecx         # imm = 0x13715E
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291e9(%rip), %rsi     # 0x373c5
movl $0x4, %edx
movl $0x13715e, %ecx         # imm = 0x13715E
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291ee(%rip), %rsi     # 0x373ef
movl $0x4, %edx
movl $0x1a409c, %ecx         # imm = 0x1A409C
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291f2(%rip), %rsi     # 0x37418
movl $0x4, %edx
movl $0x1a409c, %ecx         # imm = 0x1A409C
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291f6(%rip), %rsi     # 0x37441
movl $0x6, %edx
movl $0x3a4dc9, %ecx         # imm = 0x3A4DC9
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291f3(%rip), %rsi     # 0x37463
movl $0x6, %edx
movl $0x3a4dc9, %ecx         # imm = 0x3A4DC9
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291f0(%rip), %rsi     # 0x37485
movl $0x5, %edx
movl $0xf5472, %ecx          # imm = 0xF5472
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291ef(%rip), %rsi     # 0x374a9
movl $0x5, %edx
movl $0xf5472, %ecx          # imm = 0xF5472
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291ee(%rip), %rsi     # 0x374cd
movl $0x6, %edx
movl $0x350fe, %ecx          # imm = 0x350FE
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291e8(%rip), %rsi     # 0x374ec
movl $0x6, %edx
movl $0x350fe, %ecx          # imm = 0x350FE
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291e2(%rip), %rsi     # 0x3750b
movl $0x6, %edx
movl $0x16a0b, %ecx          # imm = 0x16A0B
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291db(%rip), %rsi     # 0x37529
movl $0x6, %edx
movl $0x16a0b, %ecx          # imm = 0x16A0B
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291d4(%rip), %rsi     # 0x37547
movl $0x6, %edx
movl $0x8a9, %ecx            # imm = 0x8A9
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291cd(%rip), %rsi     # 0x37565
movl $0x6, %edx
movl $0x8a9, %ecx            # imm = 0x8A9
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291c6(%rip), %rsi     # 0x37583
movl $0x7, %edx
movl $0x8a920, %ecx          # imm = 0x8A920
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291c0(%rip), %rsi     # 0x375a2
movl $0x7, %edx
movl $0x8a920, %ecx          # imm = 0x8A920
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291ba(%rip), %rsi     # 0x375c1
movl $0x4, %edx
movl $0x5be7, %ecx           # imm = 0x5BE7
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
leaq -0x1d8(%rbp), %rdi
leaq 0x291b7(%rip), %rsi     # 0x375e3
movl $0x4, %edx
movl $0x5be7, %ecx           # imm = 0x5BE7
callq 0xde80
addq -0x10(%rbp), %rax
movq %rax, -0x10(%rbp)
callq 0x14080
subl -0x4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1dc(%rbp)
imulq $0x3e8, -0x10(%rbp), %rax # imm = 0x3E8
movslq -0x1dc(%rbp), %rcx
xorl %edx, %edx
divq %rcx
movq %rax, %rsi
leaq 0x29193(%rip), %rdi     # 0x37605
movb $0x0, %al
callq 0x8c60
leaq 0x2919a(%rip), %rdi     # 0x3761a
movb $0x0, %al
callq 0x8c60
addq $0x1e0, %rsp            # imm = 0x1E0
popq %rbp
retq