Instead of using a list, a dictionary is much more suitable for your needs; the only problem is that a standard dictionary is not ordered, meaning that if you cycle through its items you will never get the same order of key/value pairs. The standard library module provides the OrderedDict
which is an advanced class that can behave like a dictionary while always remembering the order in which you inserted data.
Besides the suggested and wise advice "don't use builtins as variable names", you should reeeally avoid "character cheapness" in variable names: they never help readability and debugging: the tenths of seconds you "gain" by using too short names can easily become minutes (if not hours!) of painful bug hunting.
Finally, the global
statement should only be used in very specific cases, and its use is highly discouraged.
import random
from collections import OrderedDict
# create the valid range for every ability, while keeping the insertion order;
# it's been more than 20 years since I've played tabletop role playing, these
# are just ranges I put in randomly
ability_ranges = OrderedDict([
("Strength", (3, 20)),
("Dexterity", (5, 18)),
("Constitution", (2, 20)),
("Intelligence", (3, 18)),
("Wisdom", (1, 18)),
("Charisma", (4, 16)),
])
print("Dungeons and Dragons 5e Character Creator\n")
def stats_roll():
# create a new dictionary object that will be filled in with new statistics
stats = {}
for ability, (minimum, maximum) in ability_ranges.items():
# create random statistics, remember that randrange is always between
# the minimum and the maximum *minus* one: randrange(0, 2) will only
# return 0 or 1
stats[ability] = random.randrange(minimum, maximum + 1)
# return the complete statistics
return stats
stats = stats_roll()
def stats_assignment(stats):
print("Current stats:")
for ability in ability_ranges.keys():
while True:
# use a while loop to avoid raising exceptions if the user does not
# input a number or the number is not between the range of the ability
random_value = stats[ability]
ability_min, ability_max = ability_ranges[ability]
new_value = input("Which stat will you assign to {} (current: {}, <Enter> to confirm)? ".format(
ability, random_value))
if not new_value:
# if the user presses <Enter> without typing anything it means
# that he/she is ok with the random chosen value
stats[ability] = random_value
break
if new_value.isdigit():
new_value = int(new_value)
if ability_min <= new_value <= ability_max:
# if the value is between the allowed range, use it and go on!
stats[ability] = new_value
break
# at this point the user has entered a value outside the allowed range
# or has typed something that cannot be interpreted as a number
print("{} is not a valid value for {} (has to be between {} and {})!\n".format(
new_value, ability, ability_min, ability_max))
# run the assignment function using the existing statistics as a parameter; the
# function will modify the data of the "stats" object in place
stats_assignment(stats)
print("\nYour character statistics:")
for key in ability_ranges.keys():
print(" {}: {}".format(key, stats[key]))