// File: chrischute[P]are-you-the-one/src/ayto.cpp
// Function: getNextGuessUsingMinimax[abi:cxx11](PerfectMatchingSet const*, PerfectMatchingSet const*)
Pm getNextGuessUsingMinimax(const PmSet* possibleAnswers, const PmSet* guessesAlreadyMade)
{
    // Spin up threads to run minimax in parallel.
    map<Pm, int>* bestGuessFromEachThread = new map<Pm, int>();
    mutex* writeLock = new mutex();
    vector<thread> minimaxThreads;
    vector<ArgsForMinimaxThread*> argsForMinimaxThreads;
    PmSet** chunksToEvaluate;

    if (possibleAnswers->size() > START_PART_MM) {
        // Select the best guess from a fixed pool of possibilities.
        PmSet* fixedPoolToEvaluate = new PmSet();
        fixedPoolToEvaluate->populateFromFile(POOL_FILENAME);
        chunksToEvaluate = fixedPoolToEvaluate->copyIntoChunks(NUM_THREADS);
        delete fixedPoolToEvaluate;
    } else if (possibleAnswers->size() > START_FULL_MM) {
        // Select the best guess from the possible remaining solutions.
        chunksToEvaluate = possibleAnswers->copyIntoChunks(NUM_THREADS);
    } else {
        // Select the best guess from all possible permutations.
        cout << "    Full minimax... May take up to one minute." << endl;
        PmSet* allPossible = new PmSet();
        allPossible->populateAll();
        chunksToEvaluate = allPossible->copyIntoChunks(NUM_THREADS);
        delete allPossible;
    }

    for (int id = 0; id < NUM_THREADS; ++id) {
        ArgsForMinimaxThread* args = new ArgsForMinimaxThread(
                id,
                possibleAnswers,
                chunksToEvaluate[id],
                guessesAlreadyMade,
                bestGuessFromEachThread,
                writeLock);
        argsForMinimaxThreads.push_back(args);
        minimaxThreads.push_back(thread(getBestGuessFromSubset, args));
    }

    // Wait for all threads to finish up.
    for (vector<thread>::iterator it = minimaxThreads.begin();
         it != minimaxThreads.end();
         ++it) {
        it->join();
    }

    // Find the best guess in the set bestGuessFromEachThread.
    Pm bestGuess("");
    long numRemainingAfterBestGuess = possibleAnswers->size();
    for (map<Pm, int>::const_iterator it = bestGuessFromEachThread->begin();
         it != bestGuessFromEachThread->end();
         ++it) {
        Pm guess = it->first;
        int numRemainingAfterGuess = it->second;

        if (numRemainingAfterGuess < numRemainingAfterBestGuess) {
            bestGuess = guess;
            numRemainingAfterBestGuess = numRemainingAfterGuess;
        }
    }

    // Clean up allocated args, chunks, map, and mutex.
    for (vector<ArgsForMinimaxThread*>::iterator it = argsForMinimaxThreads.begin();
         it != argsForMinimaxThreads.end();
         ++it) {
        delete *it;
    }
    for (int i = 0; i < NUM_THREADS; ++i) {
        if (chunksToEvaluate && chunksToEvaluate[i]) {
            delete chunksToEvaluate[i];
        }
    }
    if (chunksToEvaluate) {
        delete chunksToEvaluate;
    }
    delete bestGuessFromEachThread;
    delete writeLock;

    return bestGuess;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x220, %rsp            # imm = 0x220
movq %rdi, -0x178(%rbp)
movq %rdi, %rax
movq %rax, -0x170(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movl $0x30, %edi
callq 0x32f0
movq %rax, %rdi
movq %rdi, -0x168(%rbp)
xorps %xmm0, %xmm0
movaps %xmm0, -0x160(%rbp)
movaps %xmm0, 0x20(%rdi)
movaps %xmm0, 0x10(%rdi)
movaps %xmm0, (%rdi)
callq 0x7c20
movq -0x168(%rbp), %rax
movq %rax, -0x20(%rbp)
movl $0x28, %edi
callq 0x32f0
movaps -0x160(%rbp), %xmm0
movq %rax, %rdi
movq %rdi, -0x150(%rbp)
movaps %xmm0, 0x10(%rdi)
movaps %xmm0, (%rdi)
movq $0x0, 0x20(%rdi)
callq 0x7c40
movq -0x150(%rbp), %rax
movq %rax, -0x28(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x7c60
leaq -0x58(%rbp), %rdi
callq 0x7c80
movq -0x10(%rbp), %rdi
callq 0x107a0
movq %rax, -0x148(%rbp)
jmp 0x592f
movq -0x148(%rbp), %rax
cmpq $0x2710, %rax           # imm = 0x2710
jbe 0x5a94
movl $0x8, %edi
callq 0x32f0
movq %rax, -0x180(%rbp)
jmp 0x5955
movq -0x180(%rbp), %rdi
callq 0x10100
jmp 0x5963
movq -0x180(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x78(%rbp), %rax
movq %rax, -0x190(%rbp)
leaq -0x99(%rbp), %rdi
movq %rdi, -0x188(%rbp)
callq 0x34e0
movq -0x188(%rbp), %rdx
leaq 0xe860(%rip), %rsi      # 0x141fa
leaq -0x98(%rbp), %rdi
callq 0x6e80
jmp 0x59a8
movq -0x190(%rbp), %rdi
leaq -0x98(%rbp), %rsi
callq 0x10680
jmp 0x59bd
leaq -0x98(%rbp), %rdi
callq 0x3190
leaq -0x99(%rbp), %rdi
callq 0x3340
movq -0x78(%rbp), %rdi
movl $0xa, %esi
callq 0x107c0
movq %rax, -0x198(%rbp)
jmp 0x59ec
movq -0x198(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x78(%rbp), %rax
movq %rax, -0x1a0(%rbp)
cmpq $0x0, %rax
je 0x5a25
movq -0x1a0(%rbp), %rdi
callq 0x10210
movq -0x1a0(%rbp), %rdi
movl $0x8, %esi
callq 0x3300
jmp 0x5bc6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x6079
movq -0x180(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
movl $0x8, %esi
callq 0x3300
jmp 0x6079
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x5a83
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x98(%rbp), %rdi
callq 0x3190
leaq -0x99(%rbp), %rdi
callq 0x3340
jmp 0x6079
movq -0x10(%rbp), %rdi
callq 0x107a0
movq %rax, -0x1a8(%rbp)
jmp 0x5aa6
movq -0x1a8(%rbp), %rax
cmpq $0x13a, %rax            # imm = 0x13A
jbe 0x5adc
movq -0x10(%rbp), %rdi
movl $0xa, %esi
callq 0x107c0
movq %rax, -0x1b0(%rbp)
jmp 0x5acc
movq -0x1b0(%rbp), %rax
movq %rax, -0x60(%rbp)
jmp 0x5bc4
movq 0x184e5(%rip), %rdi     # 0x1dfc8
leaq 0xe721(%rip), %rsi      # 0x1420b
callq 0x32e0
movq %rax, -0x1b8(%rbp)
jmp 0x5af8
movq -0x1b8(%rbp), %rdi
movq 0x184aa(%rip), %rsi     # 0x1dfb0
callq 0x3320
jmp 0x5b0d
movl $0x8, %edi
callq 0x32f0
movq %rax, -0x1c0(%rbp)
jmp 0x5b20
movq -0x1c0(%rbp), %rdi
callq 0x10100
jmp 0x5b2e
movq -0x1c0(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0xa8(%rbp), %rdi
callq 0x105b0
jmp 0x5b4a
movq -0xa8(%rbp), %rdi
movl $0xa, %esi
callq 0x107c0
movq %rax, -0x1c8(%rbp)
jmp 0x5b64
movq -0x1c8(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0x1d0(%rbp)
cmpq $0x0, %rax
je 0x5ba0
movq -0x1d0(%rbp), %rdi
callq 0x10210
movq -0x1d0(%rbp), %rdi
movl $0x8, %esi
callq 0x3300
jmp 0x5bc4
movq -0x1c0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
movl $0x8, %esi
callq 0x3300
jmp 0x6079
jmp 0x5bc6
movl $0x0, -0xac(%rbp)
cmpl $0xa, -0xac(%rbp)
jge 0x5cd2
movl $0x30, %edi
callq 0x32f0
movq %rax, -0x1d8(%rbp)
jmp 0x5bf0
movq -0x1d8(%rbp), %rdi
movslq -0xac(%rbp), %rcx
movl %ecx, %esi
movq -0x10(%rbp), %rdx
movq -0x60(%rbp), %rax
movq (%rax,%rcx,8), %rcx
movq -0x18(%rbp), %r8
movq -0x20(%rbp), %r9
movq -0x28(%rbp), %r10
movq %rsp, %rax
movq %r10, (%rax)
callq 0x7ca0
jmp 0x5c25
movq -0x1d8(%rbp), %rax
movq %rax, -0xb8(%rbp)
leaq -0x58(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x7d00
jmp 0x5c45
leaq 0x7e4(%rip), %rsi       # 0x6430
leaq -0xc0(%rbp), %rdi
leaq -0xb8(%rbp), %rdx
callq 0x7da0
jmp 0x5c61
leaq -0x40(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x7d70
jmp 0x5c73
leaq -0xc0(%rbp), %rdi
callq 0x7e60
movl -0xac(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xac(%rbp)
jmp 0x5bd0
movq -0x1d8(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
movl $0x30, %esi
callq 0x3300
jmp 0x6079
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xc0(%rbp), %rdi
callq 0x7e60
jmp 0x6079
leaq -0x40(%rbp), %rdi
callq 0x7e90
movq %rax, -0xc8(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x7f00
movq %rax, -0xd0(%rbp)
leaq -0xc8(%rbp), %rdi
leaq -0xd0(%rbp), %rsi
callq 0x7ec0
testb $0x1, %al
jne 0x5d0b
jmp 0x5d31
leaq -0xc8(%rbp), %rdi
callq 0x7f30
movq %rax, %rdi
callq 0x34b0
jmp 0x5d21
jmp 0x5d23
leaq -0xc8(%rbp), %rdi
callq 0x7f50
jmp 0x5ce2
movb $0x0, -0xd1(%rbp)
leaq -0xd2(%rbp), %rdi
movq %rdi, -0x1e0(%rbp)
callq 0x34e0
movq -0x178(%rbp), %rdi
movq -0x1e0(%rbp), %rdx
leaq 0xe4de(%rip), %rsi      # 0x1423e
callq 0x6e80
jmp 0x5d67
leaq -0xd2(%rbp), %rdi
callq 0x3340
movq -0x10(%rbp), %rdi
callq 0x107a0
movq %rax, -0x1e8(%rbp)
jmp 0x5d85
movq -0x1e8(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0x20(%rbp), %rdi
callq 0x7f70
movq %rax, -0xf0(%rbp)
leaq -0xe8(%rbp), %rdi
leaq -0xf0(%rbp), %rsi
callq 0x7fa0
movq -0x20(%rbp), %rdi
callq 0x7ff0
movq %rax, -0x100(%rbp)
leaq -0xf8(%rbp), %rdi
leaq -0x100(%rbp), %rsi
callq 0x7fa0
leaq -0xe8(%rbp), %rdi
leaq -0xf8(%rbp), %rsi
callq 0x7fc0
testb $0x1, %al
jne 0x5df5
jmp 0x5ec4
leaq -0xe8(%rbp), %rdi
callq 0x8020
movq %rax, %rsi
leaq -0x120(%rbp), %rdi
callq 0x30f0
jmp 0x5e12
leaq -0xe8(%rbp), %rdi
callq 0x8020
movl 0x20(%rax), %eax
movl %eax, -0x124(%rbp)
movslq -0x124(%rbp), %rax
cmpq -0xe0(%rbp), %rax
jge 0x5ea7
movq -0x178(%rbp), %rdi
leaq -0x120(%rbp), %rsi
callq 0x3050
jmp 0x5e4c
movslq -0x124(%rbp), %rax
movq %rax, -0xe0(%rbp)
jmp 0x5ea7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0xd2(%rbp), %rdi
callq 0x3340
jmp 0x6079
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
jmp 0x606d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x68(%rbp)
movl %eax, -0x6c(%rbp)
leaq -0x120(%rbp), %rdi
callq 0x3190
jmp 0x606d
leaq -0x120(%rbp), %rdi
callq 0x3190
leaq -0xe8(%rbp), %rdi
callq 0x8050
jmp 0x5db6
leaq -0x58(%rbp), %rdi
callq 0x8080
movq %rax, -0x130(%rbp)
leaq -0x58(%rbp), %rdi
callq 0x80f0
movq %rax, -0x138(%rbp)
leaq -0x130(%rbp), %rdi
leaq -0x138(%rbp), %rsi
callq 0x80b0
testb $0x1, %al
jne 0x5efd
jmp 0x5f3a
leaq -0x130(%rbp), %rdi
callq 0x8120
movq (%rax), %rax
movq %rax, -0x1f0(%rbp)
cmpq $0x0, %rax
je 0x5f2a
movq -0x1f0(%rbp), %rdi
movl $0x30, %esi
callq 0x3300
jmp 0x5f2c
leaq -0x130(%rbp), %rdi
callq 0x8140
jmp 0x5ed4
movl $0x0, -0x13c(%rbp)
cmpl $0xa, -0x13c(%rbp)
jge 0x5fb4
cmpq $0x0, -0x60(%rbp)
je 0x5fa1
movq -0x60(%rbp), %rax
movslq -0x13c(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x5fa1
movq -0x60(%rbp), %rax
movslq -0x13c(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x1f8(%rbp)
cmpq $0x0, %rax
je 0x5f9f
movq -0x1f8(%rbp), %rdi
callq 0x10210
movq -0x1f8(%rbp), %rdi
movl $0x8, %esi
callq 0x3300
jmp 0x5fa1
jmp 0x5fa3
movl -0x13c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x13c(%rbp)
jmp 0x5f44
cmpq $0x0, -0x60(%rbp)
je 0x5fdf
movq -0x60(%rbp), %rax
movq %rax, -0x200(%rbp)
cmpq $0x0, %rax
je 0x5fdd
movq -0x200(%rbp), %rdi
movl $0x8, %esi
callq 0x3300
jmp 0x5fdf
movq -0x20(%rbp), %rax
movq %rax, -0x208(%rbp)
cmpq $0x0, %rax
je 0x600d
movq -0x208(%rbp), %rdi
callq 0x8160
movq -0x208(%rbp), %rdi
movl $0x30, %esi
callq 0x3300
movq -0x28(%rbp), %rax
movq %rax, -0x210(%rbp)
cmpq $0x0, %rax
je 0x602f
movq -0x210(%rbp), %rdi
movl $0x28, %esi
callq 0x3300
movb $0x1, -0xd1(%rbp)
testb $0x1, -0xd1(%rbp)
jne 0x604b
movq -0x178(%rbp), %rdi
callq 0x3190
leaq -0x58(%rbp), %rdi
callq 0x8180
leaq -0x40(%rbp), %rdi
callq 0x81e0
movq -0x170(%rbp), %rax
addq $0x220, %rsp            # imm = 0x220
popq %rbp
retq
movq -0x178(%rbp), %rdi
callq 0x3190
leaq -0x58(%rbp), %rdi
callq 0x8180
leaq -0x40(%rbp), %rdi
callq 0x81e0
movq -0x68(%rbp), %rdi
callq 0x34d0
nopw %cs:(%rax,%rax)