// File: /workspace/github_cpp_makefile_star2_O1/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, %r15d
movq 0x570d(%rip), %r14      # 0xdfd8
leaq 0x1d6a(%rip), %rsi      # 0xa63c
movl $0x32, %edx
movq %r14, %rdi
callq 0x21e0
movq %r14, %rdi
callq 0x2110
movq %rbx, (%rsp)
movq %rbx, %rdi
callq 0x63a6
testb %al, %al
je 0x8c65
leaq 0xa0(%rsp), %r12
movq (%rsp), %rax
addq $0x8, %rax
movq %rax, 0x60(%rsp)
leaq 0x18(%rsp), %rbx
leaq 0x14(%rsp), %rbp
cmpl $0x2, 0x8(%rsp)
jl 0x8960
movq 0x56b0(%rip), %rbx      # 0xdfd8
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2180
movsbl %al, %esi
movq %rbx, %rdi
leaq 0x18(%rsp), %rbx
callq 0x2030
movq %rax, %rdi
callq 0x2110
movq %rax, %rdi
movq (%rsp), %rsi
callq 0x7287
leaq 0x68(%rsp), %rdi
movq (%rsp), %rsi
callq 0x6844
movl $0x0, 0x38(%rsp)
xorl %ecx, %ecx
movq %rcx, 0x40(%rsp)
leaq 0x38(%rsp), %rax
movq %rax, 0x48(%rsp)
movq %rax, 0x50(%rsp)
movq %rcx, 0x58(%rsp)
movq 0x80(%rsp), %r13
leaq 0x70(%rsp), %rax
cmpq %rax, %r13
je 0x8a95
movl 0x20(%r13), %eax
movl %eax, 0x14(%rsp)
leaq 0x28(%r13), %rsi
movq %rbx, %rdi
callq 0x8e6a
movq 0x20(%rsp), %r14
subq 0x18(%rsp), %r14
sarq $0x3, %r14
movabsq $-0x3333333333333333, %rax # imm = 0xCCCCCCCCCCCCCCCD
imulq %rax, %r14
testl %r14d, %r14d
jle 0x8a78
leaq 0x30(%rsp), %rdi
movq %rbp, %rsi
callq 0x3e48
movl $0x0, (%rax)
andl $0x7fffffff, %r14d      # imm = 0x7FFFFFFF
movl $0x10, %ebx
movq 0x18(%rsp), %rsi
movl -0x8(%rsi,%rbx), %eax
addq %rbx, %rsi
movl %eax, 0x98(%rsp)
movq %r12, %rdi
callq 0x2d38
movl %r15d, %edi
leaq 0x98(%rsp), %rsi
movl $0x1, %edx
callq 0x843c
movss %xmm0, 0xc(%rsp)
movq 0x18(%rsp), %rax
movss -0x10(%rax,%rbx), %xmm0
movss %xmm0, 0x10(%rsp)
leaq 0x30(%rsp), %rdi
movq %rbp, %rsi
callq 0x3e48
movss 0xc(%rsp), %xmm0
mulss 0x10(%rsp), %xmm0
addss (%rax), %xmm0
movss %xmm0, (%rax)
movq %r12, %rdi
callq 0x2e18
addq $0x28, %rbx
decq %r14
jne 0x89ff
leaq 0x18(%rsp), %rbx
movq %rbx, %rdi
callq 0x3f54
movq %r13, %rdi
callq 0x2120
movq %rax, %r13
jmp 0x8999
cmpl $0x2, 0x8(%rsp)
jle 0x8baa
movl $0x11, %edx
movq 0x552c(%rip), %rdi      # 0xdfd8
leaq 0x166d(%rip), %rsi      # 0xa120
callq 0x21e0
movq 0x60(%rsp), %rdi
callq 0x9011
cvtss2sd %xmm0, %xmm0
movq 0x550b(%rip), %rdi      # 0xdfd8
callq 0x2260
movq %rax, %r13
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %r13, %rdi
movl $0xa, %esi
callq 0x2180
movsbl %al, %esi
movq %r13, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2110
movl $0xd, %edx
movq %rax, %rdi
leaq 0x1627(%rip), %rsi      # 0xa132
callq 0x21e0
movq 0x48(%rsp), %r13
leaq 0x38(%rsp), %rax
cmpq %rax, %r13
je 0x8b78
movl 0x20(%r13), %esi
movq 0x54ae(%rip), %rdi      # 0xdfd8
callq 0x22a0
movq %rax, %r14
movl $0x2, %edx
movq %rax, %rdi
leaq 0x1936(%rip), %rsi      # 0xa477
callq 0x21e0
xorps %xmm0, %xmm0
cvtss2sd 0x24(%r13), %xmm0
movq %r14, %rdi
callq 0x2260
movl $0x2, %edx
movq %rax, %rdi
leaq 0x15da(%rip), %rsi      # 0xa140
callq 0x21e0
movq %r13, %rdi
callq 0x2120
movq %rax, %r13
jmp 0x8b15
movq 0x5459(%rip), %rcx      # 0xdfd8
movq (%rcx), %rax
movq -0x18(%rax), %rdi
addq %rcx, %rdi
movl $0xa, %esi
callq 0x2180
movsbl %al, %esi
movq 0x543b(%rip), %rdi      # 0xdfd8
callq 0x2030
movq %rax, %rdi
callq 0x2110
movq 0x48(%rsp), %rax
leaq 0x38(%rsp), %rcx
xorl %ebx, %ebx
cmpq %rcx, %rax
je 0x8bf2
movss 0x1515(%rip), %xmm0     # 0xa0d8
movss 0x24(%rax), %xmm1
ucomiss %xmm0, %xmm1
jbe 0x8bd0
movl 0x20(%rax), %ebx
maxss %xmm0, %xmm1
movss %xmm1, 0xc(%rsp)
movq %rax, %rdi
callq 0x2120
movss 0xc(%rsp), %xmm0
leaq 0x38(%rsp), %rcx
cmpq %rcx, %rax
jne 0x8bc3
cmpl $0x3, %ebx
ja 0x8c3b
movl %ebx, %eax
leaq 0x1a2c(%rip), %rcx      # 0xa62c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x673c
jmp 0x8c3b
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x67e4
jmp 0x8c3b
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x680c
jmp 0x8c3b
movq (%rsp), %rdi
xorl %esi, %esi
callq 0x67bc
leaq 0x30(%rsp), %rdi
callq 0x3eac
leaq 0x68(%rsp), %rdi
callq 0x3efc
movq (%rsp), %rdi
callq 0x63a6
testb %al, %al
leaq 0x18(%rsp), %rbx
jne 0x891a
movl 0x8(%rsp), %ebp
cmpl $0x1, %ebp
jg 0x8caa
movq 0x5363(%rip), %rbx      # 0xdfd8
leaq 0x1408(%rip), %rsi      # 0xa084
movl $0x5, %edx
movq %rbx, %rdi
callq 0x21e0
xorl %edx, %edx
testl %ebp, %ebp
sete %dl
leaq 0x13f3(%rip), %rax      # 0xa08a
leaq 0x13ed(%rip), %rsi      # 0xa08b
cmoveq %rax, %rsi
movq %rbx, %rdi
callq 0x21e0
testl %ebp, %ebp
movq (%rsp), %r14
jle 0x8d15
movq 0x531f(%rip), %rbx      # 0xdfd8
movq (%rbx), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2180
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2110
movq %rax, %rdi
movq %r14, %rsi
callq 0x7287
movq %rax, %rbx
movq (%rax), %rax
movq -0x18(%rax), %rdi
addq %rbx, %rdi
movl $0xa, %esi
callq 0x2180
movsbl %al, %esi
movq %rbx, %rdi
callq 0x2030
movq %rax, %rdi
callq 0x2110
movq %r14, %rdi
callq 0x7228
movl (%r14), %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 0x8d43
jmp 0x8d43
jmp 0x8d48
jmp 0x8d43
movq %rax, %rbx
jmp 0x8d62
movq %rax, %rbx
jmp 0x8d58
movq %rax, %rbx
movq %r12, %rdi
callq 0x2e18
leaq 0x18(%rsp), %rdi
callq 0x3f54
leaq 0x30(%rsp), %rdi
callq 0x3eac
leaq 0x68(%rsp), %rdi
callq 0x3efc
movq %rbx, %rdi
callq 0x22b0