# Two questions about style and some simple math

John Machin sjmachin at lexicon.net
Tue Jan 20 03:46:43 CET 2009

```On Jan 20, 12:15 pm, Spoofy <spoo... at gmx.net> wrote:
> Hello everybody!
>
> Though I'm a hobby programmer for years now (mainly small hackery
> things) I still have big problems getting "real" things to work.
>
> I'm currently trying to write a simple RPG and have problems with
> the following:
>
> 1.
>
> Characters have a "courage" attribute that basically determins who
> has the first attack in a fight. After some trying, I came up with
> this (sorry, not really working code, but what I made from
> interactive experimentation):
>
> def first_attack(player1,  player2):
>      diff = player1.attributes.courage - player2.attributes.courage
>      players = (player,  player2)
>      return players[diff + random.randint(-diff,  diff) < 0]
>
> To make it more realistic, I randomized it a little bit and this
> seems to work for low courage values. But when the courage values
> are high (100 and such) it fails (the chance to have the first
> attack drops the higher the values are). My math is really bad and I
> have problems to understand what's happenning here. I suspect the
> greater range for randint() is the problem, but I don't really get why.

Are you 100% sure that the above code is what you have been running?

For a start, the result of that code depends only on "diff" which is
the difference between the two courages -- it should not be influenced

If player1 is more aggro than player2, then diff will be positive.
Let's say it's 20. The lowest possible value returned by random.randint
(-20, 20) will be -20. Then 20 + (-20) is zero. so 0 < 0 is False, and
player 1 will always be chosen. This happens for any positive value of
diff, even 1.

If the diff is zero, then again you get 0 < 0, and player1 will always
be chosen.

If the diff is negative, the world blows up; for diff == -10, you get
this:
ValueError: empty range for randrange() (10,-9, -19)

I think that you need to take the range of the courage values into
account. You need to scale the randomisation so that you get
believable outcomes. If the players have equal courage, there should
be a 50% chance that player2 hits first. If one has maximal courage
and the other has zero, then the maximal one should have 100% chance
of hitting first. For example:

>>> def choosep2(diff, maxc):
...    assert abs(diff) <= maxc
...    return random.randint(-maxc, maxc-1) >= diff
...
>>> def simulate(diff, maxc):
...    return sum(choosep2(diff, maxc) for _ in range(100))
...
>>> simulate(0, 50)
50
>>> simulate(0, 50)
47
>>> simulate(0, 50)
43
>>> simulate(49, 50)
1
>>> simulate(-49, 50)
100
>>>

You may want to choose a probability distribution that's a bit more
bell-shaped than roadkill-shaped, but whatever you do you should check
that it's behaving plausibly.

HTH,
John

```