Skip to content

Instantly share code, notes, and snippets.

@taylorthurlow
Created January 29, 2026 17:15
Show Gist options
  • Select an option

  • Save taylorthurlow/b31e9d348d4bd2431640178f72cdecc0 to your computer and use it in GitHub Desktop.

Select an option

Save taylorthurlow/b31e9d348d4bd2431640178f72cdecc0 to your computer and use it in GitHub Desktop.
Calculate the average number of chests required to obtain N number of unique barrows pieces
#!/usr/bin/env ruby
brothers = %i[ahrim karil dharok verac torag guthan]
categories = %i[helm body legs weapon]
@items = brothers
.product(categories)
.map { |(brother, category)| :"#{brother} #{category}" }
.sort
@brothers_killed = 6
puts "Brother kill count: #{@brothers_killed}"
@probability_of_unique = 1 / (450 - (58 * @brothers_killed)).to_f
@roll_fractional_base = (1 / @probability_of_unique).to_i
puts "Probability of unique: 1 in #{@roll_fractional_base}"
@roll_for_unique = ->(excluded_items) {
if rand(1..@roll_fractional_base) == 1
(@items - excluded_items).sample
end
}
def loot_chest
chest_loot = []
(@brothers_killed + 1).times do
if (roll_loot = @roll_for_unique.call(chest_loot))
chest_loot << roll_loot
end
end
chest_loot
end
run_limit = 100_000
all_finished_at = {}
total_runs = 0
num_uniques_to_stop = @items.count
loop do # Multiple-sample run loop (experiment)
kc = 0
current_items = []
finished_at = {}
loop do # Single sample run loop (get all items at least once)
current_items += loot_chest
kc += 1
if (uniques_count = current_items.uniq.count) > 0 && !finished_at[uniques_count]
finished_at[uniques_count] ||= []
finished_at[uniques_count] << kc
end
break if current_items.uniq.count == num_uniques_to_stop
end
total_runs += 1
all_finished_at.merge!(finished_at) do |key, old_value, new_value|
old_value + new_value
end
if total_runs % 1000 == 0
puts "After #{total_runs} samples (min/max/avg):"
all_finished_at.sort.each do |uniques_count, kc_array|
puts " #{uniques_count} => #{kc_array.min}/#{kc_array.max}/#{kc_array.sum / kc_array.size}"
end
end
break if total_runs == run_limit
end
@taylorthurlow
Copy link
Author

After 64000 samples (min/max/avg):
  1 => 1/168/15
  2 => 1/206/30
  3 => 1/306/46
  4 => 3/311/62
  5 => 8/360/80
  6 => 9/396/98
  7 => 14/420/117
  8 => 25/437/138
  9 => 28/469/160
  10 => 33/509/183
  11 => 39/636/208
  12 => 54/733/235
  13 => 59/740/264
  14 => 60/811/296
  15 => 69/896/331
  16 => 107/932/370
  17 => 70/1040/414
  18 => 81/1134/464
  19 => 134/1393/522
  20 => 147/1558/592
  21 => 180/1823/680
  22 => 242/2177/796
  23 => 245/2681/971
  24 => 292/4921/1324

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment