So, I'm trying to search the list list_of_chars for any duplicate names, so that I can avoid adding a duplicate. I'm unsure how to do this without using a for loop, which isn't ideal.

I'm using python 3.7.3 in idle on windows 10. I've attempted to use list_of_chars.name, but that doesn't work. I tried putting it in a for loop to search each object.name individually, but it ended up doubling all the things in the list.

class character:
    name = ""
    boldness_mod = 1
    wealth_mod = 1
    def describe_char(self):
        print("%s is a player with %d boldness and %d wealth" % (self.name, self.boldness_mod, self.wealth_mod))

def character_creator():
    name_bank = [
        "Jim", "Kyle", "Malinda", "Wheat", "Whispering River", "Thunderous Fall", "Megalodon", "Morpheus"
        ]
    char = character()
    mod1 = random.randint(1,10)
    mod2 = random.randint(1,4)
    mod3 = random.randint(0,len(name_bank)-1)
    char.boldness_mod = mod1
    char.wealth_mod = mod2
    char.name = name_bank[mod3]
    return char

def run_game(number_of_ai, starting_money):
    list_of_chars = []
    for i in range(number_of_ai):
        char = character_creator()
        #for i in range (len(list_of_chars)):
        #    if char.name in list_of_chars[i].name:
        #        continue
        #    list_of_chars.append(char)
        if char.name in list_of_chars:
            continue
        list_of_chars.append(char)
    for i in range(len(list_of_chars)):
        list_of_chars[i].describe_char()

so, the expected output is something like this

Jim is a player with 6 boldness and 3 wealth
Morpheus is a player with 6 boldness and 4 wealth
Whispering River is a player with 7 boldness and 4 wealth
Thunderous Fall is a player with 5 boldness and 2 wealth

And the desire is to never have any characters have the same name. When I attempted to put in the for loop thats commented out, the results looked like this.

Megalodon is a player with 2 boldness and 1 wealth
Malinda is a player with 4 boldness and 3 wealth
Malinda is a player with 4 boldness and 3 wealth
Jim is a player with 1 boldness and 3 wealth
Jim is a player with 1 boldness and 3 wealth
Jim is a player with 1 boldness and 3 wealth
Jim is a player with 1 boldness and 3 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth
Morpheus is a player with 8 boldness and 4 wealth

2 Answers

0
Netwave On Best Solutions

Use a set to keep track of the names:

def run_game(number_of_ai, starting_money):
    list_of_chars = []
    char_names = set()
    for i in range(number_of_ai):
        char = character_creator()
        if char.name in char_names:
            continue
        list_of_chars.append(char)
        char_names.add(char.name)
    for i in range(len(list_of_chars)):
        list_of_chars[i].describe_char()
0
user10987432 On

Your list_of_chars is a list of characters, not a list of character names. The way things are written now, it makes no sense to check if the current name is in a list of characters (you're looking for a string in a list that has character objects).

I'm addition, you don't want a character's attributes (name, modifiers, etc.) to be static variables (variables that belong to the class, rather than instances of that class).

EDIT* My suggestion of avoiding static variables is not that critical. Unlike other languages, python differentiates between a class-level and an instance-level variable regardless. For example:

class Character:
    name = "Default Name"


def main():

    char = Character()
    char.name = "Bob"

    print(char.name)
    print(Character.name)

    return 0

if __name__ == "__main__":
    from sys import exit
    exit(main())

Output:

Bob
Default Name

Still, I suggest explicitly making them instance variables. Incidentally you can move your "character_creator" code into your class' __init__ method. I think using a set of taken names to prevent yourself from adding a duplicate is avoiding a deeper issue with your code (I realize this isn't the code review board, oh well). I suggest using a class-level set (available_names in this case) and popping arbitrary elements from it until it is exhausted (at which point an exception is thrown):

class Character:

    available_names = {"Tom", "Jerry", "Laura", "Nigel", "Bob", "Robert", "Tom"}

    def __init__(self):
        from random import randint

        if not Character.available_names:
            raise RuntimeError("No more names available!")

        next_name = Character.available_names.pop()

        self.name = next_name
        self.strength = randint(0, 10)

    def get_info(self):
        return f"My name is {self.name} and my strength is {self.strength}."


def main():

    number_of_characters = 3

    characters = [Character() for _ in range(number_of_characters)]

    for character in characters:
        print(character.get_info())

    return 0

if __name__ == "__main__":
    from sys import exit
    exit(main())

Output:

My name is Jerry and my strength is 4.
My name is Robert and my strength is 7.
My name is Tom and my strength is 3.