// File: /workspace/github_cpp_makefile_star2_O2/NathanWine[P]2048-AI-Solvers/src/Expectimax.cpp
// Function: expectimaxSearch(int, int, Game)
std::pair<int, int> expectimaxSearch(int depth, int display_level, Game game) {
    std::cout << "Attempting to solve a new game with Expectimax... " << 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
            weightedmoves weighted_subset = entry.second;       // Vector of (prob, game)
            int len = (int) weighted_subset.size();
            if (len > 0) {
                scores[move] = 0.0;
                for (int j = 0; j < len; ++j) {
                    scores[move] += expectimaxScore(depth, weighted_subset[j].second, true) * weighted_subset[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) {
                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 $0xb8, %rsp
movq %rdx, %rbx
movl %esi, 0x8(%rsp)
movl %edi, %r14d
movq 0x58a2(%rip), %rdi      # 0xcfd0
leaq 0xf07(%rip), %rsi       # 0x863c
callq 0x21b0
movq %rax, %rdi
callq 0x2120
movq %rbx, (%rsp)
leaq 0x8(%rbx), %rax
movq %rax, 0x60(%rsp)
leaq 0x14(%rsp), %rbp
leaq 0x98(%rsp), %r15
movq (%rsp), %rdi
callq 0x56a2
testb %al, %al
je 0x7a01
cmpl $0x2, 0x8(%rsp)
jl 0x778c
movq 0x5855(%rip), %rdi      # 0xcfd0
callq 0x20d0
movq %rax, %rdi
movq (%rsp), %rsi
callq 0x625d
leaq 0x68(%rsp), %rdi
movq (%rsp), %rsi
callq 0x5a30
andl $0x0, 0x38(%rsp)
andq $0x0, 0x40(%rsp)
leaq 0x38(%rsp), %rax
movq %rax, 0x48(%rsp)
movq %rax, 0x50(%rsp)
andq $0x0, 0x58(%rsp)
movq 0x80(%rsp), %r12
leaq 0x70(%rsp), %rax
cmpq %rax, %r12
je 0x78af
movl 0x20(%r12), %eax
movl %eax, 0x14(%rsp)
leaq 0x28(%r12), %rsi
leaq 0x18(%rsp), %rdi
callq 0x7b7a
movq 0x20(%rsp), %rax
subq 0x18(%rsp), %rax
cqto
pushq $0x28
popq %rcx
idivq %rcx
movq %rax, %r13
testl %r13d, %r13d
jle 0x7895
leaq 0x30(%rsp), %rdi
movq %rbp, %rsi
callq 0x39ec
andl $0x0, (%rax)
andl $0x7fffffff, %r13d      # imm = 0x7FFFFFFF
imulq $0x28, %r13, %r13
xorl %ebx, %ebx
cmpq %rbx, %r13
je 0x7895
movq 0x18(%rsp), %rax
leaq (%rax,%rbx), %rsi
addq $0x8, %rsi
movq %r15, %rdi
callq 0x29e8
movl %r14d, %edi
movq %r15, %rsi
pushq $0x1
popq %rdx
callq 0x72cc
movss %xmm0, 0xc(%rsp)
movq 0x18(%rsp), %rax
movss (%rax,%rbx), %xmm0
movss %xmm0, 0x10(%rsp)
leaq 0x30(%rsp), %rdi
movq %rbp, %rsi
callq 0x39ec
movss 0xc(%rsp), %xmm0
mulss 0x10(%rsp), %xmm0
addss (%rax), %xmm0
movss %xmm0, (%rax)
leaq 0xa0(%rsp), %rdi
callq 0x2abc
addq $0x28, %rbx
jmp 0x7823
leaq 0x18(%rsp), %rdi
callq 0x3af6
movq %r12, %rdi
callq 0x2130
movq %rax, %r12
jmp 0x77c2
cmpl $0x2, 0x8(%rsp)
jle 0x795f
movq 0x570f(%rip), %rdi      # 0xcfd0
leaq 0x858(%rip), %rsi       # 0x8120
callq 0x21b0
movq %rax, %r12
movq 0x60(%rsp), %rdi
callq 0x7ce2
movq %r12, %rdi
callq 0x2150
movq %rax, %rdi
callq 0x20d0
movq %rax, %rdi
leaq 0x83e(%rip), %rsi       # 0x8132
callq 0x21b0
movq 0x48(%rsp), %r12
leaq 0x38(%rsp), %rax
cmpq %rax, %r12
je 0x7953
movl 0x20(%r12), %esi
movq 0x56bc(%rip), %rdi      # 0xcfd0
callq 0x22b0
movq %rax, %rdi
leaq 0xb54(%rip), %rsi       # 0x8477
callq 0x21b0
movss 0x24(%r12), %xmm0
movq %rax, %rdi
callq 0x2150
movq %rax, %rdi
leaq 0x7ff(%rip), %rsi       # 0x8140
callq 0x21b0
movq %r12, %rdi
callq 0x2130
movq %rax, %r12
jmp 0x78fe
movq 0x5676(%rip), %rdi      # 0xcfd0
callq 0x20d0
xorl %ebx, %ebx
movq 0x48(%rsp), %rax
movss 0x76a(%rip), %xmm0      # 0x80d8
leaq 0x38(%rsp), %rcx
cmpq %rcx, %rax
je 0x799f
movss 0x24(%rax), %xmm1
ucomiss %xmm0, %xmm1
jbe 0x7985
movl 0x20(%rax), %ebx
maxss %xmm0, %xmm1
movss %xmm1, 0xc(%rsp)
movq %rax, %rdi
callq 0x2130
movss 0xc(%rsp), %xmm0
jmp 0x796e
cmpl $0x3, %ebx
ja 0x79e8
movl %ebx, %eax
leaq 0xc7f(%rip), %rcx       # 0x862c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x5944
jmp 0x79e8
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x59e0
jmp 0x79e8
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x5a08
jmp 0x79e8
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x59b8
leaq 0x30(%rsp), %rdi
callq 0x3a3a
leaq 0x68(%rsp), %rdi
callq 0x3a92
jmp 0x775c
movl 0x8(%rsp), %ebx
cmpl $0x1, %ebx
jg 0x7a3e
movq 0x55bf(%rip), %rdi      # 0xcfd0
leaq 0x66c(%rip), %rsi       # 0x8084
callq 0x21b0
testl %ebx, %ebx
leaq 0x664(%rip), %rcx       # 0x808a
leaq 0x65e(%rip), %rsi       # 0x808b
cmoveq %rcx, %rsi
movq %rax, %rdi
callq 0x21b0
cmpl $0x1, %ebx
jne 0x7a5e
movq 0x558b(%rip), %rdi      # 0xcfd0
callq 0x20d0
movq %rax, %rdi
movq (%rsp), %rsi
callq 0x625d
movq %rax, %rdi
callq 0x20d0
movq (%rsp), %rbx
movq %rbx, %rdi
callq 0x61f8
movl (%rbx), %ecx
shlq $0x20, %rcx
movl %eax, %eax
orq %rcx, %rax
addq $0xb8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x7a8f
jmp 0x7a8f
jmp 0x7a94
jmp 0x7a8f
movq %rax, %rbx
jmp 0x7ab3
movq %rax, %rbx
jmp 0x7aa9
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0x2abc
leaq 0x18(%rsp), %rdi
callq 0x3af6
leaq 0x30(%rsp), %rdi
callq 0x3a3a
leaq 0x68(%rsp), %rdi
callq 0x3a92
movq %rbx, %rdi
callq 0x22c0