8
\$\begingroup\$

This program displays a list of TV characters. You can kill them off by random or bring them back by name. I have used the random.choice function. I've defined a couple of functions so that the while loop looks a little more clean. In two of the functions, bring_back and check_decision, we assign True to invalid_input if user input is invalid, like a flag. This program is for learning purposes.

from random import choice

tv_characters = [
    'john', 'henry', 'maria', 'jason', 
    'max', 'lara', 'gilbert', 'paris'
    ]

killed_tv_characters = []
valid_decision_input = ['kill off', 'bring back']

start_prompt = "Would you like to start (yes/no)?"
decision_prompt = "\nWould you like to bring back a character you killed?"
decision_prompt += "\nOr would you like to kill off another character?"
decision_prompt += "\nEnter 'kill off' or 'bring back' ->"
character_from_dead_prompt = "\nPlease enter the name of character you would like to bring back: "
confirm_kill_prompt = "\nEnter 'kill off' to kill your first character: "




def kill_tv_characters():
    """Kills a random tv character and displays the name on the screen."""
    if tv_characters:
        killed_tv_character = choice(tv_characters)
        tv_characters.remove(killed_tv_character)
        print(f"You have killed off {killed_tv_character.title()}")
        killed_tv_characters.append(killed_tv_character)
    else:
        print("You have killed off all the characters!")

def bring_back(name):
    """Brings back a dead character."""
    name = name.lower().strip()
    if name in killed_tv_characters:
        killed_tv_characters.remove(name)
        tv_characters.append(name)
        print(f"\nYou have brought {name.title()} back to life!")
    elif name in tv_characters:
        print(f"{name} isn't dead!")
        invalid_input = True
    else:
        print(f"{name} isn't a character!")
        invalid_input = True

def check_decision(user_input):
    """Checks user input for decision."""
    if user_input in valid_decision_input and user_input == 'kill off':
        return user_input
    elif user_input in valid_decision_input and user_input == 'bring back':
        return user_input
    else:
        invalid_input == True
        print("Please enter a valid input!")
print("\nYou can kill off characters randomly and add them back my name!")


start = input(start_prompt)
if start == 'yes':
    start = True
else:
    start = False


while tv_characters and start:
    invalid_input = None

    print("\nThese are the living TV characters:")
    for tv_character in tv_characters:
        print(tv_character.title()) 
    if killed_tv_characters:
        user_decision = input(decision_prompt)
        decision = check_decision(user_decision)
        if invalid_input:
            continue
        if decision == 'kill off':
            kill_tv_characters()
        if decision == 'bring back':
            character_from_dead = input(character_from_dead_prompt)
            bring_back(character_from_dead)
            if invalid_input:
                continue

    else:
        confirm_kill = input(confirm_kill_prompt)
        if confirm_kill != 'kill off':
            print("You have entered an invalid input.")
            continue
        kill_tv_characters()

            
if tv_characters == False:
    print("You have killed off all the characters.")
    print("Thanks for playing!")

else:
    print("Goodbye")
        
\$\endgroup\$
5
\$\begingroup\$

User interface decisions

Having a start option is an odd choice. If the user started the program itself, is it likely that they don't want to start the rest of its logic?

Successive concatenation

This:

decision_prompt = "\nWould you like to bring back a character you killed?"
decision_prompt += "\nOr would you like to kill off another character?"
decision_prompt += "\nEnter 'kill off' or 'bring back' ->"

is better off as

DECISION_PROMPT = '''
Would you like to bring back a character you killed?
Or would you like to kill off another character?
Enter 'kill off' or 'bring back' ->'''

Data structures

It seems that the order of killed_tv_characters does not matter, so it should be a set, not a list.

Input validation

This:

"""Checks user input for decision."""
if user_input in valid_decision_input and user_input == 'kill off':
    return user_input
elif user_input in valid_decision_input and user_input == 'bring back':
    return user_input
else:
    invalid_input == True
    print("Please enter a valid input!")

has a few problems:

  • invalid_input == True doesn't do what you think it does; it's a no-effect statement
  • This doesn't really benefit from the combination of valid_decision_input (which should be a set) and checking for specific strings
  • Early-return means that you don't need to use else

Here is an alternative:

if user_input in valid_decision_input:
    return user_input
invalid_input = True
print("Please enter a valid input!")

Other concerns:

  • This will set a local invalid_input unless you declare it global at the top
  • Rather than returning a string, consider returning an Enum to narrowly represent user choice

Booleans

This:

if tv_characters == False:

should be

if not tv_characters:
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Why do I need a set, doesn’t a list do the job too? \$\endgroup\$ – snow_razer Jun 22 at 6:56
  • \$\begingroup\$ do the job is a little loaded. Certainly a list will work, but a set will be more efficient for your application in this case. \$\endgroup\$ – Reinderien Jun 22 at 13:59
  • \$\begingroup\$ The "why" is because valid_decision_input is being used for membership tests, which have better time complexity in sets than in sequences. \$\endgroup\$ – Reinderien Jun 22 at 14:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.