// File: /workspace/github_cpp_makefile_star2_O2/NathanWine[P]2048-AI-Solvers/src/Minimax.cpp
// Function: minimaxSearch(int, int, Game)
std::pair<int, int> minimaxSearch(int depth, int display_level, Game game) {
    std::cout << "Attempting to solve a new game with Minimax... " << std::flush;
    while (game.canContinue()) {
        if (display_level >= 2) {
            std::cout << std::endl << game;
        }

        std::map<int, weightedmoves> possibilities = game.computePossibilities();
        std::map<int, float> scores;

        for (auto const& entry : possibilities) {
            int move = entry.first;                             // Direction of move
            int len = (int) entry.second.size();                // entry.second is a vector of (prob, game)
            if (len > 0) {
                scores[move] = 0.0;
                for (int j = 0; j < len; ++j) {
                    scores[move] += minimaxScore(depth, entry.second[j].second) * entry.second[j].first;
                }
            }
        }

        if (display_level >= 3) {
            std::cout << "Heuristic score: " << Heuristics::get_h_score(game.state) << std::endl << "Move scores: ";
            for (auto const& score : scores) {
                std::cout << score.first << ": " << score.second << ", ";
            }
            std::cout << std::endl;
        }

        float max_score = -std::numeric_limits<float>::max();
        int max_choice = UP;
        for (auto const& score : scores) {      // Determine best move choice based on tabulated scores
            if (score.second > max_score) {     // score.first is the move direction, score.second is the score
                max_score = score.second;
                max_choice = score.first;
            }
        }

        switch (max_choice) {
            case UP:
                game.up(false);
                break;
            case DOWN:
                game.down(false);
                break;
            case LEFT: 
                game.left(false);
                break;
            case RIGHT:
                game.right(false);
        }
    }
    if (display_level <= 1) {
        std::cout << "Done!" << (display_level == 0 ? "\n" : "");
    }
    if (display_level >= 1) {
        std::cout << std::endl << game << std::endl;
    }
    return std::pair<int, int>(game.getHighestTile(), game.score);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movq %rdx, %rbx
movl %esi, 0x10(%rsp)
movl %edi, %r14d
movq 0x99fd(%rip), %rdi      # 0xcfd0
leaq 0x4b16(%rip), %rsi      # 0x80f0
callq 0x21b0
movq %rax, %rdi
callq 0x2120
movq %rbx, 0x8(%rsp)
leaq 0x8(%rbx), %rax
movq %rax, 0x20(%rsp)
leaq 0x28(%rsp), %rbp
leaq 0x1c(%rsp), %rbx
movq 0x8(%rsp), %rdi
callq 0x56a2
testb %al, %al
je 0x3870
cmpl $0x2, 0x10(%rsp)
jl 0x3631
movq 0x99b1(%rip), %rdi      # 0xcfd0
callq 0x20d0
movq %rax, %rdi
movq 0x8(%rsp), %rsi
callq 0x625d
leaq 0x58(%rsp), %rdi
movq 0x8(%rsp), %rsi
callq 0x5a30
andl $0x0, 0x30(%rsp)
andq $0x0, 0x38(%rsp)
leaq 0x30(%rsp), %rax
movq %rax, 0x40(%rsp)
movq %rax, 0x48(%rsp)
andq $0x0, 0x50(%rsp)
movq 0x70(%rsp), %r12
leaq 0x60(%rsp), %rax
cmpq %rax, %r12
je 0x3718
movl 0x20(%r12), %eax
movl %eax, 0x1c(%rsp)
movq 0x30(%r12), %rax
subq 0x28(%r12), %rax
cqto
pushq $0x28
popq %rcx
idivq %rcx
movq %rax, %r13
testl %r13d, %r13d
jle 0x3708
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x39ec
andl $0x0, (%rax)
andl $0x7fffffff, %r13d      # imm = 0x7FFFFFFF
imulq $0x28, %r13, %r13
xorl %r15d, %r15d
cmpq %r15, %r13
je 0x3708
movq 0x28(%r12), %rax
leaq (%rax,%r15), %rsi
addq $0x8, %rsi
movl %r14d, %edi
callq 0x33f8
movss %xmm0, 0x14(%rsp)
movq 0x28(%r12), %rax
movss (%rax,%r15), %xmm0
movss %xmm0, 0x18(%rsp)
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x39ec
movss 0x14(%rsp), %xmm0
mulss 0x18(%rsp), %xmm0
addss (%rax), %xmm0
movss %xmm0, (%rax)
addq $0x28, %r15
jmp 0x36b2
movq %r12, %rdi
callq 0x2130
movq %rax, %r12
jmp 0x3665
cmpl $0x2, 0x10(%rsp)
jle 0x37c8
movq 0x98a6(%rip), %rdi      # 0xcfd0
leaq 0x49ef(%rip), %rsi      # 0x8120
callq 0x21b0
movq %rax, %r12
movq 0x20(%rsp), %rdi
callq 0x7ce2
movq %r12, %rdi
callq 0x2150
movq %rax, %rdi
callq 0x20d0
movq %rax, %rdi
leaq 0x49d5(%rip), %rsi      # 0x8132
callq 0x21b0
movq 0x40(%rsp), %r12
leaq 0x30(%rsp), %rax
cmpq %rax, %r12
je 0x37bc
movl 0x20(%r12), %esi
movq 0x9853(%rip), %rdi      # 0xcfd0
callq 0x22b0
movq %rax, %rdi
leaq 0x4ceb(%rip), %rsi      # 0x8477
callq 0x21b0
movss 0x24(%r12), %xmm0
movq %rax, %rdi
callq 0x2150
movq %rax, %rdi
leaq 0x4996(%rip), %rsi      # 0x8140
callq 0x21b0
movq %r12, %rdi
callq 0x2130
movq %rax, %r12
jmp 0x3767
movq 0x980d(%rip), %rdi      # 0xcfd0
callq 0x20d0
xorl %r15d, %r15d
movq 0x40(%rsp), %rax
movss 0x4900(%rip), %xmm0     # 0x80d8
leaq 0x30(%rsp), %rcx
cmpq %rcx, %rax
je 0x380a
movss 0x24(%rax), %xmm1
ucomiss %xmm0, %xmm1
jbe 0x37f0
movl 0x20(%rax), %r15d
maxss %xmm0, %xmm1
movss %xmm1, 0x14(%rsp)
movq %rax, %rdi
callq 0x2130
movss 0x14(%rsp), %xmm0
jmp 0x37d8
cmpl $0x3, %r15d
ja 0x3859
movl %r15d, %eax
leaq 0x48c6(%rip), %rcx      # 0x80e0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0x5944
jmp 0x3859
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0x59e0
jmp 0x3859
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0x5a08
jmp 0x3859
movq 0x8(%rsp), %rdi
xorl %esi, %esi
callq 0x59b8
movq %rbp, %rdi
callq 0x3a3a
leaq 0x58(%rsp), %rdi
callq 0x3a92
jmp 0x35ff
movl 0x10(%rsp), %ebx
cmpl $0x1, %ebx
jg 0x38ad
movq 0x9750(%rip), %rdi      # 0xcfd0
leaq 0x47fd(%rip), %rsi      # 0x8084
callq 0x21b0
testl %ebx, %ebx
leaq 0x47f5(%rip), %rcx      # 0x808a
leaq 0x47ef(%rip), %rsi      # 0x808b
cmoveq %rcx, %rsi
movq %rax, %rdi
callq 0x21b0
cmpl $0x1, %ebx
jne 0x38ce
movq 0x971c(%rip), %rdi      # 0xcfd0
callq 0x20d0
movq %rax, %rdi
movq 0x8(%rsp), %rsi
callq 0x625d
movq %rax, %rdi
callq 0x20d0
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
callq 0x61f8
movl (%rbx), %ecx
shlq $0x20, %rcx
movl %eax, %eax
orq %rcx, %rax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x3900
jmp 0x3900
jmp 0x3900
jmp 0x3900
movq %rax, %rbx
leaq 0x28(%rsp), %rdi
callq 0x3a3a
leaq 0x58(%rsp), %rdi
callq 0x3a92
movq %rbx, %rdi
callq 0x22c0