Simple Hangman in Python I decided to code a simple Hangman in Python today and wanted some feedback on the code since I only started programming three weeks ago.

I intentionally didn't add a lot of whitespace, it just doesn't make it any more readable for me - but feel free to give me reasons to start doing so.

Any tips and suggestions are appreciated.

import os

words = ["foobar", "gnarf", "fnord"]

current_word = 0
maximum_words = len(words)
maximum_guesses = 10
solved_words = 0

for word in words:
    current_word += 1
    current_guess = 0
    dashes = []
    for letter in word:
        dashes.append("_")
    while current_guess &lt; maximum_guesses:
        current_guess += 1
        os.system("clear")
        print("Word {}/{}".format(current_word, maximum_words))
        print("Solved {}/{}".format(solved_words, maximum_words))
        print("Guess {}/{}".format(current_guess, maximum_guesses))
        print("\n{}\n".format(" ".join(dashes)))
        guess = input("Guess: ")
        guess = guess.lower()
        if not len(guess) == 1 or not guess.isalpha():
            current_guess -= 1
        for index, letter in enumerate(word):
            if letter == guess:
                dashes[index] = letter 
        if not "_" in dashes:
            solved_words += 1
            break


The output looks something like this:

Word 1/3
Solved 0/3
Guess 5/10

f o o b a _

Guess: r


Any suggestings for a better output?
I see a couple issues, though nothing too major.



Improper form for 'if not in'

While this works, it's not the proper form for this:

if not "_" in dashes:


The better form for this is:

if "_" not in dashes:




Tracking if a value is not equal to something

This works:

if not len(guess) == 1 or not guess.isalpha():


But, we can remove one 'not' though,  and use an inequality operator instead:

if len(guess) != 1 or not guess.isalpha():




Generation of dashes

You can shorten the creation of 'dashes' to this when you create it, and then get rid of the for loop that generated it previously:

dashes = ['_'] * len(word)




No tracking of guesses already made

Your code does not track guesses already made.  Therefore, people can 'waste' guesses.

Let's do two things:  first let's move around some things.  Secondly, let's add some code to capture this case and not increment the number of guesses made when this happens.

First, let's change where we increment the 'current guess' value, and define a different 'start' value:

for word in words:
    current_word += 1
    current_guess = 1
    dashes = []
    ....
    while current_guess &lt; maximum_guesses:
        os.system("clear")
        ....
        guess = guess.lower()
        if not len(guess) == 1 or not guess.isalpha():
            current_guess += 1
            ....


Basically, we moved the current_guess incrementer to lower in the code.  And initialize the guess counter to 1 to begin with.

Now let's do some "already guessed" code:

for word in words:
    ....
    guesses = set()
    for letter in word:
        ...
    guess = guess.lower()
    if guess not in guesses:
        guesses.add(guess)
        current_guess += 1
        if not len(guess) == 1 or not guess.isalpha():
            current_guess -= 1
        for index, letter in enumerate(word):
            if letter == guess:
                dashes[index] = letter
        if "_" not in dashes:
            solved_words += 1
            break


This allows 'repeated' guesses of the same letter to not take effect.  That way, if someone enters 'o' as a guess twice, accidentally or intentionally, on the word 'foobar', they aren't penalized for something already guessed.  You can choose to not do this, but it helps protect against "What the heck, I shouldn't be penalized for something I already guessed!" complaints.



I don't change much of your program.  This is the total program with my above suggestions, plus some whitespace for readability.  I don't have any suggestions for improving the output, though, because it seems to be okay as it is, at least to me.

import os

words = ["foobar", "gnarf", "fnord"]

current_word = 0
maximum_words = len(words)
maximum_guesses = 10
solved_words = 0

for word in words:
    current_word += 1
    current_guess = 1
    dashes = ['_'] * len(word)
    guesses = set()

    while current_guess &lt; maximum_guesses:
        os.system("clear")

        print("Word {}/{}".format(current_word, maximum_words))
        print("Solved {}/{}".format(solved_words, maximum_words))
        print("Guess {}/{}".format(current_guess, maximum_guesses))
        print("\n{}\n".format(" ".join(dashes)))

        guess = input("Guess: ")
        guess = guess.lower()

        if guess not in guesses:
            guesses.add(guess)
            current_guess += 1

            if len(guess) != 1 or not guess.isalpha():
                current_guess -= 1

            for index, letter in enumerate(word):
                if letter == guess:
                    dashes[index] = letter

            if "_" not in dashes:
                solved_words += 1
                break