4
\$\begingroup\$

So this is the code I wrote for hangman in python. I want to know of can shorten this code more further and make it look more professional

# importing random function
import random, hanged
from word_meaning import meanings

# Dictionary of random words
word_dict = '''whistle,
park,
picayune,
attach,
grubby,
gusty,
neck,
necessary,
day,
compete,
memory,
interfere,
sophisticated,
lumpy,
spiky,
frail'''.split(',\n')


# System chooses a random word
rand_word = word_dict[random.randint(0, len(word_dict)-1)]

print('Welcome to HANGMAN.\nGuess correct letters to complete the hidden word, Else hangman will be Hanged')



n = len(rand_word)
hidden_word = ((n-1)*'*')
hidden_word_1 = hidden_word.split('*')
print(f'Hidden Word: {hidden_word}*')
print(f'Hint: {meanings[str(rand_word)]}')
#This is the dictionary imported from another file. it gives the meaning of the hidden word as a hint

chances = 10


def user_lose():
    global chances
    print(f'Oops wrong guess\n Chances Left : {chances - 1}')
    if chances > 1:
        chances -= 1
        user_guess()
    else:
        hanged.hangman()
#hanged.Hangman() this is the function which shows pic of hangman. imported from another file

def user_guess():
    global chances
    if '' in hidden_word_1:
        user_input = str(input('\nGuess a letter: ')[0]).lower()
        if user_input in rand_word:
            if user_input in hidden_word_1:
                user_lose()
            else:
                if chances > 0:
                    letter_index = rand_word.index(user_input)
                    letter_index_r = rand_word.rindex(user_input)
                    hidden_word_1[letter_index] = user_input
                    hidden_word_1[letter_index_r] = user_input
                    print(hidden_word_1)
                    user_guess()

        else:
            user_lose()

    else:
        print('Hurrah, You saved Hangman')


user_guess()

hanged.py file

def hangman():
    print('''You could not save hangman\n
                                   -------------------
                                   |         |
                                   |         |
                                   |         |
                                   |      ( ` ` ) 
                                   |         |
                                   |        /|\\
                                   |       / | \\
                                   |         |  
                                   |        / \\ 
                                   |       /   \\
                                   |
                                   |
                                   |
                                   |                 ''')
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Can you add the hanged include file, so that others can reproduce your code ? \$\endgroup\$
    – Kate
    Commented May 17, 2020 at 12:40
  • 1
    \$\begingroup\$ Oh, that might have occurred when I paste the code. I've run the code, It worked all fine. \$\endgroup\$ Commented May 17, 2020 at 13:13

2 Answers 2

2
\$\begingroup\$

I don't have word_meaning, is that another dependency ?

Since you are already using the random module, you can simply select a random element from a list with random.choice like this:

rand_word = random.choice(word_dict)

instead of:

rand_word = word_dict[random.randint(0, len(word_dict)-1)]

Here you are picking only one element at a time, but if you wanted to select several unique elements (no repeating items) then you would use random.sample.


Your list of words is a constant, make it so:

word_dict = (
'attach', 'compete', 'day', 'frail', 'grubby', 'gusty', 'interfere', 'lumpy', 'memory',
'necessary', 'neck', 'park', 'picayune', 'sophisticated', 'spiky', 'whistle'
)

(did a simple search & replace in Notepad++). NB: I have sorted it too.

The way you are splitting the string is awkward and the comma delimiter is superfluous. This design choice forces you to waste one line per word and makes the code longer for no benefit.

Note that I made it a tuple (non mutable) instead of a list, hence the parentheses.

You could also load the list from a text file, if you want flexibility and separate data from code.


It is not safe to rely on \n as a line break delimiter because it is platform-specific. On Windows/Mac it is different although Python should still interpret it the same. But you never know. Think about portability issues.

Relying on global variables is probably not so Pythonic. You could pass chances as a parameter to your functions. And if you make changes to that value, then return the value in your functions.

Using a global variable could make debugging harder because the variable can be altered in so many places. If you refactor your functions at some point the variable could even be out of sync.


I would aim for minimal variable scope. If hidden_word_1 (not a great name) is only used in user_guess then it need no be defined as a global variable.


I cannot run your code right now but I am not convinced you need a recursive function. You simply need a while loop eg while chances > 0: and decrement the counter after each wrong response.

\$\endgroup\$
1
\$\begingroup\$

Firstly, dictionaries are a class within python so word_dict, will cause confusion down the line, so instead use a different variable name eg. word_list.

Whilst this code is correct:

rand_word = word_dict[random.randint(0, len(word_dict)-1)]

A more readable version uses random.choice, which return a random element from a non-empty sequence:

rand_word = random.choice(word_dict)

Try to keep lines to a maximum of ~80 chars and split this:

print('Welcome to HANGMAN.\nGuess correct letters to complete the hidden word, Else hangman will be Hanged')

Into:

print("Welcome to HANGMAN.")
print("Guess the correct letters to complete the hidden word, "
      "Else hangman will be Hanged")

NITPICK: Whitespace around operators is nicer, eg. ((n-1)*'*') turns into ((n - 1) * '*')

Your variables:

n = len(rand_word)
hidden_word = ((n - 1) * '*')
hidden_word_1 = hidden_word.split('*')

Are not descriptive and as a result you've even forgot to remove n as a variable. Your method for generating hidden_word_1 is convoluted, use this instead:

hidden_word_list = ['' for i in rand_word]

Perhaps also change the function name user_lose to the more descriptive wrong_guess.

There's places where tail recursion fits, but I don't think user_guess works effectively with it. Tail recursion adds far more complexity for debugging than it adds to the effectiveness of the program, especially considering that there is no advantage over say looping with while chance > 0:.

To make tail recursion practical I recommend modifying your code to fit this pseudocode:

def hangman(target_word, user_guess, chances=10):
    if target_word == user_guess:
        print('You saved hangman')
    elif chances < 0:
        print('hangman died')
        return

    print("'So far you've guessed:", user_guess)
    user_input = str('eee'[0]).lower()
    # add use_input into user_guess based on target_word
    # Eg. target_word='random', user_guess='______', user_input='a'
    #     turns into:
    #     target_word='random', user_guess='_a____',
    # Eg. target_word='random', user_guess='_a____', user_input='n'
    #     turns into:
    #     target_word='random', user_guess='_an___',

    # If bad guess, then print(bad luck) ect.
    hangman(target_word, user_guess, chances=(chances - 1))


# code to generate these params
hangman('complete word', '________ ____')
input('Guess a letter: ')
\$\endgroup\$
1
  • \$\begingroup\$ That was a great help from you. Thank you very much. \$\endgroup\$ Commented May 17, 2020 at 14:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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