# Python class assignment simplification for d&d character creator

As some of you may know, part of creating, or leveling up a character in almost any game is ability score increases. In this example, the character has six abilities with preassigned scores: strength, dexterity, intelligence, wisdom, charisma, and constitution. Users of the code have the option of choosing to level up one score by 2 points, or two different scores by one each.

The code I have works, and it works well, however, I realize that it's bulky, ugly, and probably a sin for python to be running it. Can you help me simplify/streamline it? Thank you

def ability(self):
choice = raw_input("leveling up: do you want to increase 'one' score by two, or 'two' scores by one each?")
if choice == "one":
score = raw_input("which ability do you want to increase by two?")
if score == "strength":
self.strength = self.strength + 2
elif score == "dexterity":
self.dexterity = self.dexterity + 2
elif score == "intelligence":
self.intelligence = self.intelligence + 2
elif score == "wisdom":
self.wisdom = self.wisdom + 2
elif score == "charisma":
self.charisma = self.charisma + 2
else:
self.constitution = self.constitution + 2
else:
score = raw_input("which ability do you want to increase by one?")
if score == "strength":
self.strength = self.strength + 1
elif score == "dexterity":
self.dexterity = self.dexterity + 1
elif score == "intelligence":
self.intelligence = self.intelligence + 1
elif score == "wisdom":
self.wisdom = self.wisdom + 1
elif score == "charisma":
self.charisma = self.charisma + 1
else:
self.constitution = self.constitution + 1
score_two = raw_input("which second ability do you want to increase?")
if score_two == "strength":
self.strength = self.strength + 1
elif score_two == "dexterity":
self.dexterity = self.dexterity + 1
elif score_two == "intelligence":
self.intelligence = self.intelligence + 1
elif score_two == "wisdom":
self.wisdom = self.wisdom + 1
elif score_two == "charisma":
self.charisma = self.charisma + 1
else:
self.constitution = self.constitution + 1

• if choice == "one": score = raw_input("which ability do you want to increase by two?")
– Mast
Jun 19 '18 at 19:32
• Take a good look at that. It's quite confusing phrased like that, even with the line above it.
– Mast
Jun 19 '18 at 19:32
• that's understandable. I think I can easily rename the variables to make it more readable on the back-end. Thank you Jun 19 '18 at 19:48

Duplicate code is almost always better replaced with a function. Consider a class method which alters an ability by a given value. This can be achieved (most cleanly, I believe) with getattr and setattr. Calling getattr(x,'spam') will return the value x.spam, and similarly setattr(x,'spam',n) will set the value of x.spam to n.

This, combined with a helpful message when the user enters something unexpected, would yield code like that below:

def ability(self):
choice = raw_input("Leveling up: do you want to increase 'one' score by two, or 'two' scores by one each?")
while True:
if choice == "one":
stat = raw_input("Which ability do you want to increase by two?")
self.alter_stat(self, stat, 2)

break
elif choice == "two":
first_stat = raw_input("Which first ability do you want to increase by one?")
self.alter_stat(self, first_stat, 1)
second_stat = raw_input("Which second ability do you want to increase?")
self.alter_stat(self, second_stat, 1)

break
else:
print("Hmm, I don't understand. Enter 'one' or 'two' next time!")

def alter_stat(self, stat, alteration):
assert stat in ['charisma', 'constitution', 'dexterity', 'intelligence', 'strength', 'wisdom'], "That's not a valid ability!"
old_value = getattr(self, stat)
setattr(self, stat, old_value + alteration)

• Thank you so much! This is exactly what I was looking for. I greatly appreciate it. I hadn't thought of using 'assert' in a non-testing functionality as well. Jun 20 '18 at 13:25
• My one comment is that this might be a place to use an enum or similar. Jun 20 '18 at 17:54