// File: jswaff[P]prophet3/test/init__test.cpp
// Function: test_zkeys()
void test_zkeys() {

    uint64 keys[851];
    //uint32 hdistances[851][851];

    // putting a large array on the stack was causing a stack overflow
    // using malloc puts it on the heap
    uint32* hdistances = (uint32*)malloc(851*851*sizeof(uint32));
    if (!hdistances) {
        error("could not malloc hdistances!\n");
        exit(1);
    }

    uint32 n = 0;

    uint32 i,j,k;
    for (i=0;i<2;i++) { // color
        for (j=0;j<64;j++) { // squares
            for (k=1;k<=6;k++) {
                keys[n++] = zkeys.pieces[k][i][j];
            }
        }
        keys[n++] = zkeys.ptm[i];
    }

    for (i=0;i<16;i++) { // castling rights
        keys[n++] = zkeys.casting_rights[i];
    }

    for (i=0;i<65;i++) { // ep square
        keys[n++] = zkeys.ep[i];
    }

    assert(n==851);

    // measure the distance between each combination of keys
    // note distance[X][X] == 0 and distance[X][Y] == distance[Y][X]
    for (i=0;i<n;i++) {
        for (j=0;j<n;j++) {
            uint32 hd = hamming_distance(keys[i],keys[j]);
            assert(hd >= 0 && hd <= 64);
            if (i==j) assert(hd==0);
            hdistances[i*n+j] = hd;
        }
    }

    for (i=0;i<n;i++) {
        for (j=0;j<n;j++) {
            assert(i >= 0 && i < n && j >= 0 && j < n);
            assert(hdistances[i*n+j]==hdistances[j*n+i]);
        }
    }

    // create an array of the distances for each combination
    uint32 total_distance = 0;
    uint32 num_distances = 0;
    for (i=0;i<n;i++) {
        for (j=i+1;j<n;j++) {
            assert(hdistances[i*n+j] >= 0 && hdistances[i*n+j] <= 64);
            total_distance += hdistances[i*n+j];
            num_distances++;
        }
    }

    assert(num_distances==361675);
    double mean_distance = (double)total_distance / num_distances;
    //print("mean: %f\n",mean_distance);
    // we would expect, on average, half of the bits to be different from
    // on key to the next.
    assert(mean_distance >= 31 && mean_distance <= 33);

    // get standard deviation
    double sum_dev = 0;
    double min_dev=999.9,max_dev=0.0;
    int dev_cnts[64];
    for (i=0;i<64;i++) dev_cnts[i] = 0;
    for (i=0;i<n;i++) {
        for (j=i+1;j<n;j++) {
            double delta = (double)hdistances[i*n+j] - mean_distance;
            sum_dev += delta * delta;

            if (abs(delta) < min_dev) min_dev = abs(delta);
            if (abs(delta) > max_dev) max_dev = abs(delta);
            dev_cnts[(int)abs(delta)]++;
        }
    }
    double std_dev = sqrt(sum_dev/num_distances);
    /*print("stddev: %f\n",std_dev);
    print("mindev: %f\n",min_dev);
    print("maxdev: %f\n",max_dev);
    for (i=0;i<64;i++) {
        if (dev_cnts[i]>0) {
            print("dev: %d ==> %d\n",i,dev_cnts[i]);
        }
    }*/

    free(hdistances);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1c10, %rsp           # imm = 0x1C10
movl $0x2c33a4, %edi         # imm = 0x2C33A4
callq 0x2220
movq %rax, -0x1aa8(%rbp)
cmpq $0x0, -0x1aa8(%rbp)
jne 0x2172e
leaq 0x1d5ac(%rip), %rdi     # 0x3ecc9
movb $0x0, %al
callq 0x8f00
movl $0x1, %edi
callq 0x21f0
movl $0x0, -0x1aac(%rbp)
movl $0x0, -0x1ab0(%rbp)
cmpl $0x2, -0x1ab0(%rbp)
jae 0x2182e
movl $0x0, -0x1ab4(%rbp)
cmpl $0x40, -0x1ab4(%rbp)
jae 0x217e8
movl $0x1, -0x1ab8(%rbp)
cmpl $0x6, -0x1ab8(%rbp)
ja 0x217d2
movl -0x1ab8(%rbp), %eax
movl %eax, %ecx
leaq 0xe1fd0(%rip), %rax     # 0x103758
shlq $0xa, %rcx
addq %rcx, %rax
movl -0x1ab0(%rbp), %ecx
shlq $0x9, %rcx
addq %rcx, %rax
movl -0x1ab4(%rbp), %ecx
movq (%rax,%rcx,8), %rcx
movl -0x1aac(%rbp), %eax
movl %eax, %edx
addl $0x1, %edx
movl %edx, -0x1aac(%rbp)
movl %eax, %eax
movq %rcx, -0x1aa0(%rbp,%rax,8)
movl -0x1ab8(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab8(%rbp)
jmp 0x21770
jmp 0x217d4
movl -0x1ab4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
jmp 0x21759
movl -0x1ab0(%rbp), %eax
movl %eax, %ecx
leaq 0xe1f61(%rip), %rax     # 0x103758
movq 0x1c00(%rax,%rcx,8), %rcx
movl -0x1aac(%rbp), %eax
movl %eax, %edx
addl $0x1, %edx
movl %edx, -0x1aac(%rbp)
movl %eax, %eax
movq %rcx, -0x1aa0(%rbp,%rax,8)
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21742
movl $0x0, -0x1ab0(%rbp)
cmpl $0x10, -0x1ab0(%rbp)
jae 0x21884
movl -0x1ab0(%rbp), %eax
movl %eax, %ecx
leaq 0xe1f08(%rip), %rax     # 0x103758
movq 0x1c10(%rax,%rcx,8), %rcx
movl -0x1aac(%rbp), %eax
movl %eax, %edx
addl $0x1, %edx
movl %edx, -0x1aac(%rbp)
movl %eax, %eax
movq %rcx, -0x1aa0(%rbp,%rax,8)
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21838
movl $0x0, -0x1ab0(%rbp)
cmpl $0x41, -0x1ab0(%rbp)
jae 0x218da
movl -0x1ab0(%rbp), %eax
movl %eax, %ecx
leaq 0xe1eb2(%rip), %rax     # 0x103758
movq 0x1c90(%rax,%rcx,8), %rcx
movl -0x1aac(%rbp), %eax
movl %eax, %edx
addl $0x1, %edx
movl %edx, -0x1aac(%rbp)
movl %eax, %eax
movq %rcx, -0x1aa0(%rbp,%rax,8)
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x2188e
cmpl $0x353, -0x1aac(%rbp)   # imm = 0x353
jne 0x218e8
jmp 0x21907
leaq 0x1d3f8(%rip), %rdi     # 0x3ece7
leaq 0x1d29a(%rip), %rsi     # 0x3eb90
movl $0x4f, %edx
leaq 0x1d3ec(%rip), %rcx     # 0x3ecee
callq 0x20c0
movl $0x0, -0x1ab0(%rbp)
movl -0x1ab0(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21a3d
movl $0x0, -0x1ab4(%rbp)
movl -0x1ab4(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21a27
movl -0x1ab0(%rbp), %eax
movq -0x1aa0(%rbp,%rax,8), %rdi
movl -0x1ab4(%rbp), %eax
movq -0x1aa0(%rbp,%rax,8), %rsi
callq 0x214a0
movl %eax, -0x1abc(%rbp)
xorl %eax, %eax
cmpl $0x0, -0x1abc(%rbp)
movb %al, -0x1c01(%rbp)
jb 0x21987
cmpl $0x40, -0x1abc(%rbp)
setbe %al
movb %al, -0x1c01(%rbp)
movb -0x1c01(%rbp), %al
testb $0x1, %al
jne 0x21993
jmp 0x21995
jmp 0x219b4
leaq 0x1d364(%rip), %rdi     # 0x3ed00
leaq 0x1d1ed(%rip), %rsi     # 0x3eb90
movl $0x56, %edx
leaq 0x1d33f(%rip), %rcx     # 0x3ecee
callq 0x20c0
movl -0x1ab0(%rbp), %eax
cmpl -0x1ab4(%rbp), %eax
jne 0x219ee
cmpl $0x0, -0x1abc(%rbp)
jne 0x219cd
jmp 0x219ec
leaq 0x1d340(%rip), %rdi     # 0x3ed14
leaq 0x1d1b5(%rip), %rsi     # 0x3eb90
movl $0x57, %edx
leaq 0x1d307(%rip), %rcx     # 0x3ecee
callq 0x20c0
jmp 0x219ee
movl -0x1abc(%rbp), %edx
movq -0x1aa8(%rbp), %rax
movl -0x1ab0(%rbp), %ecx
imull -0x1aac(%rbp), %ecx
addl -0x1ab4(%rbp), %ecx
movl %ecx, %ecx
movl %edx, (%rax,%rcx,4)
movl -0x1ab4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
jmp 0x2192d
jmp 0x21a29
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21911
movl $0x0, -0x1ab0(%rbp)
movl -0x1ab0(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21b7c
movl $0x0, -0x1ab4(%rbp)
movl -0x1ab4(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21b66
xorl %eax, %eax
cmpl $0x0, -0x1ab0(%rbp)
movb %al, -0x1c02(%rbp)
jb 0x21ac2
movl -0x1ab0(%rbp), %ecx
xorl %eax, %eax
cmpl -0x1aac(%rbp), %ecx
movb %al, -0x1c02(%rbp)
jae 0x21ac2
xorl %eax, %eax
cmpl $0x0, -0x1ab4(%rbp)
movb %al, -0x1c02(%rbp)
jb 0x21ac2
movl -0x1ab4(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
setb %al
movb %al, -0x1c02(%rbp)
movb -0x1c02(%rbp), %al
testb $0x1, %al
jne 0x21ace
jmp 0x21ad0
jmp 0x21aef
leaq 0x1d243(%rip), %rdi     # 0x3ed1a
leaq 0x1d0b2(%rip), %rsi     # 0x3eb90
movl $0x5e, %edx
leaq 0x1d204(%rip), %rcx     # 0x3ecee
callq 0x20c0
movq -0x1aa8(%rbp), %rax
movl -0x1ab0(%rbp), %ecx
imull -0x1aac(%rbp), %ecx
addl -0x1ab4(%rbp), %ecx
movl %ecx, %ecx
movl (%rax,%rcx,4), %eax
movq -0x1aa8(%rbp), %rcx
movl -0x1ab4(%rbp), %edx
imull -0x1aac(%rbp), %edx
addl -0x1ab0(%rbp), %edx
movl %edx, %edx
cmpl (%rcx,%rdx,4), %eax
jne 0x21b31
jmp 0x21b50
leaq 0x1d205(%rip), %rdi     # 0x3ed3d
leaq 0x1d051(%rip), %rsi     # 0x3eb90
movl $0x5f, %edx
leaq 0x1d1a3(%rip), %rcx     # 0x3ecee
callq 0x20c0
jmp 0x21b52
movl -0x1ab4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
jmp 0x21a63
jmp 0x21b68
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21a47
movl $0x0, -0x1ac0(%rbp)
movl $0x0, -0x1ac4(%rbp)
movl $0x0, -0x1ab0(%rbp)
movl -0x1ab0(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21cb3
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
movl -0x1ab4(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21c9d
movq -0x1aa8(%rbp), %rcx
movl -0x1ab0(%rbp), %eax
imull -0x1aac(%rbp), %eax
addl -0x1ab4(%rbp), %eax
movl %eax, %eax
movl %eax, %edx
xorl %eax, %eax
cmpl $0x0, (%rcx,%rdx,4)
movb %al, -0x1c03(%rbp)
jb 0x21c22
movq -0x1aa8(%rbp), %rax
movl -0x1ab0(%rbp), %ecx
imull -0x1aac(%rbp), %ecx
addl -0x1ab4(%rbp), %ecx
movl %ecx, %ecx
cmpl $0x40, (%rax,%rcx,4)
setbe %al
movb %al, -0x1c03(%rbp)
movb -0x1c03(%rbp), %al
testb $0x1, %al
jne 0x21c2e
jmp 0x21c30
jmp 0x21c4f
leaq 0x1d12b(%rip), %rdi     # 0x3ed62
leaq 0x1cf52(%rip), %rsi     # 0x3eb90
movl $0x68, %edx
leaq 0x1d0a4(%rip), %rcx     # 0x3ecee
callq 0x20c0
movq -0x1aa8(%rbp), %rax
movl -0x1ab0(%rbp), %ecx
imull -0x1aac(%rbp), %ecx
addl -0x1ab4(%rbp), %ecx
movl %ecx, %ecx
movl (%rax,%rcx,4), %eax
addl -0x1ac0(%rbp), %eax
movl %eax, -0x1ac0(%rbp)
movl -0x1ac4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ac4(%rbp)
movl -0x1ab4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
jmp 0x21bbb
jmp 0x21c9f
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21b9a
cmpl $0x584cb, -0x1ac4(%rbp) # imm = 0x584CB
jne 0x21cc1
jmp 0x21ce0
leaq 0x1d0cc(%rip), %rdi     # 0x3ed94
leaq 0x1cec1(%rip), %rsi     # 0x3eb90
movl $0x6e, %edx
leaq 0x1d013(%rip), %rcx     # 0x3ecee
callq 0x20c0
movl -0x1ac0(%rbp), %eax
cvtsi2sd %rax, %xmm0
movl -0x1ac4(%rbp), %eax
cvtsi2sd %rax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, -0x1ad0(%rbp)
movsd -0x1ad0(%rbp), %xmm0
xorl %eax, %eax
movsd 0x1ce4c(%rip), %xmm1    # 0x3eb60
ucomisd %xmm1, %xmm0
movb %al, -0x1c04(%rbp)
jb 0x21d39
movsd 0x1ce40(%rip), %xmm0    # 0x3eb68
ucomisd -0x1ad0(%rbp), %xmm0
setae %al
movb %al, -0x1c04(%rbp)
movb -0x1c04(%rbp), %al
testb $0x1, %al
jne 0x21d45
jmp 0x21d47
jmp 0x21d66
leaq 0x1d05c(%rip), %rdi     # 0x3edaa
leaq 0x1ce3b(%rip), %rsi     # 0x3eb90
movl $0x73, %edx
leaq 0x1cf8d(%rip), %rcx     # 0x3ecee
callq 0x20c0
xorps %xmm0, %xmm0
movsd %xmm0, -0x1ad8(%rbp)
movsd 0x1cdf7(%rip), %xmm0    # 0x3eb70
movsd %xmm0, -0x1ae0(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x1ae8(%rbp)
movl $0x0, -0x1ab0(%rbp)
cmpl $0x40, -0x1ab0(%rbp)
jae 0x21dc1
movl -0x1ab0(%rbp), %eax
movl $0x0, -0x1bf0(%rbp,%rax,4)
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21d96
movl $0x0, -0x1ab0(%rbp)
movl -0x1ab0(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21f1c
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
movl -0x1ab4(%rbp), %eax
cmpl -0x1aac(%rbp), %eax
jae 0x21f06
movq -0x1aa8(%rbp), %rax
movl -0x1ab0(%rbp), %ecx
movl -0x1aac(%rbp), %edx
imull %edx, %ecx
movl -0x1ab4(%rbp), %edx
addl %edx, %ecx
movl (%rax,%rcx,4), %eax
cvtsi2sd %rax, %xmm0
subsd -0x1ad0(%rbp), %xmm0
movsd %xmm0, -0x1bf8(%rbp)
movsd -0x1bf8(%rbp), %xmm0
movsd -0x1bf8(%rbp), %xmm2
movsd -0x1ad8(%rbp), %xmm1
mulsd %xmm2, %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, -0x1ad8(%rbp)
cvttsd2si -0x1bf8(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cvtsi2sd %eax, %xmm1
movsd -0x1ae0(%rbp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x21e98
cvttsd2si -0x1bf8(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cvtsi2sd %eax, %xmm0
movsd %xmm0, -0x1ae0(%rbp)
cvttsd2si -0x1bf8(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cvtsi2sd %eax, %xmm0
ucomisd -0x1ae8(%rbp), %xmm0
jbe 0x21ed0
cvttsd2si -0x1bf8(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cvtsi2sd %eax, %xmm0
movsd %xmm0, -0x1ae8(%rbp)
cvttsd2si -0x1bf8(%rbp), %eax
movl %eax, %ecx
negl %ecx
cmovnsl %ecx, %eax
cltq
movl -0x1bf0(%rbp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, -0x1bf0(%rbp,%rax,4)
movl -0x1ab4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab4(%rbp)
jmp 0x21dec
jmp 0x21f08
movl -0x1ab0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1ab0(%rbp)
jmp 0x21dcb
movsd -0x1ad8(%rbp), %xmm0
movl -0x1ac4(%rbp), %eax
cvtsi2sd %rax, %xmm1
divsd %xmm1, %xmm0
callq 0x20e0
movsd %xmm0, -0x1c00(%rbp)
movq -0x1aa8(%rbp), %rdi
callq 0x21e0
addq $0x1c10, %rsp           # imm = 0x1C10
popq %rbp
retq
nopw %cs:(%rax,%rax)