2 """Faithful translations of calculations the games make."""
3 from __future__
import division
5 from itertools
import izip
10 Thanks for the "compact" solution go to:
11 http://stackoverflow.com/questions/2096573/counting-combinations-and-permutations-efficiently
15 lambda x
, y
: x
* y
[0] / y
[1],
16 izip(xrange(n
- r
+ 1, n
+ 1),
21 def calculated_stat(base_stat
, level
, iv
, effort
):
22 """Returns the calculated stat -- i.e. the value actually shown in the game
23 on a Pokémon's status tab.
26 # Remember: this is from C; use floor division!
27 return (base_stat
* 2 + iv
+ effort
// 4) * level
// 100 + 5
29 def calculated_hp(base_hp
, level
, iv
, effort
):
30 """Similar to `calculated_stat`, except with a slightly different formula
31 used specifically for HP.
34 # Shedinja's base stat of 1 is special; its HP is always 1
38 return (base_hp
* 2 + iv
+ effort
// 4) * level
// 100 + 10 + level
40 def earned_exp(base_exp
, level
):
41 """Returns the amount of EXP earned when defeating a Pokémon at the given
45 return base_exp
* level
// 7
47 def capture_chance(percent_hp
, capture_rate
,
48 ball_bonus
=1, status_bonus
=1, heavy_modifier
=0):
49 """Calculates the chance that a Pokémon will be caught, given its capture
50 rate and the percentage of HP it has remaining.
52 Returns five values: the chance of a capture, then the chance of the ball
53 shaking three, two, one, or zero times. Each of these is a float such that
54 0.0 <= n <= 1.0. Feel free to ignore all but the first.
58 # Only used by Heavy Ball. Changes the target's capture rate outright
59 capture_rate
+= heavy_modifier
63 # This should really be integer math, right? But the formula uses FOURTH
64 # ROOTS in a moment, so it can't possibly be. It probably doesn't matter
65 # either way, so whatever; use regular ol' division. ball_bonus and
66 # status_bonus can be 1.5, anyway.
69 # The formula is originally: (3 max - 2 curr) rate bonus / (3 max)
70 # I have reduced this to: (1 - 2/3 * pct) rate bonus
71 # My rationale is that this cannot possibly be integer math, so rounding is
72 # not a problem and commutation won't make a difference. It also
73 # simplifies the input considerably.
74 base_chance
= (1 - 2/3 * percent_hp
) * capture_rate \
75 * ball_bonus
* status_bonus
77 shake_index
= (base_chance
/ 255) ** 0.25 * (2**16 - 1)
79 # Iff base_chance < 255, then shake_index < 65535.
80 # The game now picks four random uwords. However many of them are <=
81 # shake_index is the number of times the ball will shake. If all four are
82 # <= shake_index, the Pokémon is caught.
84 # If shake_index >= 65535, all four randoms must be <= it, and the Pokémon
85 # will be caught. Skip hard math
86 if shake_index
>= 65535:
87 return (1.0, 0.0, 0.0, 0.0, 0.0)
89 # This brings up an interesting invariant: sum(return_value) == 1.0.
90 # Something is guaranteed to happen.
92 # Alrighty. Here's some probability.
93 # The chance that a single random number will be <= shake_index is:
94 p
= (shake_index
+ 1) / 65536
95 # Now, the chance that two random numbers will be <= shake_index is p**2.
96 # And the chance that neither will be is (1 - p)**2.
98 # The chance that one will be and one will NOT be is p * (1 - p) * 2.
99 # The 2 is because they can go in any order: the first could be less, or
100 # the second could be less. That 2 is actually nCr(2, 1); the number of
101 # ways of picking one item in any order from a group of two.
102 # Try it yourself add up those three values and you'll get 1.
104 # Right. Hopefully, the following now makes sense.
105 # There are five cases: four randoms are <= shake_index (which means
106 # capture), or three are, etc.
108 p
**i
* (1 - p
)**(4 - i
) * nCr(4, i
)
109 for i
in reversed(range(5))