// File: /workspace/github_cpp_makefile_star2_O2/NathanWine[P]2048-AI-Solvers/src/Main.cpp
// Function: main
int main(int argc, char** argv) {
    enum ALGORITHMS {MONTECARLO, MINIMAX, EXPECTIMAX};
    std::map<std::string, int> alg_map = {{"montecarlo", MONTECARLO}, {"minimax", MINIMAX}, {"expectimax", EXPECTIMAX}};
    int alg_key = MINIMAX;
    int num_games = 1;
    int num_runs = 25;
    int depth = 1;
    int print_level = 2;

    // Parse command-line arguments
    CmdParser cmd_parser(argc, argv);
    if (cmd_parser.cmdOptionExists("-h") || cmd_parser.cmdOptionExists("--help") 
            || cmd_parser.cmdOptionExists("help") || cmd_parser.cmdOptionExists("usage")) {
        std::string msg = "Usage:\
            \n  AISolver <flag> <flag_val> ...\
            \n  Flag list:\
            \n    -a: Integer/String value; Algorithm to run. 0=montecarlo, 1=minimax, 2=expectimax\
            \n    -n: Integer value; # times to run the algorithm. Stats displayed at program completion\
            \n    -r: Integer value; # runs MonteCarlo completes for each move. Higher=better but slower. Recommend 10-100\
            \n    -d: Integer value; # depth level for Minimax / Expectimax\
            \n    -p: Integer value; Print level. Higher=more display. 0=minimal, 1=medium, 2=high, 3=full\
            \n  Ex: AISolver -a minimax -n 1 -d 1 -p 3";
        std::cout << msg << std::endl;
        return 0;
    }
    if (cmd_parser.cmdOptionExists("-a")) {
        std::string a_arg = cmd_parser.getCmdOption("-a");
        if (isNumber(a_arg)) {
            alg_key = std::stoi(a_arg);
        }
        else {
            lowercase(a_arg);
            alg_key = alg_map[a_arg];
        }
    }
    if (cmd_parser.cmdOptionExists("-n")) {
        std::string n_option = cmd_parser.getCmdOption("-n");
        if (isNumber(n_option)) {
            num_games = std::stoi(n_option);
        }
    }
    if (cmd_parser.cmdOptionExists("-r")) {
        std::string r_option = cmd_parser.getCmdOption("-r");
        if (isNumber(r_option)) {
            num_runs = std::stoi(r_option);
        }
    }
    if (cmd_parser.cmdOptionExists("-d")) {
        std::string d_option = cmd_parser.getCmdOption("-d");
        if (isNumber(d_option)) {
            depth = std::stoi(d_option);
        }
    }
    if (cmd_parser.cmdOptionExists("-p")) {
        std::string p_option = cmd_parser.getCmdOption("-p");
        if (isNumber(p_option)) {
            print_level = std::stoi(p_option);
        }
    }

    // Set up variables for statistics
    int successes = 0;
    std::vector<int> scores;
    std::vector<int> highest_tiles;
    high_resolution_clock::time_point t1 = high_resolution_clock::now();
    switch (alg_key) {          // Run chosen algorithm
        case MONTECARLO:
            successes = monteCarloSolve(num_games, num_runs, print_level, scores, highest_tiles);
            break;
        case MINIMAX:
            successes = minimaxSolve(num_games, depth, print_level, scores, highest_tiles);
            break;
        case EXPECTIMAX:
            successes = expectimaxSolve(num_games, depth, print_level, &scores, &highest_tiles);
    }
    high_resolution_clock::time_point t2 = high_resolution_clock::now();
    duration<double> time_span = duration_cast<duration<double>>(t2 - t1);

    // Display statistics
    if (num_games > 1) {
        std::cout << "Success rate: " << (float) successes / num_games * 100 << "%" << std::endl;
        float average = std::accumulate(scores.begin(), scores.end(), 0.0) / num_games;
        std::cout << "Average score: " << average << std::endl;
        std::cout << "Highest tiles: ";
        for (int i = 0; i < (int) highest_tiles.size(); ++i) {
            std::cout << highest_tiles[i] << ", ";
        }
        std::cout << std::endl;
    }
    else {
        std::cout << (successes > 0 ? "Game won!" : "Game lost.") << std::endl;
        std::cout << "Final score: " << scores[0] << std::endl;
        std::cout << "Highest tile: " << highest_tiles[0] << std::endl;
    }
    std::cout << "Time elapsed: " << time_span.count() << " seconds" << std::endl;

    return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x138, %rsp            # imm = 0x138
movq %rsi, %rbx
movl %edi, 0xbc(%rsp)
movq %rsp, %rdx
andl $0x0, (%rdx)
leaq 0x428b(%rip), %rsi      # 0x8154
leaq 0x40(%rsp), %r14
movq %r14, %rdi
callq 0x47ae
leaq 0x68(%rsp), %r15
leaq 0x427d(%rip), %rsi      # 0x815f
leaq 0xc0(%rsp), %rdx
movq %r15, %rdi
callq 0x48c4
leaq 0x90(%rsp), %r15
movl $0x1, -0x8(%r15)
leaq 0xc0(%rsp), %rdx
movl $0x2, (%rdx)
leaq 0x4250(%rip), %rsi      # 0x8167
movq %r15, %rdi
callq 0x47ae
leaq 0x108(%rsp), %rdi
leaq 0x40(%rsp), %rsi
pushq $0x3
popq %rdx
leaq 0xe8(%rsp), %rcx
leaq 0x28(%rsp), %r8
callq 0x47d0
pushq $0x50
popq %r14
leaq (%rsp,%r14), %rdi
addq $0x40, %rdi
callq 0x2318
addq $-0x28, %r14
cmpq $-0x28, %r14
jne 0x3f45
leaq 0x28(%rsp), %rdi
leaq 0xbc(%rsp), %rsi
movq %rbx, %rdx
callq 0x4818
leaq 0x41fa(%rip), %rsi      # 0x8172
leaq 0x40(%rsp), %rdi
leaq 0x27(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48a8
testb %al, %al
jne 0x4007
leaq 0x41d4(%rip), %rsi      # 0x8175
movq %rsp, %rdi
leaq 0x26(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
movq %rsp, %rsi
callq 0x48a8
testb %al, %al
jne 0x3fff
leaq 0x41b1(%rip), %rsi      # 0x8177
leaq 0xc0(%rsp), %rdi
leaq 0x25(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0xc0(%rsp), %rsi
callq 0x48a8
testb %al, %al
je 0x4073
leaq 0xc0(%rsp), %rdi
callq 0x2318
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x2318
leaq 0x416a(%rip), %rsi      # 0x8182
leaq 0x40(%rsp), %rdi
movq %rsp, %rdx
callq 0x48c4
movq 0x8fa4(%rip), %rdi      # 0xcfd0
leaq 0x40(%rsp), %rsi
callq 0x2190
movq %rax, %rdi
callq 0x20d0
leaq 0x40(%rsp), %rdi
callq 0x2318
leaq 0x28(%rsp), %rdi
callq 0x4a4a
leaq 0x108(%rsp), %rdi
callq 0x4e6e
xorl %eax, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x4102(%rip), %rsi      # 0x817c
leaq 0xe8(%rsp), %rdi
leaq 0x24(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0xe8(%rsp), %rsi
callq 0x48a8
movl %eax, %ebx
leaq 0xe8(%rsp), %rdi
callq 0x2318
leaq 0xc0(%rsp), %rdi
callq 0x2318
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x2318
testb %bl, %bl
jne 0x4011
leaq 0x431e(%rip), %rsi      # 0x83f9
leaq 0x40(%rsp), %rdi
movq %rsp, %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48a8
movl %eax, %ebx
leaq 0x40(%rsp), %rdi
callq 0x2318
testb %bl, %bl
je 0x4161
leaq 0x42eb(%rip), %rsi      # 0x83f9
movq %rsp, %rdi
leaq 0xc0(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
movq %rsp, %rsi
callq 0x4900
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2210
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x3e4c
testb %al, %al
je 0x4166
leaq 0x40(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x49b3
movl %eax, %ebp
jmp 0x4185
pushq $0x1
popq %rbp
jmp 0x418f
leaq 0x40(%rsp), %rbx
movq %rbx, %rdi
callq 0x3e74
leaq 0x108(%rsp), %rdi
movq %rbx, %rsi
callq 0x49d0
movl (%rax), %ebp
leaq 0x40(%rsp), %rdi
callq 0x2318
leaq 0x4266(%rip), %rsi      # 0x83fc
leaq 0x40(%rsp), %rdi
movq %rsp, %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48a8
movl %eax, %ebx
leaq 0x40(%rsp), %rdi
callq 0x2318
testb %bl, %bl
je 0x421c
leaq 0x4233(%rip), %rsi      # 0x83fc
movq %rsp, %rdi
leaq 0xc0(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
movq %rsp, %rsi
callq 0x4900
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2210
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x3e4c
testb %al, %al
je 0x4221
leaq 0x40(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x49b3
movl %eax, %ebx
jmp 0x4224
pushq $0x1
popq %rbx
jmp 0x422e
pushq $0x1
popq %rbx
leaq 0x40(%rsp), %rdi
callq 0x2318
leaq 0x41ca(%rip), %rsi      # 0x83ff
leaq 0x40(%rsp), %rdi
movq %rsp, %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48a8
movl %eax, %r14d
leaq 0x40(%rsp), %rdi
callq 0x2318
testb %r14b, %r14b
je 0x42be
leaq 0x4195(%rip), %rsi      # 0x83ff
movq %rsp, %rdi
leaq 0xc0(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
movq %rsp, %rsi
callq 0x4900
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2210
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x3e4c
testb %al, %al
je 0x42c4
leaq 0x40(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x49b3
movl %eax, %r15d
jmp 0x42c8
pushq $0x19
popq %r15
jmp 0x42d2
pushq $0x19
popq %r15
leaq 0x40(%rsp), %rdi
callq 0x2318
leaq 0x4129(%rip), %rsi      # 0x8402
leaq 0x40(%rsp), %rdi
movq %rsp, %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48a8
movl %eax, %r14d
leaq 0x40(%rsp), %rdi
callq 0x2318
testb %r14b, %r14b
je 0x4362
leaq 0x40f4(%rip), %rsi      # 0x8402
movq %rsp, %rdi
leaq 0xc0(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
movq %rsp, %rsi
callq 0x4900
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2210
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x3e4c
testb %al, %al
je 0x4368
leaq 0x40(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x49b3
movl %eax, %r12d
jmp 0x436c
pushq $0x1
popq %r12
jmp 0x4376
pushq $0x1
popq %r12
leaq 0x40(%rsp), %rdi
callq 0x2318
leaq 0x4088(%rip), %rsi      # 0x8405
leaq 0x40(%rsp), %rdi
movq %rsp, %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
leaq 0x40(%rsp), %rsi
callq 0x48a8
movl %eax, %r14d
leaq 0x40(%rsp), %rdi
callq 0x2318
testb %r14b, %r14b
je 0x4406
leaq 0x4053(%rip), %rsi      # 0x8405
movq %rsp, %rdi
leaq 0xc0(%rsp), %rdx
callq 0x48c4
leaq 0x28(%rsp), %rdi
movq %rsp, %rsi
callq 0x4900
leaq 0x40(%rsp), %rdi
movq %rax, %rsi
callq 0x2210
movq %rsp, %rdi
callq 0x2318
leaq 0x40(%rsp), %rdi
callq 0x3e4c
testb %al, %al
je 0x440c
leaq 0x40(%rsp), %rdi
pushq $0xa
popq %rdx
xorl %esi, %esi
callq 0x49b3
movl %eax, %r13d
jmp 0x4410
pushq $0x2
popq %r13
jmp 0x441a
pushq $0x2
popq %r13
leaq 0x40(%rsp), %rdi
callq 0x2318
xorps %xmm0, %xmm0
movaps %xmm0, 0x40(%rsp)
andq $0x0, 0x50(%rsp)
movaps %xmm0, (%rsp)
andq $0x0, 0x10(%rsp)
callq 0x2050
movq %rax, %r14
cmpl $0x2, %ebp
je 0x4479
cmpl $0x1, %ebp
je 0x4462
xorl %r12d, %r12d
testl %ebp, %ebp
jne 0x4491
leaq 0x40(%rsp), %rcx
movq %rsp, %r8
movl %ebx, %edi
movl %r15d, %esi
movl %r13d, %edx
callq 0x293d
jmp 0x448e
leaq 0x40(%rsp), %rcx
movq %rsp, %r8
movl %ebx, %edi
movl %r12d, %esi
movl %r13d, %edx
callq 0x391f
jmp 0x448e
leaq 0x40(%rsp), %rcx
movq %rsp, %r8
movl %ebx, %edi
movl %r12d, %esi
movl %r13d, %edx
callq 0x7acf
movl %eax, %r12d
callq 0x2050
movq %rax, %r15
cmpl $0x2, %ebx
jl 0x4598
movq 0x8b27(%rip), %rdi      # 0xcfd0
leaq 0x3f58(%rip), %rsi      # 0x8408
callq 0x21b0
cvtsi2ss %r12d, %xmm0
cvtsi2ss %ebx, %xmm1
divss %xmm1, %xmm0
mulss 0x3c86(%rip), %xmm0     # 0x8150
movq %rax, %rdi
callq 0x2150
leaq 0x3f3e(%rip), %rsi      # 0x8417
movq %rax, %rdi
callq 0x21b0
movq %rax, %rdi
callq 0x20d0
movq 0x40(%rsp), %rdi
movq 0x48(%rsp), %rsi
xorps %xmm0, %xmm0
callq 0x4a36
movsd %xmm0, 0xe0(%rsp)
movq 0x8ac5(%rip), %rdi      # 0xcfd0
leaq 0x3f07(%rip), %rsi      # 0x8419
callq 0x21b0
cvtsi2sd %ebx, %xmm0
movsd 0xe0(%rsp), %xmm1
divsd %xmm0, %xmm1
cvtsd2ss %xmm1, %xmm0
movq %rax, %rdi
callq 0x2150
movq %rax, %rdi
callq 0x20d0
movq 0x8a8d(%rip), %rdi      # 0xcfd0
leaq 0x3edf(%rip), %rsi      # 0x8429
callq 0x21b0
xorl %r13d, %r13d
movq 0x8a77(%rip), %rbx      # 0xcfd0
leaq 0x3be0(%rip), %r12      # 0x8140
movq (%rsp), %rax
movq 0x8(%rsp), %rcx
subq %rax, %rcx
shrq $0x2, %rcx
movslq %ecx, %rcx
cmpq %rcx, %r13
jge 0x4616
movl (%rax,%r13,4), %esi
movq %rbx, %rdi
callq 0x22b0
movq %rax, %rdi
movq %r12, %rsi
callq 0x21b0
incq %r13
jmp 0x4560
testl %r12d, %r12d
leaq 0x3e97(%rip), %rax      # 0x8439
leaq 0x3e9a(%rip), %rsi      # 0x8443
cmovgq %rax, %rsi
movq 0x8a1c(%rip), %rdi      # 0xcfd0
callq 0x21b0
movq %rax, %rdi
callq 0x20d0
movq 0x8a08(%rip), %rdi      # 0xcfd0
leaq 0x3e7f(%rip), %rsi      # 0x844e
callq 0x21b0
movq 0x40(%rsp), %rcx
movl (%rcx), %esi
movq %rax, %rdi
callq 0x22b0
movq %rax, %rdi
callq 0x20d0
movq 0x89de(%rip), %rdi      # 0xcfd0
leaq 0x3e63(%rip), %rsi      # 0x845c
callq 0x21b0
movq (%rsp), %rcx
movl (%rcx), %esi
movq %rax, %rdi
callq 0x22b0
movq %rax, %rdi
callq 0x20d0
jmp 0x4622
movq 0x89b3(%rip), %rdi      # 0xcfd0
callq 0x20d0
movq 0x89a7(%rip), %rdi      # 0xcfd0
leaq 0x3e3b(%rip), %rsi      # 0x846b
callq 0x21b0
subq %r14, %r15
cvtsi2sd %r15, %xmm0
divsd 0x3b03(%rip), %xmm0     # 0x8148
movq %rax, %rdi
callq 0x2270
leaq 0x3e26(%rip), %rsi      # 0x847a
movq %rax, %rdi
callq 0x21b0
movq %rax, %rdi
callq 0x20d0
movq %rsp, %rdi
callq 0x2e28
leaq 0x40(%rsp), %rdi
callq 0x2e28
jmp 0x4048
jmp 0x476b
jmp 0x476b
jmp 0x476b
jmp 0x476b
jmp 0x4724
jmp 0x4724
jmp 0x4724
jmp 0x4724
jmp 0x476b
jmp 0x4724
jmp 0x477a
jmp 0x46d3
jmp 0x476b
jmp 0x4724
jmp 0x46d3
jmp 0x476b
jmp 0x4724
jmp 0x46d3
jmp 0x476b
jmp 0x4724
jmp 0x46d3
jmp 0x476b
jmp 0x4724
movq %rax, %rbx
movq %rsp, %rdi
jmp 0x4773
jmp 0x476b
jmp 0x4724
movq %rax, %rbx
leaq 0xe8(%rsp), %rdi
callq 0x2318
jmp 0x46fe
jmp 0x46fb
jmp 0x477a
movq %rax, %rbx
leaq 0xc0(%rsp), %rdi
callq 0x2318
jmp 0x4712
jmp 0x470f
movq %rax, %rbx
movq %rsp, %rdi
callq 0x2318
jmp 0x476e
jmp 0x476b
jmp 0x477a
jmp 0x4724
jmp 0x476b
movq %rax, %rbx
jmp 0x478f
movq %rax, %rbx
jmp 0x4799
movq %rax, %rbx
pushq $0x50
popq %r14
leaq (%rsp,%r14), %rdi
addq $0x40, %rdi
callq 0x2318
addq $-0x28, %r14
cmpq $-0x28, %r14
jne 0x4735
jmp 0x47a6
jmp 0x4750
movq %rax, %rbx
addq $-0x28, %r15
movq %r15, %rdi
callq 0x2318
cmpq %r14, %r15
jne 0x4753
jmp 0x47a6
movq %rax, %rbx
jmp 0x47a6
movq %rax, %rbx
leaq 0x40(%rsp), %rdi
callq 0x2318
jmp 0x478f
movq %rax, %rbx
movq %rsp, %rdi
callq 0x2e28
leaq 0x40(%rsp), %rdi
callq 0x2e28
leaq 0x28(%rsp), %rdi
callq 0x4a4a
leaq 0x108(%rsp), %rdi
callq 0x4e6e
movq %rbx, %rdi
callq 0x22c0