// File: /workspace/github_cpp_makefile_star2_O2/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 $0x1ba0, %rsp           # imm = 0x1BA0
movl $0x2c33a4, %edi         # imm = 0x2C33A4
callq 0x2220
testq %rax, %rax
je 0x171d5
movq %rax, %rbx
xorl %ecx, %ecx
leaq 0xe46a3(%rip), %rdx     # 0xfb598
movq %rdx, %rsi
xorl %eax, %eax
cmpq $0x2, %rcx
je 0x16f5f
movq %rsi, %rdi
xorl %r8d, %r8d
cmpq $0x40, %r8
je 0x16f3e
movl $0x400, %r9d            # imm = 0x400
cmpq $0x1c00, %r9            # imm = 0x1C00
je 0x16f35
movq (%rdi,%r9), %r10
movl %eax, %r11d
incl %eax
movq %r10, 0x100(%rsp,%r11,8)
addq $0x400, %r9             # imm = 0x400
jmp 0x16f12
incq %r8
addq $0x8, %rdi
jmp 0x16f06
movq 0x1c00(%rdx,%rcx,8), %rdi
movl %eax, %r8d
incl %eax
movq %rdi, 0x100(%rsp,%r8,8)
incq %rcx
addq $0x200, %rsi            # imm = 0x200
jmp 0x16efa
movl %eax, %esi
xorl %edx, %edx
leaq 0xe462e(%rip), %rcx     # 0xfb598
cmpq $0x10, %rdx
je 0x16f8b
leaq (%rsi,%rdx), %rdi
movq 0x1c10(%rcx,%rdx,8), %r8
movl %edi, %edi
movq %r8, 0x100(%rsp,%rdi,8)
incq %rdx
jmp 0x16f6a
addl %edx, %eax
movq $-0x208, %rdx           # imm = 0xFDF8
testq %rdx, %rdx
je 0x16fb3
movq 0x1e98(%rcx,%rdx), %rsi
movl %eax, %edi
incl %eax
movq %rsi, 0x100(%rsp,%rdi,8)
addq $0x8, %rdx
jmp 0x16f94
cmpl $0x353, %eax            # imm = 0x353
jne 0x171eb
xorl %r15d, %r15d
movq %rbx, %r12
cmpq $0x353, %r15            # imm = 0x353
je 0x17019
movq 0x100(%rsp,%r15,8), %r14
xorl %r13d, %r13d
cmpq $0x353, %r13            # imm = 0x353
je 0x1700d
movq 0x100(%rsp,%r13,8), %rsi
movq %r14, %rdi
callq 0x16d1c
cmpq %r13, %r15
setne %cl
testl %eax, %eax
sete %dl
orb %cl, %dl
je 0x17186
movl %eax, (%r12,%r13,4)
incq %r13
jmp 0x16fd8
incq %r15
addq $0xd4c, %r12            # imm = 0xD4C
jmp 0x16fc4
xorl %eax, %eax
movq %rbx, %rcx
movq %rbx, %rdx
cmpq $0x353, %rax            # imm = 0x353
je 0x17062
movq %rcx, %rsi
xorl %edi, %edi
cmpq $0x353, %rdi            # imm = 0x353
je 0x17052
movl (%rdx,%rdi,4), %r8d
incq %rdi
leaq 0xd4c(%rsi), %r9
cmpl (%rsi), %r8d
movq %r9, %rsi
je 0x1702e
jmp 0x1719f
incq %rax
addq $0xd4c, %rdx            # imm = 0xD4C
addq $0x4, %rcx
jmp 0x17021
movq %rbx, %rax
addq $0x4, %rax
xorl %esi, %esi
xorl %ecx, %ecx
xorl %edx, %edx
cmpq $0x353, %rsi            # imm = 0x353
je 0x170b0
leaq 0x1(%rsi), %rdi
xorl %r8d, %r8d
leaq (%rsi,%r8), %r9
cmpq $0x352, %r9             # imm = 0x352
je 0x170a2
movl (%rax,%r8,4), %r9d
cmpl $0x41, %r9d
jae 0x171b8
addl %r9d, %ecx
incq %r8
jmp 0x1707f
addq $0xd50, %rax            # imm = 0xD50
addl %r8d, %edx
movq %rdi, %rsi
jmp 0x1706f
cmpl $0x584cb, %edx          # imm = 0x584CB
jne 0x17204
movl %ecx, %eax
cvtsi2sd %rax, %xmm1
divsd 0x192ed(%rip), %xmm1    # 0x303b8
ucomisd 0x192ed(%rip), %xmm1    # 0x303c0
jb 0x1721d
movsd 0x192e7(%rip), %xmm0    # 0x303c8
ucomisd %xmm1, %xmm0
jb 0x1721d
xorl %eax, %eax
cmpq $0x40, %rax
je 0x170fc
andl $0x0, (%rsp,%rax,4)
incq %rax
jmp 0x170ed
xorpd %xmm0, %xmm0
xorl %eax, %eax
pushq $0x1
popq %rcx
movq %rbx, %rdx
cmpq $0x353, %rax            # imm = 0x353
je 0x17157
movq %rcx, %rsi
leaq (%rax,%rsi), %rdi
cmpq $0x353, %rdi            # imm = 0x353
je 0x1714b
movl (%rdx,%rsi,4), %edi
cvtsi2sd %rdi, %xmm2
subsd %xmm1, %xmm2
cvttsd2si %xmm2, %edi
mulsd %xmm2, %xmm2
addsd %xmm2, %xmm0
movl %edi, %r8d
negl %r8d
cmovsl %edi, %r8d
incl (%rsp,%r8,4)
incq %rsi
jmp 0x17113
incq %rax
addq $0xd50, %rdx            # imm = 0xD50
jmp 0x17108
divsd 0x19259(%rip), %xmm0    # 0x303b8
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jae 0x1716e
callq 0x20e0
movq %rbx, %rdi
addq $0x1ba0, %rsp           # imm = 0x1BA0
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
jmp 0x21e0
leaq 0x193cb(%rip), %rdi     # 0x30558
leaq 0x19254(%rip), %rsi     # 0x303e8
leaq 0x193ab(%rip), %rcx     # 0x30546
pushq $0x57
jmp 0x171cf
leaq 0x193b8(%rip), %rdi     # 0x3055e
leaq 0x1923b(%rip), %rsi     # 0x303e8
leaq 0x19392(%rip), %rcx     # 0x30546
pushq $0x5f
jmp 0x171cf
leaq 0x193c4(%rip), %rdi     # 0x30583
leaq 0x19222(%rip), %rsi     # 0x303e8
leaq 0x19379(%rip), %rcx     # 0x30546
pushq $0x68
popq %rdx
callq 0x20c0
leaq 0x19345(%rip), %rdi     # 0x30521
xorl %eax, %eax
callq 0x622a
pushq $0x1
popq %rdi
callq 0x21f0
leaq 0x1934d(%rip), %rdi     # 0x3053f
leaq 0x191ef(%rip), %rsi     # 0x303e8
leaq 0x19346(%rip), %rcx     # 0x30546
pushq $0x4f
jmp 0x171cf
leaq 0x193aa(%rip), %rdi     # 0x305b5
leaq 0x191d6(%rip), %rsi     # 0x303e8
leaq 0x1932d(%rip), %rcx     # 0x30546
pushq $0x6e
jmp 0x171cf
leaq 0x193a7(%rip), %rdi     # 0x305cb
leaq 0x191bd(%rip), %rsi     # 0x303e8
leaq 0x19314(%rip), %rcx     # 0x30546
pushq $0x73
jmp 0x171cf