Two questions about style and some simple math

S

Spoofy

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.

Any tips would be greatly appreciated.

2.

For maintaining the character attributes I creates a seperate class.
I wonder weather this is an "overuse" of OO (instead of just making
the attributes plain variables of the Char class) and if the way I
wrote this is OK (somehow this looks cool to me but maybe too "showy"?)

class Attributes(object):
ATTRIBUTES = {"attack": 0, "defence": 0, "ability": 0,
"courage": 0, "condition": 0}
def __init__(self, **kwargs):
self.__dict__.update(self.ATTRIBUTES)
for arg in kwargs:
if arg not in self.ATTRIBUTES:
raise ValueError("Unkown character attribute '%s'"
% arg)
self.__dict__[arg] = kwargs[arg]


Again, I appreciate any tips. I you need more code (for the bigger
picture or such), just ask.

Thanks in advance
 
J

John Machin

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
by whether the courages are (say) about 10 or about 100.

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:
.... assert abs(diff) <= maxc
.... return random.randint(-maxc, maxc-1) >= diff
........ return sum(choosep2(diff, maxc) for _ in range(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
 
J

J Kenneth King

Spoofy said:
.. <snip> ..

2.

For maintaining the character attributes I creates a seperate class. I
wonder weather this is an "overuse" of OO (instead of just making the
attributes plain variables of the Char class) and if the way I wrote
this is OK (somehow this looks cool to me but maybe too "showy"?)

class Attributes(object):
ATTRIBUTES = {"attack": 0, "defence": 0, "ability": 0, "courage":
0, "condition": 0}
def __init__(self, **kwargs):
self.__dict__.update(self.ATTRIBUTES)
for arg in kwargs:
if arg not in self.ATTRIBUTES:
raise ValueError("Unkown character attribute '%s'" %
arg)
self.__dict__[arg] = kwargs[arg]


Again, I appreciate any tips. I you need more code (for the bigger
picture or such), just ask.

Thanks in advance

I think the first part has been covered well.

If you want an opinion, this class isn't "showy" at all, rather it is
ugly and unnecessary.

Firstly it's bad because:

1. ATTRIBUTES is still modifiable after insantiation. This breaks the
restriction you're expressing in __init__

2. You want to avoid modifying __dict__ directly if you can. It bypasses
the whole point of using named attributes.

What you'd really want in a case where a class has a restricted set of
attributes is __slots__. Classes defined with it have no __dict__ and
thus attributes cannot be dynamically added to them after
instanciation (a __slots__ defined class will raise an exception in this
case).

However, even in this case, it doesn't make sense to encapsulate the
attributes of your game's Character objects in this way. Your "Hero"
class should have its attributes directly associated to it: Hero.health,
Hero.defence, and so forth. If you want to encapsulate a common set of
attributes available to a "class" of objects, you'd create a "Character"
class with those general attributes, sub-class your NPC's and Hero from
it, and specialize those sub-classes as needed.

HTH,

j_king
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top