// File: /workspace/github_cpp_makefile_star2_O2/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 $0x138, %rsp            # imm = 0x138
movq %r8, -0x78(%rbp)
movl %ecx, %ebx
movl %edx, -0x2c(%rbp)
movq %rdi, -0x70(%rbp)
movl %esi, -0x30(%rbp)
movslq %esi, %rsi
movslq 0xf3b6(%rip), %rdx      # 0x1534c
movslq 0xf3b3(%rip), %rcx      # 0x15350
leaq -0x68(%rbp), %rdi
callq 0x599b
xorl %eax, %eax
testl %ebx, %ebx
cmovlel %eax, %ebx
movl %ebx, -0x34(%rbp)
leaq -0xe8(%rbp), %r13
movq %rax, -0x80(%rbp)
cmpl -0x34(%rbp), %eax
je 0x612e
leaq -0x100(%rbp), %rbx
movq %rbx, %rdi
movq -0x78(%rbp), %rsi
leaq -0x68(%rbp), %rdx
callq 0x75b4
leaq -0x98(%rbp), %rdi
movq %rbx, %rsi
movl -0x30(%rbp), %edx
callq 0x75d6
andq $0x0, -0x40(%rbp)
xorps %xmm0, %xmm0
movaps %xmm0, -0x50(%rbp)
xorl %ebx, %ebx
xorl %r15d, %r15d
movq -0x98(%rbp), %rsi
movq -0x90(%rbp), %rax
subq %rsi, %rax
sarq $0x6, %rax
decq %rax
cmpq %rax, %r15
jae 0x605d
leaq (%rsi,%rbx), %rdx
addq $0x40, %rdx
addq %rbx, %rsi
movq %r13, %rdi
callq 0x5e72
leaq -0x50(%rbp), %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x7768
movq %r12, %rdi
leaq -0xc8(%rbp), %rsi
callq 0x7768
movq %r13, %rdi
callq 0x77a4
addq $0x40, %rbx
incq %r15
jmp 0x5ffe
movq -0x50(%rbp), %rdi
movq -0x48(%rbp), %rsi
leaq -0x274(%rip), %rax      # 0x5df8
movq %rax, -0xa8(%rbp)
movl -0x2c(%rbp), %eax
movl %eax, -0xa0(%rbp)
movq %rdi, %rdx
leaq -0xa8(%rbp), %rcx
callq 0x77c4
leaq -0x68(%rbp), %rdi
callq 0x7828
movq -0x50(%rbp), %rbx
movq -0x48(%rbp), %r15
cmpq %r15, %rbx
je 0x6102
leaq -0x120(%rbp), %r12
movq %r12, %rdi
movq %rbx, %rsi
callq 0x4440
leaq -0x158(%rbp), %r14
movq %r14, %rdi
movq %r12, %rsi
callq 0x7836
movq %r13, %rdi
movq %r14, %rsi
callq 0x57a1
leaq -0x68(%rbp), %rdi
movq %r13, %rsi
callq 0x7ac8
movq %r13, %rdi
callq 0x6ed6
leaq -0x158(%rbp), %rdi
callq 0x7342
leaq -0x120(%rbp), %rdi
callq 0x4160
addq $0x20, %rbx
jmp 0x609c
leaq -0x50(%rbp), %rdi
callq 0x78de
leaq -0x98(%rbp), %rdi
callq 0x6f7a
leaq -0x100(%rbp), %rdi
callq 0x6ef6
movq -0x80(%rbp), %rax
incl %eax
jmp 0x5fb7
leaq -0xe8(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x5a60
movq -0xe8(%rbp), %rdi
movq -0xe0(%rbp), %rsi
callq 0x8954
movq -0x70(%rbp), %rbx
movq -0xe8(%rbp), %rsi
movq %rbx, %rdi
callq 0x6e9c
leaq -0xe8(%rbp), %rdi
callq 0x6ef6
leaq -0x68(%rbp), %rdi
callq 0x6f7a
movq %rbx, %rax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x619e
movq %rax, %rbx
leaq -0xe8(%rbp), %rdi
jmp 0x620d
jmp 0x61dd
movq %rax, %rbx
jmp 0x6212
movq %rax, %rbx
jmp 0x6206
jmp 0x61dd
movq %rax, %rbx
jmp 0x61cf
movq %rax, %rbx
jmp 0x61c3
movq %rax, %rbx
leaq -0xe8(%rbp), %rdi
callq 0x6ed6
leaq -0x158(%rbp), %rdi
callq 0x7342
leaq -0x120(%rbp), %rdi
callq 0x4160
jmp 0x61f1
movq %rax, %rbx
jmp 0x61f1
movq %rax, %rbx
leaq -0xe8(%rbp), %rdi
callq 0x77a4
leaq -0x50(%rbp), %rdi
callq 0x78de
leaq -0x98(%rbp), %rdi
callq 0x6f7a
leaq -0x100(%rbp), %rdi
callq 0x6ef6
leaq -0x68(%rbp), %rdi
callq 0x6f7a
movq %rbx, %rdi
callq 0x4520