0

I'm trying to build my first real personal project, and this is my first post here. It's a Dungeons and Dragons character builder. I'm having a problem taking items off of a list.

I've successfully, but admittedly messily, managed to make a function that rolls the stats. It rolls 4 6 sided dice and takes the top 3 rolls and totals the 6 times to get a stat array. I then attempted to make a second function that would allow the user to take the rolls from the first function and applies them to the stat names from the game and removes them from the original list.

print("Dungeons and Dragons 5e Character Creator")
import random

def stats_roll():

This is really messy and long. All it does is get the numbers into the variable list "stats"

stats_roll()
edit_stats = stats


def stat_assignment():
    global str
    global dex
    global con
    global intel
    global wis
    global cha
    print (edit_stats)
    str = input("Which stat will you assign to Strength?: ")
    int(str)
    edit_stats.remove(str)

What I want is for in the stat_assignment function to take the stats from the edit_stats one by one and remove them and apply them to new variables for the stats that the user wants them in. I instead get an list.remove(x): x not in list error.

HogHoncho
  • 21
  • 1
  • 1
    `str` is the string type in python, don't use this as a variable name. If you do want all of these state variables you might consider using a `class` to hold them. What are you expecting in the `edit_stats` list? It is unlikely that you will have the value of `str` perhaps you mean `str` as the index, e.g. `del edit_stats[str]` – AChampion Aug 29 '19 at 01:30
  • Post whole error message with full traceback. Where do you define `stats`? Also `int(str)` does nothing unless you assign the return value to something. – Selcuk Aug 29 '19 at 01:30
  • `int(str)` is not doing anything - its return value should be assigned to something... `something = int(str)`. – wwii Aug 29 '19 at 02:42

2 Answers2

0

If you want to avoid the error you can filter the element (and don't call you variables as python builtins PLEASE!):

edit_stats = [1,2,3,4,5]

str_ = "4"

edit_stats = [x for x in edit_stats if x != int(str_)]

print(edit_stats)

result:

[1,2,3,5]

Even more pretty, you can tell the user what is going on:

edit_stats = [1,2,3,4,5]

str_ = input("Which stat will you assign to Strength?: ")

if(str_ in edit_stats):
  edit_stats = [x for x in edit_stats if x != int(str_)]
  print(str_ + " deleted!")
else:
  print(str_ + " doesn't belong to list")
developer_hatch
  • 15,898
  • 3
  • 42
  • 75
  • I didn't think about the str being a builtin! I changed it to "strength" , thanks! The way i was doing it was i wanted to get the number to be removed from a user input. Also, wouldn't the way you proposed remove all instances of the str_ variable, so if there were repeats, which happens often as the stats list is random, wouldn't all instances be removed? Sorry for the beginners questions. I didn't even know about the method you used :S – HogHoncho Aug 29 '19 at 01:51
  • @HogHoncho do you want to remove all instances of the input? or just the first? – developer_hatch Aug 29 '19 at 02:40
0

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]))
musicamante
  • 41,230
  • 6
  • 33
  • 58