// File: /workspace/github_cpp_makefile_star2_O3/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 %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1bb0, %rsp           # imm = 0x1BB0
movl $0x2c33a4, %edi         # imm = 0x2C33A4
callq 0x2220
testq %rax, %rax
je 0x18713
movq %rax, %rbx
xorl %esi, %esi
movb $0x1, %dl
leaq 0xe015d(%rip), %rax     # 0xf8598
xorl %r9d, %r9d
movq %rsi, %rdi
shlq $0x9, %rdi
addq %rax, %rdi
xorl %r8d, %r8d
movl %r9d, %ecx
movl $0x400, %r9d            # imm = 0x400
movq (%rdi,%r9), %r10
movl %ecx, %r11d
incl %ecx
movq %r10, 0x110(%rsp,%r11,8)
addq $0x400, %r9             # imm = 0x400
cmpq $0x1c00, %r9            # imm = 0x1C00
jne 0x18454
incq %r8
addq $0x8, %rdi
cmpq $0x40, %r8
jne 0x1844e
movq 0x1c00(%rax,%rsi,8), %rsi
leal 0x1(%rcx), %r9d
movl %ecx, %edi
movq %rsi, 0x110(%rsp,%rdi,8)
movl $0x1, %esi
testb $0x1, %dl
movl $0x0, %edx
jne 0x1843e
incl %ecx
xorl %edx, %edx
movq 0x1c10(%rax,%rdx), %rsi
movl %ecx, %edi
incl %ecx
movq %rsi, 0x110(%rsp,%rdi,8)
addq $0x8, %rdx
cmpq $0x80, %rdx
jne 0x184ab
xorl %edx, %edx
movq 0x1c90(%rax,%rdx,8), %rsi
movl %ecx, %edi
incl %ecx
movq %rsi, 0x110(%rsp,%rdi,8)
incq %rdx
cmpq $0x41, %rdx
jne 0x184ce
cmpl $0x353, %ecx            # imm = 0x353
jne 0x1872b
xorl %r15d, %r15d
movq %rbx, %r12
movq 0x110(%rsp,%r15,8), %r14
xorl %r13d, %r13d
movq 0x110(%rsp,%r13,8), %rsi
movq %r14, %rdi
callq 0x183cc
cmpq %r13, %r15
setne %cl
testl %eax, %eax
sete %dl
orb %cl, %dl
je 0x186b6
movl %eax, (%r12,%r13,4)
incq %r13
cmpq $0x353, %r13            # imm = 0x353
jne 0x18508
incq %r15
addq $0xd4c, %r12            # imm = 0xD4C
cmpq $0x353, %r15            # imm = 0x353
jne 0x184fd
xorl %eax, %eax
movq %rbx, %rcx
movq %rbx, %rdx
movq %rcx, %rsi
xorl %edi, %edi
movl (%rdx,%rdi,4), %r8d
cmpl (%rsi), %r8d
jne 0x186d5
incq %rdi
addq $0xd4c, %rsi            # imm = 0xD4C
cmpq $0x353, %rdi            # imm = 0x353
jne 0x1855b
incq %rax
addq $0xd4c, %rdx            # imm = 0xD4C
addq $0x4, %rcx
cmpq $0x353, %rax            # imm = 0x353
jne 0x18556
xorl %eax, %eax
movq %rbx, %rcx
xorl %edx, %edx
cmpq $0x351, %rax            # imm = 0x351
ja 0x185c6
movl $0x1, %esi
movl (%rcx,%rsi,4), %edi
cmpl $0x41, %edi
jae 0x186f4
addl %edi, %edx
leaq (%rax,%rsi), %rdi
incq %rdi
incq %rsi
cmpq $0x353, %rdi            # imm = 0x353
jne 0x185a5
incq %rax
addq $0xd50, %rcx            # imm = 0xD50
cmpq $0x353, %rax            # imm = 0x353
jne 0x18598
movl %edx, %eax
cvtsi2sd %rax, %xmm1
divsd 0x19e21(%rip), %xmm1    # 0x32408
ucomisd 0x19e21(%rip), %xmm1    # 0x32410
jb 0x1874a
movsd 0x19e1b(%rip), %xmm0    # 0x32418
ucomisd %xmm1, %xmm0
jb 0x1874a
leaq 0x10(%rsp), %rdi
xorl %r14d, %r14d
movl $0x100, %edx            # imm = 0x100
xorl %esi, %esi
movsd %xmm1, 0x8(%rsp)
callq 0x20c0
movsd 0x8(%rsp), %xmm2
xorpd %xmm0, %xmm0
movq %rbx, %rax
cmpq $0x351, %r14            # imm = 0x351
ja 0x18675
movl $0x1, %ecx
movl (%rax,%rcx,4), %edx
xorps %xmm1, %xmm1
cvtsi2sd %rdx, %xmm1
subsd %xmm2, %xmm1
cvttsd2si %xmm1, %edx
movl %edx, %esi
negl %esi
cmovsl %edx, %esi
mulsd %xmm1, %xmm1
incl 0x10(%rsp,%rsi,4)
addsd %xmm1, %xmm0
leaq (%r14,%rcx), %rdx
incq %rdx
incq %rcx
cmpq $0x353, %rdx            # imm = 0x353
jne 0x1863c
incq %r14
addq $0xd50, %rax            # imm = 0xD50
cmpq $0x353, %r14            # imm = 0x353
jne 0x1862e
divsd 0x19d79(%rip), %xmm0    # 0x32408
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jae 0x1869e
callq 0x20f0
movq %rbx, %rdi
addq $0x1bb0, %rsp           # imm = 0x1BB0
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x21e0
leaq 0x19dee(%rip), %rdi     # 0x324ab
leaq 0x19d74(%rip), %rsi     # 0x32438
leaq 0x19dce(%rip), %rcx     # 0x32499
movl $0x57, %edx
callq 0x20d0
leaq 0x19dd5(%rip), %rdi     # 0x324b1
leaq 0x19d55(%rip), %rsi     # 0x32438
leaq 0x19daf(%rip), %rcx     # 0x32499
movl $0x5f, %edx
callq 0x20d0
leaq 0x19ddb(%rip), %rdi     # 0x324d6
leaq 0x19d36(%rip), %rsi     # 0x32438
leaq 0x19d90(%rip), %rcx     # 0x32499
movl $0x68, %edx
callq 0x20d0
leaq 0x19d5a(%rip), %rdi     # 0x32474
xorl %eax, %eax
callq 0x2330
movl $0x1, %edi
callq 0x21f0
leaq 0x19d60(%rip), %rdi     # 0x32492
leaq 0x19cff(%rip), %rsi     # 0x32438
leaq 0x19d59(%rip), %rcx     # 0x32499
movl $0x4f, %edx
callq 0x20d0
leaq 0x19db7(%rip), %rdi     # 0x32508
leaq 0x19ce0(%rip), %rsi     # 0x32438
leaq 0x19d3a(%rip), %rcx     # 0x32499
movl $0x73, %edx
callq 0x20d0