// File: /workspace/github_cpp_makefile_star2_O3/zyLiu6707[P]Arknights-Pull-Simulation/simulation_sequential.cpp
// Function: main
int main(int argc, char* argv[]) {
  // On default, will calculate the probability of a limited banner (e.g.,
  // Nian, W and Rosmontis banner), which uses the following parameter:
  // 1. Pr(get a star6 operator): 2%
  // 2. Pr(get a on-banner star 6 operator | get a satr 6 operator): 70%
  // 3. Double rate up
  ProbabilityWrapper probability_wrapper(0.02, 0.7, 0.02, 2);

  // In Arknights, the pity system will come into effect after 50 pulls
  // if you did not get any star6 operator
  unsigned int pity_starting_point = 50;

  unsigned long long int total_pull_time = 100000000;
  unsigned long long int current_pull = 0;

  bool can_continue = process_cmd_input_and_set_corres_var(
      argc, argv, probability_wrapper, total_pull_time, pity_starting_point, current_pull);
  if (!can_continue) {
    // Exit the program here rather than exiting when argument format error is
    // found in order to avoid memory leak
    return 0;
  }

  display_simulation_settings(probability_wrapper, total_pull_time,
                              pity_starting_point, current_pull);

  auto seed = get_random_seed();
  std::mt19937_64 mt(seed);
  unsigned int dist_left_border = 0;
  unsigned int dist_right_border = 999;
  // Uniform distribution on [0, 999]
  std::uniform_int_distribution<unsigned int> dist(dist_left_border,
                                                   dist_right_border);

  // Count the times of getting a star 6 operator in total_pull_times pulling
  unsigned long long int star6_count = 0;
  // Count the times of getting the target star 6 operator in total_pull_times
  // pulling
  unsigned long long int target_star6_count = 0;
  // Count the times of countinuously getting a non-star-6 operator
  unsigned long long int pity_count = 0;
  // Count the times of pulling in a trial. Will be reset to 0 when get the
  // target star 6 operator. Theoretically, no matter how many bits used to
  // store the value of current_pull_count, there exists a non-zero probability
  // that it will overflow - but the probability will converge to zero when num
  // of bits grows to positive infinity
  unsigned long long int current_pull_count = 0;

  // The thresholds will be used to decide whether we got a star6/target star6
  // operator in a pull
  const unsigned long long int init_target_star6_threshold =
      probability_wrapper.calc_init_target_star6_threshold(dist_left_border,
                                                           dist_right_border);
  const unsigned long long int init_star6_threshold =
      probability_wrapper.calc_init_star6_threshold(dist_left_border,
                                                    dist_right_border);

  unsigned long long int target_star6_threshold = init_target_star6_threshold;
  unsigned long long int star6_threshold = init_star6_threshold;

  // The amount that the thresholds change after each failed pull when pity
  // system comes into effect
  unsigned int delta_star6_threshold =
      probability_wrapper.calc_star6_threshold_change_step(dist_left_border,
                                                           dist_right_border);
  unsigned int delta_target_star6_threshold =
      probability_wrapper.calc_target_star6_threshold_change_step(
          dist_left_border, dist_right_border);

  std::vector<unsigned long long int> result(1000);

  // Record the event that did not get a star 6 operator
  // untill pulling more than 1000 times
  std::unordered_map<unsigned long long int, unsigned long long int> rare_event;

  // To avoid the rare_event map recording too many items and consuming too
  // large memory.
  const size_t max_rare_event_map_size = 100000;  // you need to simulate
                                                  // approximately 10^13 times
                                                  // of pulling to reach this
                                                  // limit.

  std::cout << "Now will start the simulation...\n" << std::endl;

  struct timespec start;
  struct timespec end;

  clock_gettime(CLOCK_MONOTONIC, &start);

  // Start simulation
  for (unsigned long long int i = 0; i < total_pull_time; ++i) {
    unsigned int rand_num = dist(mt);
    current_pull_count++;  // leave the index 0 of result vector unused
    // Get a star-6 operator
    if (rand_num < star6_threshold) {
      star6_count++;
      pity_count = 0;
      // This star-6 operator is also your target operator
      if (rand_num < target_star6_threshold) {
        target_star6_count++;
        if (current_pull_count < result.size()) {
          result[current_pull_count]++;
        }
        else if (rare_event.size() < max_rare_event_map_size) {
          rare_event[current_pull_count]++;
        }
        current_pull_count = 0;
        // Finish currrent trial, reset the pity counter and start next trial
        pity_count = current_pull;
      }
      star6_threshold = init_star6_threshold;
      target_star6_threshold = init_target_star6_threshold;
    }
    else {
      pity_count++;
      if (pity_count >= pity_starting_point) {
        star6_threshold += delta_star6_threshold;
        target_star6_threshold += delta_target_star6_threshold;
      }
    }
  }

  clock_gettime(CLOCK_MONOTONIC, &end);

  // Print the result
  display_simulation_results(result, rare_event, star6_count,
                             target_star6_count, seed, start, end);

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xad8, %rsp            # imm = 0xAD8
movaps 0x23c2(%rip), %xmm0     # 0x7060
leaq 0xe0(%rsp), %rdx
movaps %xmm0, (%rdx)
movabsq $0x3f947ae147ae147b, %rax # imm = 0x3F947AE147AE147B
movq %rax, 0x10(%rdx)
movl $0x2, 0x18(%rdx)
leaq 0x3c(%rsp), %r8
movl $0x32, (%r8)
leaq 0x70(%rsp), %rcx
movq $0x5f5e100, (%rcx)      # imm = 0x5F5E100
leaq 0x68(%rsp), %r9
movq $0x0, (%r9)
callq 0x29c7
testb %al, %al
je 0x4fdf
movq 0x70(%rsp), %r14
movl 0x3c(%rsp), %edx
movq 0x68(%rsp), %rcx
leaq 0xe0(%rsp), %rdi
movq %r14, %rsi
movq %rdx, 0x60(%rsp)
movq %rcx, 0x58(%rsp)
callq 0x3feb
callq 0x2453
movq %rax, %rsi
movq %rax, 0x110(%rsp)
movl $0x1, %eax
movabsq $0x5851f42d4c957f2d, %rcx # imm = 0x5851F42D4C957F2D
movq %rsi, 0x40(%rsp)
movq %rsi, %rdx
shrq $0x3e, %rdx
xorq %rsi, %rdx
imulq %rcx, %rdx
addq %rax, %rdx
movq %rdx, 0x110(%rsp,%rax,8)
incq %rax
movq %rdx, %rsi
cmpq $0x138, %rax            # imm = 0x138
jne 0x4d3e
movq $0x138, 0xad0(%rsp) # imm = 0x138
movabsq $0x3e700000000, %rax    # imm = 0x3E700000000
movq %rax, 0x78(%rsp)
movq $0x0, 0x10(%rsp)
leaq 0xe0(%rsp), %r15
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x67e2
movq %rax, 0x30(%rsp)
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x67b4
movq %rax, 0x28(%rsp)
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x6820
movl %eax, %ebp
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x6834
movl %eax, %r15d
movl $0x1f40, %edi           # imm = 0x1F40
callq 0x2190
movq %rax, 0x80(%rsp)
leaq 0x1f40(%rax), %rbx
movq %rbx, 0x90(%rsp)
movl $0x1f40, %edx           # imm = 0x1F40
movq %rax, 0x18(%rsp)
movq %rax, %rdi
xorl %esi, %esi
callq 0x20c0
movq %rbx, 0x88(%rsp)
leaq 0xd8(%rsp), %rax
movq %rax, -0x30(%rax)
movq $0x1, -0x28(%rax)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, -0x10(%rax) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq 0x618d(%rip), %r12      # 0xafd0
leaq 0x379f(%rip), %rsi      # 0x85e9
movl $0x21, %edx
movq %r12, %rdi
callq 0x21c0
movq (%r12), %rax
addq -0x18(%rax), %r12
movq %r12, %rdi
movl $0xa, %esi
callq 0x2180
movsbl %al, %esi
movq 0x615a(%rip), %rdi      # 0xafd0
callq 0x2030
movq %rax, %rdi
callq 0x2100
leaq 0x98(%rsp), %rsi
movl $0x1, %edi
callq 0x2160
testq %r14, %r14
je 0x4f74
movl %ebp, %eax
movq %rax, 0x50(%rsp)
movl %r15d, %eax
movq %rax, 0x48(%rsp)
xorl %r12d, %r12d
leaq 0x78(%rsp), %rbp
movq $0x0, 0x20(%rsp)
movq 0x28(%rsp), %r13
movq 0x30(%rsp), %rbx
xorl %r15d, %r15d
movq %rbp, %rdi
leaq 0x110(%rsp), %rsi
movq %rbp, %rdx
callq 0x648c
movq 0x10(%rsp), %rcx
incq %rcx
movq %rcx, 0x10(%rsp)
movl %eax, %eax
cmpq %rax, %r13
jbe 0x4f0e
incq %r12
cmpq %rax, %rbx
jbe 0x4f24
cmpq $0x3e7, %rcx            # imm = 0x3E7
ja 0x4f29
movq 0x18(%rsp), %rax
leaq (%rax,%rcx,8), %rax
jmp 0x4f49
incq %r15
cmpq 0x60(%rsp), %r15
jb 0x4f69
addq 0x50(%rsp), %r13
addq 0x48(%rsp), %rbx
jmp 0x4f69
xorl %r15d, %r15d
jmp 0x4f5f
cmpq $0x1869f, 0xc0(%rsp) # imm = 0x1869F
ja 0x4f4c
leaq 0xa8(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x6502
incq (%rax)
incq 0x20(%rsp)
movq $0x0, 0x10(%rsp)
movq 0x58(%rsp), %r15
movq 0x30(%rsp), %rbx
movq 0x28(%rsp), %r13
decq %r14
jne 0x4ecb
jmp 0x4f80
movq $0x0, 0x20(%rsp)
xorl %r12d, %r12d
leaq 0x100(%rsp), %rbx
movl $0x1, %edi
movq %rbx, %rsi
callq 0x2160
movq %rbx, (%rsp)
leaq 0x80(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
leaq 0x98(%rsp), %r9
movq %r12, %rdx
movq 0x20(%rsp), %rcx
movq 0x40(%rsp), %r8
callq 0x41a9
leaq 0xa8(%rsp), %rdi
callq 0x5410
movl $0x1f40, %esi           # imm = 0x1F40
movq 0x18(%rsp), %rdi
callq 0x21a0
xorl %eax, %eax
addq $0xad8, %rsp            # imm = 0xAD8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x4ff7
jmp 0x4ff7
movq %rax, %rbx
leaq 0xa8(%rsp), %rdi
callq 0x5410
movl $0x1f40, %esi           # imm = 0x1F40
movq 0x18(%rsp), %rdi
callq 0x21a0
movq %rbx, %rdi
callq 0x2260