1
\$\begingroup\$

I created a fairly simple hangman program as a little side project. Could you please tell me of any improvements/suggestions/criticism/feedback that you have about my code?

import tkinter as tk
import turtle
import string
from functools import partial
from draw_hangman import drawHangman
from random import randint

intro = tk.Tk()
intro.title('Menu')
intro_text = tk.Label(intro, text = 'Welcome to Hangman\nPlease choose your\ndifficulty rating:')
easy = tk.Button(intro, text = 'Hard (3-5 letters)', command = lambda: difficulty(3, 5))
medium = tk.Button(intro, text = 'Medium (5-10 letters)', command = lambda: difficulty(5, 10))
hard = tk.Button(intro, text = 'Easy (10-15 letters)', command = lambda: difficulty(10, 15))
intro_text.grid(row = 0, column = 0)
easy.grid(row = 1, column = 0, sticky = 'news')
medium.grid(row = 2, column = 0, sticky = 'news')
hard.grid(row = 3, column = 0, sticky = 'news')


def enable():
    easy.config(state = 'normal')
    hard.config(state = 'normal')
    medium.config(state = 'normal')
    root.destroy()

def disableButtons():
    for w in root.winfo_children():
        if 'button' in str(w):
            w.configure(state="disabled")

def whenGuessed():
    win = ''
    global drawRate
    if entry.get().lower() == word:
        win = 'You win!'
        lab.config(text = word)
        disableButtons()
        t.clear()
    else:
        trash = draw[drawRate]
        exec(trash)
        drawRate+=1
        if drawRate > len(draw)-1:
            win = 'You lose!'
            lab.config(text = word)
            disableButtons()
            t.clear()
    if win != '':
        entry.delete(0, tk.END)
        entry.insert(0, win)

def whenPressed(button, text):
    global drawRate
    win = ''
    button.config(state = 'disabled')
    ind = []
    local_word = list(word)
    for i in local_word :
        if i == text:
            trash = local_word.index(i)
            ind.append(trash)
            local_word.pop(trash)
            local_word.insert(trash, '-')
    if len(ind) != 0:
        for i in ind:
            shown_text.pop(i)
            shown_text.insert(i, text)
        lab.config(text = ''.join(shown_text))
        for i in shown_text:
            if i == '-':
                trash = True
        if trash != True:
            win = 'You win!'
            disableButtons()
            t.clear()
    else:
        trash = draw[drawRate]
        exec(trash)
        drawRate+=1
        if drawRate > len(draw)-1:
            win = 'You lose!'
            lab.config(text = word)
            disableButtons()
            t.clear()
    if win != '':
        entry.delete(0, tk.END)
        entry.insert(0, win)
        
def difficulty(minimum, maximum):
    global word, lab, root, shown_text, drawRate, draw, t, entry
    file = open(r"C:\Users\d_j_d\Desktop\words.txt", 'r').read().split('\n')
    word = ''
    while len(word) < minimum or len(word) >= maximum:
        word = file[randint(0, len(file)-1)]
    shown_text = list('-'*len(word))
    draw = drawHangman()
    drawRate = 0
    root = tk.Tk()
    root.title('Hangman 3.0')
    t = turtle.Turtle()
    easy.config(state = 'disabled')
    hard.config(state = 'disabled')
    medium.config(state = 'disabled')
    root.protocol("WM_DELETE_WINDOW", enable)
    length = tk.Label(root, text = 'Length: '+str(len(word)))
    length.place(relx = 1, rely = 1)
    alphabet = list(string.ascii_lowercase)
    lab = tk.Label(root, text = '-'*len(word), font = (None, 15), width = 30)
    lab.grid(row = 0, columnspan = 13, column  =  0)
    entry = tk.Entry(root)
    entry.grid(row = 3, columnspan = 10, sticky = 'news', column = 0)
    button = tk.Button(root, text = 'Enter', command = whenGuessed)
    button.grid(row = 3, columnspan = 3, sticky = 'news', column = 10) 
    for i in alphabet:
        btn = tk.Button(root, text=i)
        command = partial(whenPressed, btn, i)
        btn.config(command=command)
        row = (alphabet.index(i) // 13)+1
        column = alphabet.index(i) % 13
        btn.grid(row=row, column=column, sticky="news")

drawHangman function:

import turtle
t = turtle.Turtle()
draw = [
    '''t.speed(10)
t.penup()
t.fd(200)
t.rt(90)
t.fd(200)
t.down()
t.lt(270)
t.fd(400)''',
    '''t.rt(90)
t.fd(400)''',
    '''t.rt(90)
t.fd(300)''',
    '''t.rt(90)
t.fd(75)
t.dot(75)''',
    't.fd(100)',
    '''t.lt(90)
t.fd(60)
t.back(120)
t.fd(60)
t.rt(90)''',
    '''t.fd(75)
t.lt(30)
t.fd(100)''',
    '''t.back(100)
t.rt(60)
t.fd(100)''']
def drawHangman():
    return draw
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Minor bug

The easy variable has the word "Hard" in the text description, and vice versa:

easy   = tk.Button(intro, text = 'Hard
hard   = tk.Button(intro, text = 'Easy

I think it should be:

easy   = tk.Button(intro, text = 'Easy
hard   = tk.Button(intro, text = 'Hard

DRY

Lines like these are repeated in a couple places, with only the string changing, and also the string is the same for the 3 lines:

easy.config(state = 'disabled')
hard.config(state = 'disabled')
medium.config(state = 'disabled')

You can avoid the repetition by creating a function like:

def set_all_state(value):
    easy  .config(state = value)
    hard  .config(state = value)
    medium.config(state = value)

In the difficulty function, the expression len(word) appears several times. You can create a variable so that you only evaluate the expression once:

word_len = len(word)

Naming

The PEP 8 style guide recommends camel_case for function names. Change whenGuessed to when_guessed.

Layout

Move the functions to the top after the import lines. Having them in the middle of the code interrupts the natural flow of the code (from a human readability standpoint).

Documentation

Add a doctring at the top of the file to summarize the purpose of the code:

"""
Hangman game using tkinter GUI with 3 difficulty levels.
"""

There is a hard-coded directory path buried deep in the code:

file = open(r"C:\Users\d_j_d\Desktop\words.txt", 'r').read().split('\n')

It would be a good idea to mention this in the header documentation for the user.

Add docstrings for your functions as well:

def difficulty(minimum, maximum):
    """
    Set the difficulty level of the game.
    Input minimum: minimum length of the word
    Input maximum: maximum length of the word
    """
\$\endgroup\$

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.