// File: 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
subq $0x260, %rsp            # imm = 0x260
movq %r8, -0x228(%rbp)
movq %rdi, -0x220(%rbp)
movq %rdi, %rax
movq %rax, -0x218(%rbp)
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movl %edx, -0x10(%rbp)
movl %ecx, -0x14(%rbp)
movq %r8, -0x20(%rbp)
movslq -0xc(%rbp), %rsi
movslq 0x2ae9d(%rip), %rdx     # 0x323ac
movslq 0x2ae9a(%rip), %rcx     # 0x323b0
leaq -0x38(%rbp), %rdi
callq 0x6930
leaq -0x346(%rip), %rsi      # 0x71e0
movq 0x2aa73(%rip), %rdx     # 0x31fa0
leaq -0x48(%rbp), %rdi
leaq -0x10(%rbp), %rcx
callq 0xaa20
jmp 0x753c
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x14(%rbp), %eax
jge 0x78d0
leaq -0x38(%rbp), %rdi
callq 0xaad0
movq %rax, -0x78(%rbp)
leaq -0x78(%rbp), %rdi
callq 0xab00
movq -0x228(%rbp), %rsi
movq %rax, %rdx
leaq -0x70(%rbp), %rdi
callq 0xaa70
jmp 0x757a
movl -0xc(%rbp), %edx
leaq -0x90(%rbp), %rdi
leaq -0x70(%rbp), %rsi
callq 0xab20
jmp 0x758f
leaq -0xa8(%rbp), %rdi
callq 0xaf00
movq $0x0, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
movq %rax, -0x230(%rbp)
leaq -0x90(%rbp), %rdi
callq 0xa4b0
movq %rax, %rcx
movq -0x230(%rbp), %rax
subq $0x1, %rcx
cmpq %rcx, %rax
jae 0x76c3
movq -0xb0(%rbp), %rsi
leaq -0x90(%rbp), %rdi
movq %rdi, -0x240(%rbp)
callq 0xaf20
movq -0x240(%rbp), %rdi
movq %rax, -0x238(%rbp)
movq -0xb0(%rbp), %rsi
incq %rsi
callq 0xaf20
movq -0x238(%rbp), %rsi
movq %rax, %rdx
leaq -0xf0(%rbp), %rdi
callq 0x72f0
jmp 0x7626
leaq -0xa8(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0xaf40
jmp 0x763b
leaq -0xd0(%rbp), %rsi
leaq -0xa8(%rbp), %rdi
callq 0xaf40
jmp 0x7650
leaq -0xf0(%rbp), %rdi
callq 0xafb0
movq -0xb0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xb0(%rbp)
jmp 0x75a6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x7999
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x78c2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x78aa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0xf0(%rbp), %rdi
callq 0xafb0
jmp 0x78aa
leaq -0xa8(%rbp), %rdi
movq %rdi, -0x250(%rbp)
callq 0xb070
movq -0x250(%rbp), %rdi
movq %rax, -0xf8(%rbp)
callq 0xb0a0
movq -0x250(%rbp), %rdi
movq %rax, -0x100(%rbp)
callq 0xb070
movq %rax, -0x108(%rbp)
movups -0x48(%rbp), %xmm0
movaps %xmm0, -0x120(%rbp)
movq -0xf8(%rbp), %rdi
movq -0x100(%rbp), %rsi
movq -0x108(%rbp), %rdx
leaq -0x120(%rbp), %rcx
callq 0xafe0
movq %rax, -0x248(%rbp)
jmp 0x7738
movq -0x248(%rbp), %rax
movq %rax, -0x128(%rbp)
leaq -0x38(%rbp), %rdi
callq 0xb0d0
leaq -0xa8(%rbp), %rax
movq %rax, -0x130(%rbp)
movq -0x130(%rbp), %rdi
callq 0xb070
movq %rax, -0x138(%rbp)
movq -0x130(%rbp), %rdi
callq 0xb0a0
movq %rax, -0x140(%rbp)
leaq -0x138(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0xb0f0
testb $0x1, %al
jne 0x779f
jmp 0x787b
leaq -0x138(%rbp), %rdi
callq 0xb130
movq %rax, %rsi
leaq -0x160(%rbp), %rdi
callq 0x4160
jmp 0x77bc
leaq -0x1d8(%rbp), %rdi
leaq -0x160(%rbp), %rsi
callq 0xb150
jmp 0x77d1
leaq -0x1a0(%rbp), %rdi
leaq -0x1d8(%rbp), %rsi
callq 0x6690
jmp 0x77e6
leaq -0x38(%rbp), %rdi
leaq -0x1a0(%rbp), %rsi
callq 0xa410
jmp 0x77f8
leaq -0x1a0(%rbp), %rdi
callq 0x9450
leaq -0x1d8(%rbp), %rdi
callq 0xa3c0
leaq -0x160(%rbp), %rdi
callq 0x4230
leaq -0x138(%rbp), %rdi
callq 0xb2b0
jmp 0x7783
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x786d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
jmp 0x7861
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x1a0(%rbp), %rdi
callq 0x9450
leaq -0x1d8(%rbp), %rdi
callq 0xa3c0
leaq -0x160(%rbp), %rdi
callq 0x4230
jmp 0x78aa
leaq -0xa8(%rbp), %rdi
callq 0xb2d0
leaq -0x90(%rbp), %rdi
callq 0x9890
leaq -0x70(%rbp), %rdi
callq 0x9520
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x7543
leaq -0xa8(%rbp), %rdi
callq 0xb2d0
leaq -0x90(%rbp), %rdi
callq 0x9890
leaq -0x70(%rbp), %rdi
callq 0x9520
jmp 0x7999
leaq -0x38(%rbp), %rdi
callq 0xaad0
movq %rax, -0x1f8(%rbp)
leaq -0x1f8(%rbp), %rdi
callq 0xab00
movq %rax, %rsi
leaq -0x1f0(%rbp), %rdi
callq 0x6a80
jmp 0x78fd
leaq -0x1f0(%rbp), %rdi
movq %rdi, -0x258(%rbp)
callq 0x94c0
movq -0x258(%rbp), %rdi
movq %rax, -0x200(%rbp)
callq 0x94f0
movq %rax, -0x208(%rbp)
movq -0x200(%rbp), %rdi
movq -0x208(%rbp), %rsi
callq 0x9480
jmp 0x793f
leaq -0x1f0(%rbp), %rdi
callq 0xb330
movq -0x220(%rbp), %rdi
movq %rax, %rsi
callq 0x9360
jmp 0x795c
leaq -0x1f0(%rbp), %rdi
callq 0x9520
leaq -0x38(%rbp), %rdi
callq 0x9890
movq -0x218(%rbp), %rax
addq $0x260, %rsp            # imm = 0x260
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x1f0(%rbp), %rdi
callq 0x9520
leaq -0x38(%rbp), %rdi
callq 0x9890
movq -0x50(%rbp), %rdi
callq 0x45c0
nopl (%rax,%rax)