// File: /workspace/github_cpp_makefile_star2_O2/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 $0xac8, %rsp            # imm = 0xAC8
movaps 0x1dba(%rip), %xmm0     # 0x6060
leaq 0xd0(%rsp), %rdx
movaps %xmm0, (%rdx)
movabsq $0x3f947ae147ae147b, %rax # imm = 0x3F947AE147AE147B
movq %rax, 0x10(%rdx)
movl $0x2, 0x18(%rdx)
leaq 0x2c(%rsp), %r8
movl $0x32, (%r8)
leaq 0x78(%rsp), %rcx
movq $0x5f5e100, (%rcx)      # imm = 0x5F5E100
leaq 0x70(%rsp), %r9
andq $0x0, (%r9)
callq 0x280b
testb %al, %al
je 0x4528
movq 0x78(%rsp), %r14
movl 0x2c(%rsp), %edx
movq 0x70(%rsp), %rcx
leaq 0xd0(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
movq %rdx, 0x50(%rsp)
movq %rcx, 0x48(%rsp)
callq 0x3b5a
callq 0x2420
leaq 0x100(%rsp), %rdi
movq %rax, 0x30(%rsp)
movq %rax, %rsi
callq 0x4b12
movabsq $0x3e700000000, %rax    # imm = 0x3E700000000
movq %rax, 0x80(%rsp)
andq $0x0, 0x10(%rsp)
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x5df2
movq %rax, 0x20(%rsp)
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x5dc4
movq %rax, 0x18(%rsp)
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x5e30
movl %eax, %ebx
movq %r15, %rdi
xorl %esi, %esi
movl $0x3e7, %edx            # imm = 0x3E7
callq 0x5e44
movl %eax, %r15d
leaq 0x58(%rsp), %rdi
leaq 0x98(%rsp), %rdx
movl $0x3e8, %esi            # imm = 0x3E8
callq 0x4760
leaq 0xc8(%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 0x6bf0(%rip), %rdi      # 0xafd0
leaq 0x31d2(%rip), %rsi      # 0x75b9
callq 0x21a0
movq %rax, %rdi
callq 0x20c0
pushq $0x1
popq %rdi
leaq 0x88(%rsp), %rsi
callq 0x2180
movl %ebx, %eax
movq %rax, 0x40(%rsp)
movl %r15d, %eax
movq %rax, 0x38(%rsp)
xorl %ebp, %ebp
movq 0x20(%rsp), %r15
movq 0x18(%rsp), %r13
xorl %ebx, %ebx
xorl %r12d, %r12d
subq $0x1, %r14
jb 0x44d5
leaq 0x80(%rsp), %rdi
leaq 0x100(%rsp), %rsi
callq 0x47b2
movq 0x10(%rsp), %rcx
incq %rcx
movq %rcx, 0x10(%rsp)
movl %eax, %eax
cmpq %rax, %r13
jbe 0x447b
incq %r12
cmpq %rax, %r15
jbe 0x4491
movq 0x58(%rsp), %rax
movq 0x60(%rsp), %rdx
subq %rax, %rdx
sarq $0x3, %rdx
cmpq %rdx, %rcx
jae 0x4495
leaq (%rax,%rcx,8), %rax
jmp 0x44b5
incq %rbp
cmpq 0x50(%rsp), %rbp
jb 0x4424
addq 0x40(%rsp), %r13
addq 0x38(%rsp), %r15
jmp 0x4424
xorl %ebp, %ebp
jmp 0x44c6
cmpq $0x1869f, 0xb0(%rsp) # imm = 0x1869F
ja 0x44b8
leaq 0x98(%rsp), %rdi
leaq 0x10(%rsp), %rsi
callq 0x5a5a
incq (%rax)
andq $0x0, 0x10(%rsp)
incq %rbx
movq 0x48(%rsp), %rbp
movq 0x20(%rsp), %r15
movq 0x18(%rsp), %r13
jmp 0x4424
pushq $0x1
popq %rdi
leaq 0xf0(%rsp), %r14
movq %r14, %rsi
callq 0x2180
movq %r14, (%rsp)
leaq 0x58(%rsp), %rdi
leaq 0x98(%rsp), %rsi
leaq 0x88(%rsp), %r9
movq %r12, %rdx
movq %rbx, %rcx
movq 0x30(%rsp), %r8
callq 0x3cc4
leaq 0x98(%rsp), %rdi
callq 0x49d4
leaq 0x58(%rsp), %rdi
callq 0x590a
xorl %eax, %eax
addq $0xac8, %rsp            # imm = 0xAC8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x4540
jmp 0x4540
movq %rax, %rbx
leaq 0x98(%rsp), %rdi
callq 0x49d4
leaq 0x58(%rsp), %rdi
callq 0x590a
movq %rbx, %rdi
callq 0x2290