Cory D
Cory D

Reputation: 87

Python Dictionary Appending Issues

I'm trying to do the Chapter 5 Challenges for the Python Programming for Absolute Beginners book, and seem to be having some issues. The program I am working on is making a Character attribute skill point distribution program with a dictionary. The objective is to make a program that has 4 skills that you can distribute 30 points across. You can add them, remove them, or view them all. When I launch my program, it distributes the points to all skills, instead of just one, which is not what I am intending. Also, it has the message for my "else" option every time, which I don't want either. Sorry for posting the whole thing, I just am new to this and am unsure where within the code I messed up. Thank you!

# Hero Attribute Assigner
# My attempt

name = ""
attr = {"STRENGTH":0, "DEXTERITY":0, "WISDOM":0, "HEALTH":0}
totalPoints = 30
for attrName in attr:
    attrPoints = attr[attrName]

userInput = None

while userInput != "5":
    userInput = input \
    ("""
            Character Creator

            1 - Name Character
            2 - Assign Attribute Points
            3 - Remove Attribute Points
            4 - Exit

    """)

    # Name Character
    if userInput == "1":
        name = str(input("\nCharacter Name: "))
        print("\nYour character's name is now: " + name)
        input("\nPress 'Enter' to return to menu.")

    # Assign Points
    if userInput == "2":

        # What attribute?
        print("\n" + name + "'s Attribute Stats are:\n")
        for attrName in attr:
            print(attrName, ":\t", str(attrPoints))
        print("UNUSED POINTS:" + "\t" + str(totalPoints))
        changeAttr = input("\nWhat attribute would you like to add points to? ").upper()

        # How many points to add?
        if changeAttr in attr:
            changePoints = int(input("How many points would you like to add? "))
            attr[changeAttr] += changePoints
            totalPoints -= changePoints
            print("\n" + name + "'s Attribute Stats are now:\n")
            for attrName in attr:
                print(attrName, ":\t", str(attrPoints))
            print("UNUSED POINTS:" + "\t " + str(totalPoints))
        else:
            print("\nThat is not a valid choice.")

    # Remove Points
    if userInput == "3":

        # What attribute?
        print("\n" + name + "'s Attribute Stats are:\n")
        for attrName in attr:
            print(attrName, ":\t", str(attrPoints))
        print("UNUSED POINTS:" + "\t" + str(totalPoints))
        changeAttr = input("\nWhat attribute would you like to remove points from? ").upper()

        # How many points to remove?
        if changeAttr in attr:
            changePoints = int(input("How many points would you like to remove? "))
            attr[changeAttr] -= changePoints
            totalPoints += changePoints
            print("\n" + name + "'s Attribute Stats are now:\n")
            for attrName in attr:
                print(attrName, ":\t", str(attrPoints))
            print("UNUSED POINTS:" + "\t " + str(totalPoints))
        else:
            print("\nThat is not a valid amount.")

    # Exit  
    elif userInput == "4":
        break

    # Invalid Choice in Menu
    else:
        print("\nInvalid choice...")

input("\nPress 'Enter' to exit.")

Upvotes: 1

Views: 102

Answers (3)

Gahan
Gahan

Reputation: 4213

A function based answer for problem:

# constants
ATTRIBUTES = {"STRENGTH": 0, "DEXTERITY": 0, "WISDOM": 0, "HEALTH": 0}
TOTAL_POINTS = 30
userInput = None


def create_character():
    """

    :return: name : of character
    """
    name = str(input("\nCharacter Name: "))
    ATTRIBUTES['character'] = name
    print("\nYour character's name is now: " + name)
    input("\nPress 'Enter' to return to menu.")
    return name  # returns name entered by user which can be stored and retrive in other function


def change_attributes(char_name="", flag="add"):
    """

    :param char_name: name of character
    :param flag: add/sub to make sure which function to call to change attributes value
    :return: this either returns true or false or none
    """
    global TOTAL_POINTS
    name = char_name
    if 'character' in ATTRIBUTES.keys():  # user needs to create character first before assigning any attributes
        # What attribute?
        print(name + "'s Attribute Stats are:\n")
        for attrName in ATTRIBUTES:
            print(attrName, ":\t", str(ATTRIBUTES[attrName]))
        print("UNUSED POINTS:" + "\t" + str(TOTAL_POINTS))
        changeAttr = input("What attribute would you like to change? ").upper()

        if flag == "add":
            result = add_points(changeAttr, name)
        elif flag == "sub":
            result = remove_points(changeAttr, name)
        if result:
            return True
        else:
            print("That is an invalid choice.")
            choice = input("Do you want to try again ?... (Y/N)").upper()
            if choice == "Y":
                change_attributes(name, flag)
            elif choice == "N":
                print("Have a nice day!!!")
                return False
            else:
                print("Invalid input.")
                return False
    else:
        print('You need to create character first.')


def add_points(changeAttr, char_name):
    """
    add points to attribute
    :param changeAttr: attributes which is to be change
    :param char_name: character name whose attribute value to be change
    :return: True/False
    """
    global TOTAL_POINTS  # it is good habit to specify global keyword to know function it is not local variable otherwise you may get UnboundLocalError
    global ATTRIBUTES
    name = char_name
    if changeAttr in ATTRIBUTES:
        try:
            changePoints = abs(int(input(
                "How many points would you like to add? ")))  # converts negative input to positive or use another control statement to handle value input.
        except ValueError:
            print("Invalid values. Please enter integer value only")

        if 0 < changePoints < TOTAL_POINTS:  # make sure points to insert is greater than 0 and less than total points
            ATTRIBUTES[changeAttr] += changePoints
            TOTAL_POINTS -= changePoints
            print("\n" + name + "'s Attribute Stats are now:\n")
            for attrName in ATTRIBUTES:
                print(attrName, ":\t", str(ATTRIBUTES[attrName]))
            print("UNUSED POINTS:" + "\t " + str(TOTAL_POINTS))
            return True
        else:
            print("You can only add minimum {} points and maximum {} points".format(1, TOTAL_POINTS))
            choice = input("Do you want to try again ?... (Y/N)").upper()
            if choice == "Y":
                change_attributes(name, "add")
            elif choice == "N":
                print("Have a nice day!!!")
                return False
            else:
                print("Invalid input.")
                return False
    else:
        return False


def remove_points(changeAttr, char_name):
    """
    remove points of attribute
    :param changeAttr: attributes which is to be change
    :param char_name: character name whose attribute value to be change
    :return: True/False
    """
    global TOTAL_POINTS
    global ATTRIBUTES
    name = char_name
    if changeAttr in ATTRIBUTES:
        if ATTRIBUTES[changeAttr] > 0:  # only remove attributes if it has value
            changePoints = abs(int(input("How many points would you like to remove? ")))
            if 0 < changePoints < ATTRIBUTES[changeAttr]:
                ATTRIBUTES[changeAttr] -= changePoints
                TOTAL_POINTS += changePoints
                print("\n" + name + "'s Attribute Stats are now:\n")
                for attrName in ATTRIBUTES:
                    print(attrName, ":\t", str(ATTRIBUTES[attrName]))
                print("UNUSED POINTS:" + "\t " + str(TOTAL_POINTS))
                return True
            else:
                print("You can only remove minimum {} points and maximum {} points".format(1, ATTRIBUTES[changeAttr]))
                # give a chance to input again with function call
                choice = input("Do you want to try again ?... (Y/N)").upper()
                if choice == "Y":
                    change_attributes(name,
                                      "sub")  # you can also call same function remove_points() with valid arguments if you want user to enter only selected field again
                elif choice == "N":
                    print("Have a nice day!!!")
                    return False
                else:
                    print("Invalid input.")
                    return False
        else:
            print("no attributes left to remove.")
            sel = input("Do you want to add points first ?... (Y/N)").upper()
            if sel == "Y":
                change_attributes(name, "add")
            elif sel == "N":
                print("Have a nice day!!!")
                return False
            else:
                print("Invalid input.")
                return False
    else:
        return False


if __name__ == "__main__":
    while userInput != "5":
        userInput = input \
            ("""
    Character Creator

    1 - Name Character
    2 - Assign Attribute Points
    3 - Remove Attribute Points
    4 - Exit

    >> """)
        # Name Character
        if userInput == "1":
            character_name = create_character()

        # Assign Points
        elif userInput == "2":
            try:
                change_attributes(character_name, "add")
            except NameError:
                print("You need to create character first!!!!!")
                choice1 = input("want to try again? (Y/N)").upper()
                if choice1 == "Y":
                    pass
                else:
                    break
        # Remove Points
        elif userInput == "3":
            try:
                change_attributes(character_name, "sub")
            except NameError:
                print("You need a character with valid attributes...")
                choice2 = input("want to try again? (Y/N)").upper()
                if choice2 == "Y":
                    pass
                else:
                    break
        # Exit  
        elif userInput == "4":
            break

        # Invalid Choice in Menu
        else:
            print("\nInvalid choice...")

    input("Press 'Enter' to exit.")

Note: depending on your choice and expectation you may change flow of function which may require some fix otherwise this is a good example for you to learn and use functions.

Upvotes: 0

Cory D
Cory D

Reputation: 87

Looks like it was a combination of simple mistakes and a misunderstanding of how to properly define dictionaries. Thanks everyone!

Upvotes: 0

Gahan
Gahan

Reputation: 4213

Better version of your code with fix.

# Hero Attribute Assigner
# My attempt

name = ""
attr = {"STRENGTH":0, "DEXTERITY":0, "WISDOM":0, "HEALTH":0}
totalPoints = 30
userInput = None
while userInput != "5":
    userInput = input \
    ("""
Character Creator

1 - Name Character
2 - Assign Attribute Points
3 - Remove Attribute Points
4 - Exit

:    """)
    # Name Character
    if userInput == "1":
        name = str(input("\nCharacter Name: "))
        attr['character'] = name
        print("\nYour character's name is now: " + name)
        input("\nPress 'Enter' to return to menu.")

    # Assign Points
    elif userInput == "2":
        if 'character' in attr.keys(): # user needs to create character first before assigning any attributes
            # What attribute?
            print("\n" + name + "'s Attribute Stats are:\n")
            for attrName in attr:
                print(attrName, ":\t", str(attr[attrName]))
            print("UNUSED POINTS:" + "\t" + str(totalPoints))
            changeAttr = input("\nWhat attribute would you like to add points to? ").upper()
            # How many points to add?
            if changeAttr in attr:
                try:
                    changePoints = abs(int(input("How many points would you like to add? "))) # converts negative input to positive or use another control statement to handle value input.
                except ValueError:
                    print("Invalid values. Please enter integer value only")
                if  0 < changePoints < totalPoints: # make sure points to insert is greater than 0 and less than total points
                    attr[changeAttr] += changePoints
                    totalPoints -= changePoints
                    print("\n" + name + "'s Attribute Stats are now:\n")
                    for attrName in attr:
                        print(attrName, ":\t", str(attr[attrName]))
                    print("UNUSED POINTS:" + "\t " + str(totalPoints))
                else:
                    print("You can only add minimum {} points and maximum {} points".format(1, totalPoints))
            else:
                print("\nThat is not a valid choice.")
        else:
            print('You need to create character first.')

    # Remove Points
    elif userInput == "3":
        if 'character' in attr.keys():
            # What attribute?
            print("\n" + name + "'s Attribute Stats are:\n")
            for attrName in attr:
                print(attrName, ":\t", str(attr[attrName]))
            print("UNUSED POINTS:" + "\t" + str(totalPoints))
            changeAttr = input("\nWhat attribute would you like to remove points from? ").upper()

            # How many points to remove?
            if changeAttr in attr:
                if attr[changeAttr] > 0: # only remove attributes if it has value
                    changePoints = abs(int(input("How many points would you like to remove? ")))
                    if 0 < changePoints < attr[changeAttr]:
                        attr[changeAttr] -= changePoints
                        totalPoints += changePoints
                        print("\n" + name + "'s Attribute Stats are now:\n")
                        for attrName in attr:
                            print(attrName, ":\t", str(attr[attrName]))
                        print("UNUSED POINTS:" + "\t " + str(totalPoints))
                    else:
                        print("You can only remove minimum {} points and maximum {} points".format(1, attr[changeAttr]))
                else:
                    print("no attributes left to remove.")
            else:
                print("\nThat is not a valid amount.")
        else:
            print('You need to create character first.')

    # Exit  
    elif userInput == "4":
        break

    # Invalid Choice in Menu
    else:
        print("\nInvalid choice...")

input("\nPress 'Enter' to exit.")

Upvotes: 1

Related Questions