Python Tabletop Initiative Tracker I wrote my first Python program today after working through a few books. I decided to build a group initiative tracker for our D&amp;D group and was hoping to get some feedback. Critiques on code efficiency, formatting, suggestions, etc would be appreciated. My plan is to eventually take this from a command-line application to a django or flask web app, or maybe an iOS app.

print('Welcome to Initiative Tracker!')
while True:
    try:
        loop_count=int(input("\nHow many PC's and NPC's total? "))
        loop_start = 0
        initiative_tracking = {}
        while loop_start &lt; loop_count:
            player_name = input('What is the Players name? ')
            player_initiative = int(input('What is ' + player_name + ' initiative? '))
            if player_initiative in initiative_tracking:
                initiative_tracking[player_initiative].append(player_name)
            else:
                initiative_tracking[player_initiative] = [player_name]
            loop_start += 1
            continue
        print('\nYour initiative order is: ')
        for key in sorted (initiative_tracking.keys(), reverse=True):
            print(str(key) + ': ' + ', '.join(initiative_tracking[key]))
        break
    except ValueError:
        print("Sorry I didn't catch that. How many PC and NPC total? ")
I see that you have some error handling for int(input(...)).  I would change it, however.  Let's say that the user types a valid number of PC's, but does not type a valid player initiative.  That would trigger a ValueError, and your except block would ask again how many PC's.  Why should it restart the whole process for one little mistake?  You should have different try blocks for each of those. Also, a try block should include only the code that you expect might throw an error.  If some other code throws an error, you want to know about it.

For the first use of int(input(...)), I would just take it out completely.  Why should the user need to specify how many PC's?  Why not just keep going until he runs out and then hit Enter on a blank line?  That can be done quite simply with iter().  Usually, iter() is given an iterable, but if it is given two arguments,  the first argument is a callable (usually a function) that returns a value.  (In our case, we use lambda: input(...)).  The second argument is the stopping point.  iter() will keep calling that function and yielding the result until it returns the second argument. Therefore, we give it '', and we get all of the user's inputs until he types nothing in a line.

The second use of int(input(...)) is when you are retrieving the player initiative.  It should have its own try-except block to make sure the input is an integer.  I would then put that block inside of its own while loop so that the program keeps asking until it gets a valid answer.



Instead of a chain of string concatenations, use string formatting:

player_initiative = input('What is {} initiative? '.format(player_name))


and

print('{}: {}'.format(key, ', '.join(initiative_tracking[key])))




A loop is called that because it loops.  You don't need to tell it to keep looping.  It will keep looping until it is told to stop.  Sometimes it is stops because a condition is not met, but sometimes it stops because it encounters a break.  You should use continue only if you want to skip the code beneath and jump straight to the beginning of the loop.  It really doesn't make sense to put continue at the end of the loop.



The argument that is given to sorted() has only one requirement: that it is iterable.  To test if a type of object is iterable, go into a Python shell and create an instance of it.  Then, do for item in my_object: print(item).  If there is an error, your object is not iterable.  Otherwise, you will see what happens when iterates.  For a dictionary, you get all of the keys.  Therefore, sorted(initiative_tracking.keys(), reverse=True) can be simplified to sorted(initiative_tracking, reverse=True).



Full code:

print('Welcome to Initiative Tracker!')

initiative_tracking = {}
for player_name in iter(lambda: input("What is the player's name? "), ''):
    player_initiative = input('What is {} initiative? '.format(player_name))
    while True:
        try:
            player_initiative = int(player_initiative)
            break
        except ValueError:
            player_initiative = input('Please enter an integer: ')

    if player_initiative in initiative_tracking:
        initiative_tracking[player_initiative].append(player_name)
    else:
        initiative_tracking[player_initiative] = [player_name]

print('\nYour initiative order is: ')
for key in sorted(initiative_tracking, reverse=True):
    print(str(key) + ': ' + ', '.join(initiative_tracking[key]))