// File: /workspace/github_cpp_makefile_star2_O3/Quinny[P]IteratedPrisoners/./ipd/genetic.h
// Function: ipd::genetic::evolve(int, int, int, std::function<std::vector<std::pair<ipd::prisoner_t, int>, std::allocator<std::pair<ipd::prisoner_t, int>>> (std::vector<ipd::prisoner_t, std::allocator<ipd::prisoner_t>> const&)>)
prisoner_t evolve(int pop_size, int mutation_rate, int generations,
        fitness_fn fitness_func) {
    auto population = initial_population(
            pop_size, ipd::config::mem_first, ipd::config::mem_last);
    auto mutate     = std::bind(mutate_strategy, _1, mutation_rate);

    for (int i = 0; i < generations; ++i) {
        // fitness
        auto evaluation = fitness_func(std::cref(population));

        // selection weighted on fitness
        auto selection = weighted_random_sample(evaluation, pop_size);

        // cross over
        std::vector<std::string> genomes;
        for (auto i = 0UL; i < selection.size() - 1; ++i) {
            auto p = cross(selection[i].name, selection[i + 1].name);
            genomes.push_back(p.first); genomes.push_back(p.second);
        }

        // mutate
        std::transform(genomes.begin(), genomes.end(), genomes.begin(), mutate);

        // build next population
        population.clear();
        for (auto i: genomes)
            population.push_back(make_prisoner_t(genetic_strategy(i)));
    }

    // final eval uses overall performance
    auto evaluation = evaluate_async(std::cref(population));
    std::sort(evaluation.begin(), evaluation.end(), std::greater<score_t>());
    return evaluation.front().first;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
movq %r8, -0xf8(%rbp)
movl %ecx, %ebx
movl %edx, -0x30(%rbp)
movq %rdi, -0x40(%rbp)
movl %esi, -0x34(%rbp)
movslq %esi, %rsi
movslq 0xe7f8(%rip), %rdx      # 0x1535c
movslq 0xe7f5(%rip), %rcx      # 0x15360
leaq -0x78(%rbp), %rdi
callq 0x638f
movl %ebx, -0x2c(%rbp)
testl %ebx, %ebx
jle 0x6e03
xorl %eax, %eax
leaq -0x130(%rbp), %r15
leaq -0x60(%rbp), %r13
leaq -0xf0(%rbp), %r12
leaq -0x168(%rbp), %rbx
movq %rax, -0x100(%rbp)
movq -0xf8(%rbp), %rsi
cmpq $0x0, 0x10(%rsi)
je 0x6ec5
movq %r15, %rdi
leaq -0x78(%rbp), %rdx
callq *0x18(%rsi)
leaq -0xd0(%rbp), %rdi
movq %r15, %rsi
movl -0x34(%rbp), %edx
callq 0x8c81
xorps %xmm0, %xmm0
movaps %xmm0, -0x60(%rbp)
movq $0x0, -0x50(%rbp)
movq -0xd0(%rbp), %rdx
movq -0xc8(%rbp), %rax
subq %rdx, %rax
cmpq $0x40, %rax
jne 0x6bfe
xorl %esi, %esi
xorl %edi, %edi
jmp 0x6ca2
movl $0x40, %r15d
xorl %r12d, %r12d
leaq (%rdx,%r15), %rsi
addq $-0x40, %rsi
addq %r15, %rdx
leaq -0xb8(%rbp), %r14
movq %r14, %rdi
callq 0x6a10
movq %r13, %rdi
movq %r14, %rsi
callq 0x8ec4
movq %r13, %rdi
leaq -0x98(%rbp), %rsi
callq 0x8ec4
movq -0x98(%rbp), %rdi
leaq -0x88(%rbp), %rax
cmpq %rax, %rdi
je 0x6c53
callq 0x4350
movq -0xb8(%rbp), %rdi
leaq -0xa8(%rbp), %rax
cmpq %rax, %rdi
je 0x6c6b
callq 0x4350
incq %r12
movq -0xd0(%rbp), %rdx
movq -0xc8(%rbp), %rax
subq %rdx, %rax
sarq $0x6, %rax
decq %rax
addq $0x40, %r15
cmpq %rax, %r12
jb 0x6c07
movq -0x60(%rbp), %rdi
movq -0x58(%rbp), %rsi
leaq -0xf0(%rbp), %r12
leaq -0x348(%rip), %rax      # 0x6961
movq %rax, -0x118(%rbp)
movl -0x30(%rbp), %eax
movl %eax, -0x110(%rbp)
movq %rdi, %rdx
leaq -0x118(%rbp), %rcx
callq 0x8f45
movq -0x78(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0xd758
movq -0x60(%rbp), %r15
movq -0x58(%rbp), %rax
movq %rax, -0x108(%rbp)
cmpq %rax, %r15
je 0x6dce
leaq -0xe0(%rbp), %rax
movq %rax, -0xf0(%rbp)
movq (%r15), %rsi
movq 0x8(%r15), %rdx
addq %rsi, %rdx
movq %r12, %rdi
callq 0x9ba6
movq %rbx, %rdi
movq %r12, %rsi
callq 0x8fc2
leaq -0xb8(%rbp), %r14
movq %r14, %rdi
movq %rbx, %rsi
callq 0x6104
leaq -0x78(%rbp), %rdi
movq %r14, %rsi
callq 0x9282
movq -0x88(%rbp), %rax
testq %rax, %rax
je 0x6d53
leaq -0x98(%rbp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq %r13, %r12
leaq -0xe0(%rbp), %r13
movq -0xb8(%rbp), %rdi
leaq -0xa8(%rbp), %rax
cmpq %rax, %rdi
je 0x6d75
callq 0x4350
movq -0x150(%rbp), %rdi
testq %rdi, %rdi
je 0x6d86
callq 0x4350
movq -0x168(%rbp), %rdi
cmpq %rbx, %rdi
je 0x6da2
movq (%rdi), %r14
callq 0x4350
movq %r14, %rdi
cmpq %rbx, %r14
jne 0x6d92
movq -0xf0(%rbp), %rdi
cmpq %r13, %rdi
je 0x6db3
callq 0x4350
addq $0x20, %r15
cmpq -0x108(%rbp), %r15
movq %r12, %r13
leaq -0xf0(%rbp), %r12
jne 0x6ced
movq %r13, %rdi
callq 0x90a0
leaq -0xd0(%rbp), %rdi
callq 0x8472
leaq -0x130(%rbp), %r15
movq %r15, %rdi
callq 0x83fc
movq -0x100(%rbp), %rax
incl %eax
cmpl -0x2c(%rbp), %eax
jne 0x6b9a
leaq -0xb8(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x64b9
movq -0xb8(%rbp), %rbx
movq -0xb0(%rbp), %r14
cmpq %r14, %rbx
je 0x6e6e
movq %r14, %rax
subq %rbx, %rax
sarq $0x3, %rax
movabsq $-0x71c71c71c71c71c7, %rcx # imm = 0x8E38E38E38E38E39
imulq %rax, %rcx
bsrq %rcx, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x9f3a
movq -0x40(%rbp), %r15
movq %rbx, %rdi
movq %r14, %rsi
callq 0xa018
movq -0xb8(%rbp), %rbx
jmp 0x6e72
movq -0x40(%rbp), %r15
leaq 0x10(%r15), %r14
movq %r14, (%r15)
movq (%rbx), %rsi
movq 0x8(%rbx), %rdx
addq %rsi, %rdx
movq %r15, %rdi
callq 0x9ba6
leaq 0x20(%r15), %rdi
addq $0x20, %rbx
movq %rbx, %rsi
callq 0x92c8
leaq -0xb8(%rbp), %rdi
callq 0x83fc
leaq -0x78(%rbp), %rdi
callq 0x8472
movq %r15, %rax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
callq 0x4120
movq %rax, %rbx
movq (%r15), %rdi
cmpq %r14, %rdi
je 0x6ee1
callq 0x4350
jmp 0x6ee1
jmp 0x6ef6
movq %rax, %rbx
leaq -0xb8(%rbp), %rdi
jmp 0x6f74
jmp 0x6f44
jmp 0x6ef6
movq %rax, %rbx
jmp 0x6f6d
movq %rax, %rbx
jmp 0x6f79
movq %rax, %rdi
callq 0x92ba
jmp 0x6f44
movq %rax, %rbx
jmp 0x6f2a
movq %rax, %rbx
jmp 0x6f1e
movq %rax, %rbx
leaq -0xb8(%rbp), %rdi
callq 0x83ba
leaq -0x168(%rbp), %rdi
callq 0x89a8
movq -0xf0(%rbp), %rdi
leaq -0xe0(%rbp), %rax
cmpq %rax, %rdi
je 0x6f58
callq 0x4350
jmp 0x6f58
movq %rax, %rbx
jmp 0x6f58
movq %rax, %rbx
leaq -0xb8(%rbp), %rdi
callq 0x8f10
leaq -0x60(%rbp), %rdi
callq 0x90a0
leaq -0xd0(%rbp), %rdi
callq 0x8472
leaq -0x130(%rbp), %rdi
callq 0x83fc
leaq -0x78(%rbp), %rdi
callq 0x8472
movq %rbx, %rdi
callq 0x4520