// File: /workspace/github_cpp_makefile_star2_O1/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 0x18868
movq %rax, %rbx
xorl %edx, %edx
leaq 0xe000f(%rip), %rcx     # 0xf8598
movq %rcx, %rsi
xorl %r9d, %r9d
movq %rsi, %rdi
xorl %r8d, %r8d
movl %r9d, %eax
movl $0x400, %r9d            # imm = 0x400
movq (%rdi,%r9), %r10
movl %eax, %r11d
incl %eax
movq %r10, 0x110(%rsp,%r11,8)
addq $0x400, %r9             # imm = 0x400
cmpq $0x1c00, %r9            # imm = 0x1C00
jne 0x1859e
incq %r8
addq $0x8, %rdi
cmpq $0x40, %r8
jne 0x18598
movq 0x1c00(%rcx,%rdx,8), %rdi
leal 0x1(%rax), %r9d
movl %eax, %r8d
movq %rdi, 0x110(%rsp,%r8,8)
leaq 0x1(%rdx), %rdi
addq $0x200, %rsi            # imm = 0x200
testq %rdx, %rdx
movq %rdi, %rdx
je 0x1858f
incl %eax
xorl %edx, %edx
leaq 0xdff97(%rip), %rcx     # 0xf8598
movq 0x1c10(%rcx,%rdx), %rsi
movl %eax, %edi
incl %eax
movq %rsi, 0x110(%rsp,%rdi,8)
addq $0x8, %rdx
cmpq $0x80, %rdx
jne 0x18601
xorl %edx, %edx
movq 0x1c90(%rcx,%rdx,8), %rsi
movl %eax, %edi
incl %eax
movq %rsi, 0x110(%rsp,%rdi,8)
incq %rdx
cmpq $0x41, %rdx
jne 0x18624
cmpl $0x353, %eax            # imm = 0x353
jne 0x18880
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 0x1851c
cmpq %r13, %r15
setne %cl
testl %eax, %eax
sete %dl
orb %cl, %dl
je 0x1880b
movl %eax, (%r12,%r13,4)
incq %r13
cmpq $0x353, %r13            # imm = 0x353
jne 0x1865d
incq %r15
addq $0xd4c, %r12            # imm = 0xD4C
cmpq $0x353, %r15            # imm = 0x353
jne 0x18652
xorl %eax, %eax
movq %rbx, %rcx
movq %rbx, %rdx
movq %rcx, %rsi
xorl %edi, %edi
movl (%rdx,%rdi,4), %r8d
cmpl (%rsi), %r8d
jne 0x1882a
incq %rdi
addq $0xd4c, %rsi            # imm = 0xD4C
cmpq $0x353, %rdi            # imm = 0x353
jne 0x186b0
incq %rax
addq $0xd4c, %rdx            # imm = 0xD4C
addq $0x4, %rcx
cmpq $0x353, %rax            # imm = 0x353
jne 0x186ab
xorl %eax, %eax
movq %rbx, %rcx
xorl %edx, %edx
cmpq $0x351, %rax            # imm = 0x351
ja 0x1871b
movl $0x1, %esi
movl (%rcx,%rsi,4), %edi
cmpl $0x41, %edi
jae 0x18849
addl %edi, %edx
leaq (%rax,%rsi), %rdi
incq %rdi
incq %rsi
cmpq $0x353, %rdi            # imm = 0x353
jne 0x186fa
incq %rax
addq $0xd50, %rcx            # imm = 0xD50
cmpq $0x353, %rax            # imm = 0x353
jne 0x186ed
movl %edx, %eax
cvtsi2sd %rax, %xmm1
divsd 0x19c4c(%rip), %xmm1    # 0x32388
ucomisd 0x19c4c(%rip), %xmm1    # 0x32390
jb 0x1889f
movsd 0x19c46(%rip), %xmm0    # 0x32398
ucomisd %xmm1, %xmm0
jb 0x1889f
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 0x187ca
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 0x18791
incq %r14
addq $0xd50, %rax            # imm = 0xD50
cmpq $0x353, %r14            # imm = 0x353
jne 0x18783
divsd 0x19ba4(%rip), %xmm0    # 0x32388
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jae 0x187f3
callq 0x20f0
movq %rbx, %rdi
addq $0x1bb0, %rsp           # imm = 0x1BB0
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x21e0
leaq 0x19c19(%rip), %rdi     # 0x3242b
leaq 0x19b9f(%rip), %rsi     # 0x323b8
leaq 0x19bf9(%rip), %rcx     # 0x32419
movl $0x57, %edx
callq 0x20d0
leaq 0x19c00(%rip), %rdi     # 0x32431
leaq 0x19b80(%rip), %rsi     # 0x323b8
leaq 0x19bda(%rip), %rcx     # 0x32419
movl $0x5f, %edx
callq 0x20d0
leaq 0x19c06(%rip), %rdi     # 0x32456
leaq 0x19b61(%rip), %rsi     # 0x323b8
leaq 0x19bbb(%rip), %rcx     # 0x32419
movl $0x68, %edx
callq 0x20d0
leaq 0x19b85(%rip), %rdi     # 0x323f4
xorl %eax, %eax
callq 0x2330
movl $0x1, %edi
callq 0x21f0
leaq 0x19b8b(%rip), %rdi     # 0x32412
leaq 0x19b2a(%rip), %rsi     # 0x323b8
leaq 0x19b84(%rip), %rcx     # 0x32419
movl $0x4f, %edx
callq 0x20d0
leaq 0x19be2(%rip), %rdi     # 0x32488
leaq 0x19b0b(%rip), %rsi     # 0x323b8
leaq 0x19b65(%rip), %rcx     # 0x32419
movl $0x73, %edx
callq 0x20d0