Guest User

Carcion Octo Fest - Raising an Octopus to level 9/8/7/6 : Expected time

a guest
Sep 24th, 2025
59
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.36 KB | None | 0 0
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3.  
  4. # Simulation parameters
  5. N_TRIALS = 10000 # increase if you want tighter percentile precision
  6. RNG = np.random.default_rng(42)
  7.  
  8. # Percentiles to report (in feeds)
  9. PCTS = [1, 5, 10, 20, 30, 50, 75, 85, 95, 99]
  10.  
  11. # Success/Failure/Fled probabilities by level
  12. # fled rate = 0% for Levels 1–5 and 3% for Levels 6–8.
  13. rates = {
  14. 1: {"success": 1.00, "failure": 0.00, "fled": 0.00},
  15. 2: {"success": 0.70, "failure": 0.30, "fled": 0.00},
  16. 3: {"success": 0.55, "failure": 0.45, "fled": 0.00},
  17. 4: {"success": 0.40, "failure": 0.60, "fled": 0.00},
  18. 5: {"success": 0.307, "failure": 0.693, "fled": 0.00},
  19. 6: {"success": 0.205, "failure": 0.765, "fled": 0.03},
  20. 7: {"success": 0.153, "failure": 0.817, "fled": 0.03},
  21. 8: {"success": 0.10, "failure": 0.87, "fled": 0.03},
  22. }
  23.  
  24. def one_trial_feeds_to_goal(goal_level: int, max_feeds: int = None, rng=RNG):
  25. """
  26. Simulate one run starting at level 1.
  27. Count feeds only (no minutes). Startup has zero feeds.
  28. Each feed:
  29. - Success: level += 1
  30. - Failure: level -= 1, but not below Lv.2 (if level is 2, stays at 2)
  31. - Fled: reset to Lv.2
  32. Returns:
  33. - feeds_used (int) if goal reached
  34. - If max_feeds is provided and reached without hitting goal, returns None and final_level_after_max_feeds
  35. """
  36. level = 1
  37. feeds = 0
  38.  
  39. def step_from_level(lvl):
  40. p_s = rates[lvl]["success"]
  41. p_f = rates[lvl]["failure"]
  42. r = rng.random()
  43. if r < p_s:
  44. return "success"
  45. elif r < p_s + p_f:
  46. return "failure"
  47. else:
  48. return "fled"
  49.  
  50. if goal_level <= 1:
  51. return 0, None # already at goal with zero feeds
  52.  
  53. while True:
  54. if max_feeds is not None and feeds >= max_feeds:
  55. return None, level
  56.  
  57. feeds += 1
  58. outcome = step_from_level(level)
  59.  
  60. if outcome == "success":
  61. level += 1
  62. elif outcome == "failure":
  63. if level > 2:
  64. level -= 1
  65. else:
  66. level = 2
  67. else: # fled
  68. level = 2
  69.  
  70. if level >= goal_level:
  71. return feeds, None
  72.  
  73. def simulate(goal_level: int, n_trials: int = N_TRIALS, rng=RNG):
  74. feeds_arr = np.empty(n_trials, dtype=np.int32)
  75. for i in range(n_trials):
  76. f, _ = one_trial_feeds_to_goal(goal_level, max_feeds=None, rng=rng)
  77. feeds_arr[i] = f
  78. return feeds_arr
  79.  
  80. def simulate_censored(goal_level: int, feeds_limit: int, n_trials: int = N_TRIALS, rng=RNG):
  81. """
  82. Run Monte Carlo with a cap on number of feeds.
  83. Returns:
  84. - feeds_to_goal for runs that hit goal within feeds_limit
  85. - final levels for runs that do NOT hit goal within feeds_limit
  86. """
  87. hit_feeds = []
  88. not_hit_levels = []
  89. for _ in range(n_trials):
  90. f, lvl = one_trial_feeds_to_goal(goal_level, max_feeds=feeds_limit, rng=rng)
  91. if f is not None:
  92. hit_feeds.append(f)
  93. else:
  94. not_hit_levels.append(lvl)
  95. return np.array(hit_feeds, dtype=np.int32), np.array(not_hit_levels, dtype=np.int32)
  96.  
  97. def percentiles(feeds: np.ndarray, ps=PCTS):
  98. return {p: np.percentile(feeds, p) for p in ps}
  99.  
  100. def report(goal_level: int, feeds_limit: int = 100, n_trials: int = N_TRIALS, rng=RNG, show_plot=True):
  101. print(f"=== Goal Level {goal_level} ===")
  102. # Uncensored distribution
  103. feeds_to_goal = simulate(goal_level, n_trials=n_trials, rng=rng)
  104. # Percentiles in feeds
  105. pct = percentiles(feeds_to_goal)
  106. for p in PCTS:
  107. print(f"{p}% chance within {pct[p]:.0f} feeds")
  108.  
  109. # Censored at feeds_limit for median level not reaching goal
  110. hit_feeds, not_hit_levels = simulate_censored(goal_level, feeds_limit, n_trials=n_trials, rng=rng)
  111. if len(not_hit_levels) > 0:
  112. median_level_not_hit = int(np.median(not_hit_levels))
  113. print(f"Median level reached if you don't reach level {goal_level} after {feeds_limit} feeds: {median_level_not_hit}")
  114. else:
  115. print(f"All runs reached level {goal_level} within {feeds_limit} feeds (no censored cases).")
  116.  
  117. # Plot PDF, mark 100 feeds
  118. if show_plot:
  119. plt.figure(figsize=(9,5))
  120. bins = 80
  121. plt.hist(feeds_to_goal, bins=bins, density=True, alpha=0.6, color='steelblue', edgecolor='black')
  122. plt.axvline(feeds_limit, color='red', linestyle='--', linewidth=2, label=f"{feeds_limit} feeds")
  123. plt.title(f"Probability Distribution Function of Feeds to Reach Level {goal_level}")
  124. plt.xlabel("Feeds")
  125. plt.ylabel("Probability Density")
  126. plt.legend()
  127. plt.tight_layout()
  128. plt.show()
  129.  
  130. return {
  131. "feeds_to_goal": feeds_to_goal,
  132. "percentiles": pct,
  133. "hit_feeds_within_limit": hit_feeds,
  134. "not_hit_levels_within_limit": not_hit_levels
  135. }
  136.  
  137. if __name__ == "__main__":
  138. # Goal = level 9
  139. res9 = report(goal_level=9, feeds_limit=100, n_trials=N_TRIALS, rng=RNG, show_plot=True)
  140. # Goal = level 8
  141. res8 = report(goal_level=8, feeds_limit=100, n_trials=N_TRIALS, rng=RNG, show_plot=True)
  142. # Goal = level 7
  143. res7 = report(goal_level=7, feeds_limit=100, n_trials=N_TRIALS, rng=RNG, show_plot=True)
  144. # Goal = level 6
  145. res6 = report(goal_level=6, feeds_limit=100, n_trials=N_TRIALS, rng=RNG, show_plot=True)
Advertisement
Add Comment
Please, Sign In to add comment