5
\$\begingroup\$

I have finished my Python Hangman app with very basic code.

import random
import sys


# lets set some variables
wordList = [
"lion", "umbrella", "window", "computer", "glass", "juice", "chair", "desktop",
 "laptop", "dog", "cat", "lemon", "cabel", "mirror", "hat"
           ]

guess_word = []
secretWord = random.choice(wordList) # lets randomize single word from the list
length_word = len(secretWord)
alphabet = "abcdefghijklmnopqrstuvwxyz"
letter_storage = []



def beginning():
    print("Hello Mate!\n")

    while True:
        name = input("Please enter Your name\n").strip()

        if name == '':
            print("You can't do that! No blank lines")
        else:
            break

beginning()



def newFunc():
    print("Well, that's perfect moment to play some Hangman!\n")

    while True:
        gameChoice = input("Would You?\n").upper()

        if gameChoice == "YES" or gameChoice == "Y":
            break
        elif gameChoice == "NO" or gameChoice == "N":
            sys.exit("That's a shame! Have a nice day")
        else:
            print("Please Answer only Yes or No")
            continue

newFunc()



def change():

    for character in secretWord: # printing blanks for each letter in secret word
        guess_word.append("-")

    print("Ok, so the word You need to guess has", length_word, "characters")

    print("Be aware that You can enter only 1 letter from a-z\n\n")

    print(guess_word)



def guessing():
    guess_taken = 1

    while guess_taken < 10:


        guess = input("Pick a letter\n").lower()

        if not guess in alphabet: #checking input
            print("Enter a letter from a-z alphabet")
        elif guess in letter_storage: #checking if letter has been already used
            print("You have already guessed that letter!")
        else: 

            letter_storage.append(guess)
            if guess in secretWord:
                print("You guessed correctly!")
                for x in range(0, length_word): #This Part I just don't get it
                    if secretWord[x] == guess:
                        guess_word[x] = guess
                        print(guess_word)

                if not '-' in guess_word:
                    print("You won!")
                    break
            else:
                print("The letter is not in the word. Try Again!")
                guess_taken += 1
                if guess_taken == 10:
                    print(" Sorry Mate, You lost :<! The secret word was",         secretWord)


change()
guessing()

print("Game Over!")

So, I have couple questions about my code:

  1. I have started to lean some stuff about classes in Python and I thought "Hey, let's write this Hangman with Classes)" But after some coding I realised, i just made classes with 1 func and instead of func() I just called them class.func() and that's all. Is there any good reason why and how I should use classes in a Hangman game?

  2. I know that code is very basic and at my level I shouldn't exactly mind effectiveness of the code but still - Which Part Should be improved ( not the code itself but my logic there)? I want to write in a "proper" way but my code still looks super basic.

\$\endgroup\$
6
\$\begingroup\$

Playability

I ran your game to test it out first, and noticed something odd when a letter is found twice in the same word, such as "glass" here:

Pick a letter
 A
You guessed correctly!
['-', '-', 'a', '-', '-']
Pick a letter
 s
You guessed correctly!
['-', '-', 'a', 's', '-']
['-', '-', 'a', 's', 's']

I'm not sure if that is by design, but as a player I find it odd that it's displayed twice. I found where it originated in the code:

for x in range(0, length_word): #This Part I just don't get it
    if secretWord[x] == guess:
        guess_word[x] = guess
        print(guess_word)

If you just unindent print(guess_word) by two levels, you'll avoid that behavior since it won't run in a loop:

for i in range(0, length_word):
    if secretWord[i] == guess:
        guess_word[i] = guess
print(guess_word)

Printing a raw array like ['-', '-', 'a', 's', 's'] is a bit confusing, at first I didn't know what it was for until I guessed one right and saw the results. So let's make it print something more friendly:

print("Word to guess: {0}".format(" ".join(guess_word)))
Pick a letter
 o
You guessed correctly!
Word to guess: - o -

Much better! But it will get a bit clunky to type all that each time, so let's make a utility function for it and we can use it for the print(guess_word) at the beginning of a game too.

def print_word_to_guess(letters):
    """Utility function to print the current word to guess"""
    print("Word to guess: {0}".format(" ".join(guess_word)))

Then we just print_word_to_guess(guess_word) whenever we need it. It would also be possible to make an optional different message but default to Word to guess:, but I'll leave that for you as a challenge.


The game also doesn't ever tell me anything about how many chances I have left, so I'm left guessing (literally) until I figure it out. That's very easy to make a small utility function to do:

def print_guesses_taken(current, total):
    """Prints how many chances the player has used"""
    print("You are on guess {0}/{1}.".format(current, total))

Then a few code additions:

def guessing():
    guess_taken = 1
    MAX_GUESS = 10
    print_guesses_taken(guess_taken, MAX_GUESS)

    while guess_taken < MAX_GUESS:

And:

for i in range(0, length_word):
    if secretWord[i] == guess:
        guess_word[i] = guess
print_word_to_guess(guess_word)
print_guesses_taken(guess_taken, MAX_GUESS)

Your list of words is pretty limited, for future consider perhaps looking for a text file online with a whole bunch of words and just read a random one from it, that would bring more variety!


Code Improvements

main function

You run all your game functions as soon as you make them. It would make more sense to put them inside the __main__ function:

if __name__ == "__main__":
    beginning()
    newFunc()
    change()
    guessing()

By the way, newFunc() doesn't work well as a name, as it says nothing about what it does. Something like ask_user_to_play() would be much better.


Constants naming

Python doesn't have real constants, but nevertheless, it's good practice to name variables that shouldn't change (by change I mean reassigned to a different values) in ALL_CAPS_WITH_UNDERSCORES. A simple find & replace in an IDE or text editor does the trick to fix your whole script.

GUESS_WORD = []
SECRET_WORD = random.choice(wordList) # lets randomize single word from the list
LENGTH_WORD = len(SECRET_WORD)
ALPHABET = "abcdefghijklmnopqrstuvwxyz"
letter_storage = []

Docstring

It's a good habit to add a docstring to all functions, classes, and modules, to describe for other programmers what the code in question is for. I've done that for the above 2 utility function.


Type hints

Since Python 3, you can now use type hints for your function and method signatures, and use static code analysis tools. This also makes the code easier to read for humans.


Improved code

Here is what I came up with,applying all of the above, and improving the spacing (yours had too many blank lines everywhere). There are likely other things that could be improved, but this should be a good start.

import random, sys
from typing import List

# TODO try to load these from a text file
WORD_LIST = [
"lion", "umbrella", "window", "computer", "glass", "juice", "chair", "desktop",
 "laptop", "dog", "cat", "lemon", "cabel", "mirror", "hat"
           ]

GUESS_WORD = []
SECRET_WORD = random.choice(WORD_LIST) # lets randomize single word from the list
LENGTH_WORD = len(SECRET_WORD)
ALPHABET = "abcdefghijklmnopqrstuvwxyz"
letter_storage = []

# Utility functions

def print_word_to_guess(letters: List) -> None:
    """Utility function to print the current word to guess"""
    print("Word to guess: {0}".format(" ".join(letters)))


def print_guesses_taken(current: int, total: int) -> None:
    """Prints how many chances the player has used"""
    print("You are on guess {0}/{1}.".format(current, total))


# Game functions

def beginning() -> None:
    """Starts the game"""
    print("Hello Mate!\n")
    while True:
        name = input("Please enter Your name\n").strip()
        if name == '':
            print("You can't do that! No blank lines")
        else:
            break


def ask_user_to_play() -> None:
    """Ask user if they want to play"""
    print("Well, that's perfect moment to play some Hangman!\n")
    while True:
        gameChoice = input("Would You?\n").upper()
        if gameChoice == "YES" or gameChoice == "Y":
            break
        elif gameChoice == "NO" or gameChoice == "N":
            sys.exit("That's a shame! Have a nice day")
        else:
            print("Please Answer only Yes or No")
            continue


def prepare_secret_word() -> None:
    """Prepare secret word and inform user of it"""
    for character in SECRET_WORD: # printing blanks for each letter in secret word
        GUESS_WORD.append("-")
    print("Ok, so the word You need to guess has", LENGTH_WORD, "characters")
    print("Be aware that You can enter only 1 letter from a-z\n\n")
    print_word_to_guess(GUESS_WORD)


def guessing() -> None:
    """
    Main game loop to have user guess letters
    and inform them of the results
    """
    guess_taken = 1
    MAX_GUESS = 10
    print_guesses_taken(guess_taken, MAX_GUESS)

    while guess_taken < MAX_GUESS:
        guess = input("Pick a letter\n").lower()
        if not guess in ALPHABET: #checking input
            print("Enter a letter from a-z ALPHABET")
        elif guess in letter_storage: #checking if letter has been already used
            print("You have already guessed that letter!")
        else: 
            letter_storage.append(guess)
            if guess in SECRET_WORD:
                print("You guessed correctly!")
                for i in range(0, LENGTH_WORD):
                    if SECRET_WORD[i] == guess:
                        GUESS_WORD[i] = guess
                print_word_to_guess(GUESS_WORD)
                print_guesses_taken(guess_taken, MAX_GUESS)
                if not '-' in GUESS_WORD:
                    print("You won!")
                    print("Game Over!")
                    break
            else:
                print("The letter is not in the word. Try Again!")
                guess_taken += 1
                print_guesses_taken(guess_taken, MAX_GUESS)
                if guess_taken == 10:
                    print(" Sorry Mate, You lost :<! The secret word was {0}".format(SECRET_WORD))


if __name__ == "__main__":
    beginning()
    ask_user_to_play()
    prepare_secret_word()
    guessing()
\$\endgroup\$
  • 1
    \$\begingroup\$ I can't tell how much I appreciate Your answer! I will look through all of your tips and challenge myself with them, thanks again :) \$\endgroup\$ – michael93pl Oct 20 '17 at 11:51
  • \$\begingroup\$ No problem, I had fun reviewing it too! Hope you post some more in the future =) \$\endgroup\$ – Phrancis Oct 20 '17 at 11:58

protected by Jamal Jul 30 at 3:02

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

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