-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsim.py
More file actions
executable file
·179 lines (145 loc) · 6.38 KB
/
sim.py
File metadata and controls
executable file
·179 lines (145 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#!/usr/bin/env python
import matplotlib.pyplot as plt
import matplotlib.transforms as transforms
import numpy as np
from random import random
import statistics
# The class and tier to be simulated
CLASS = 4
TIER = 3
# Average price you expect to spend per item
ITEM_COST = 1000000
# If set to non-zero value, will include transferring down to another item in the costs
# i.e. if TIER = 4, this will calculate making a T5 base and transferring onto a T4
TRANSFER_ITEM_COST = 0
CONVERGENCE_TRANSFER = False
# Average price you expect to spend per sliver
SLIVER_COST = 5000
CORE_COST = SLIVER_COST * 50
GOLD_FEES = [[25000],
[750000, 5000000],
[4000000, 10000000, 20000000],
[8000000, 20000000, 40000000, 65000000, 100000000, 250000000, 750000000,
2500000000, 8000000000, 15000000000]]
CONVERGENCE_GOLD_FEES = [65000000, 165000000, 375000000, 800000000, 2000000000,
5250000000, 14500000000, 42500000000, 100000000000, 300000000000]
TRANSFER_CORES = [1, 2, 5, 10, 15, 25, 35, 50, 100] # the last 4 are guesses
# Estimated values for the bonus refund effects
DUST_REFUND = 1 / 6
CORE_REFUND = 1 / 20
ITEM_REFUND = 1 / 25
GOLD_REFUND = 1 / 100
DOWNGRADED_ITEM_REFUND = 1 / 250
UPGRADED_ITEM_REFUND = 1 / 1000
SIMULATION_ROUNDS = 10000
def main():
results = [sim_one_round(CLASS, TIER, CONVERGENCE_TRANSFER) for i in range(SIMULATION_ROUNDS)]
total_costs = [(ITEM_COST * i[0] + TRANSFER_ITEM_COST + CORE_COST * i[2] + i[3]) / 1000000 for i in results]
item_counts = [i[0] for i in results]
gold_counts = [i[3] / 1000000 for i in results]
dusts = [i[1] for i in results]
avg_dust = sum(dusts) / len(dusts)
avg_cost = sum(total_costs) / len(total_costs)
min_cost = int(min(total_costs))
max_cost = int(max(total_costs))
std_dev = statistics.stdev(total_costs)
print(f'Base: {ITEM_COST / 1000000}kk, convergence: {CONVERGENCE_TRANSFER}')
print(f'mean dust: {avg_dust}')
print(f'mean item count: {sum(item_counts) / len(item_counts)}')
print(f'mean gold fees: {sum(gold_counts) / len(gold_counts)}kk')
print(f'mean total cost: {(avg_cost)}kk')
print(f'standard deviation: {std_dev}kk')
plot(total_costs, avg_cost, min_cost, max_cost)
def plot(total_costs, avg_cost, min_cost, max_cost):
graph_end = int(np.percentile(total_costs, 100 - 1000 / SIMULATION_ROUNDS))
bin_size = max(1, (graph_end - min_cost) // 150)
bins = range(min_cost, graph_end, bin_size)
fig, ax = plt.subplots()
plt.hist(total_costs, density=True, bins=bins, color='#A0E0F0')
plt.yticks([])
quartiles = [1, 10, 25]
quartiles.append(50)
upper_quartiles = [100 - x for x in quartiles[:-1]]
upper_quartiles.reverse()
quartiles += upper_quartiles
min_height = 0.08
heights = [min_height] * len(quartiles)
for i in range(len(quartiles) // 2):
heights[i] *= i + 1
heights[len(quartiles) - 1 - i] *= i + 1
heights[len(quartiles) // 2] *= len(quartiles) // 2 + 1
mean_height = max(heights) + min_height
trans = transforms.blended_transform_factory(ax.transData, ax.transAxes)
print('percentiles:')
i = 0
for q in np.percentile(total_costs, quartiles):
print(f'{quartiles[i]}%: {int(q)}kk')
plt.axvline(q, ymax=heights[i], linewidth=2, color='orange')
plt.text(q, heights[i] + 0.01, f'{quartiles[i]}%\n{int(q)}kk', size=12, weight='bold', ha='center', transform=trans)
i += 1
plt.axvline(avg_cost, ymax=mean_height, linewidth=2, color='red')
plt.text(avg_cost, mean_height + 0.01, f'mean\n{int(avg_cost)}kk', size=12, weight='bold', ha='center', transform=trans)
plt.title(f'Class {CLASS}, Tier {TIER}', fontsize=30)
fig.set_size_inches(18.5, 10.5)
fig.savefig('fig.png', dpi=100, bbox_inches = 'tight')
plt.show()
def sim_one_round(classif, tier, convergence):
if TRANSFER_ITEM_COST > 0: tier += 1
if convergence: tier -= 1
item_count = 0
dust = 0
cores = 0
gold = 0
items = [0] * (tier + 1)
while True:
if items[-1] > 0: # we have finally made an item of the desired tier
break
# Loop backwards so that we only buy new T0s when we absolutely have to
for i in range(len(items) - 1, -1, -1):
if i == 0: # Add more tier 0 items if we don't have any left
if items[0] < 2:
item_count += 2 - items[0]
items[0] = 2
if items[i] >= 2: # We have two items of the same tier, attempt fusion
dust += 100
gold += GOLD_FEES[classif - 1][i]
# Decide whether to use cores
cores_used = 0
if classif < 4 and (GOLD_FEES[classif - 1][i] + ITEM_COST) * 0.15 < CORE_COST:
p_success = 0.5
else:
p_success = 0.65
cores_used += 1
if classif < 4 and i == 0 and ITEM_COST * (1 - p_success) * 0.5 < CORE_COST:
p_tier_loss = 1
else:
p_tier_loss = 0.5
cores_used += 1
cores += cores_used
if random() > p_success: # failed fusion
if random() < p_tier_loss: # tier loss
items[i] -= 1
if i > 0: # If an item is tier 0, it's destroyed, not reduced in tier
items[i - 1] += 1
else: # successful fusion, check for bonus refunds
if random() < DUST_REFUND: dust -= 100
elif random() < CORE_REFUND: cores -= cores_used
elif random() < GOLD_REFUND: gold -= GOLD_FEES[classif - 1][i]
elif random() < DOWNGRADED_ITEM_REFUND and i > 0: items[i - 1] += 1
elif random() < ITEM_REFUND: items[i] += 1
elif random() < UPGRADED_ITEM_REFUND: items[i + 1] += 1
items[i] -= 2
items[i + 1] += 1
break
if TRANSFER_ITEM_COST > 0:
if convergence:
dust += 160
cores += TRANSFER_CORES[tier - 1]
gold += CONVERGENCE_GOLD_FEES[tier - 1]
else:
dust += 100
cores += TRANSFER_CORES[tier - 2]
gold += GOLD_FEES[classif - 1][tier - 1]
return (item_count, dust, cores, gold)
if __name__ == '__main__':
main()