• Guest, before posting your code please take these rules into consideration:
    • It is required to use our BBCode feature to display your code. While within the editor click < / > or >_ and place your code within the BB Code prompt. This helps others with finding a solution by making it easier to read and easier to copy.
    • Don't share a wall of code. All we want is the problem area, the code related to your issue.

    To learn more about how to use our BBCode feature, please click here.

    Thank you, Code Forum.

tkinter word guessing game/hangman


Legendary Coder
#! /usr/bin/env python3
# Do the imports
import random as rnd
import tkinter as tk
from tkinter import messagebox
import os
import sys
import requests

class Stats:
    ''' Class for keeping stats '''
    wins = 0
    loss = 0
    games = 0
    tries = 0
    remaining = 0

    def __str__(self):
        return f'Stats: Wins: {Stats.wins} / Loss: {Stats.loss} / Games Played: {Stats.games} / Tries Left: {Stats.tries}'

class Model:
        Model for getting a word list from internet
        Creates a list from returned results
        Grabs a random word from the list
        Checks user entered letter against the word
    url = 'https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt'
    response = requests.get(url)
    words = response.text.split('\r\n')

    def __init__(self):
        self.wordlist = Model.words

    def random_word(self):
        word = self.wordlist.pop(rnd.randint(0, len(self.wordlist)-1))
        return word

    def find(self, letter, word, letters):
        match = [i for i, x in enumerate(word) if x == letter]
        if match:
            for i in match:
                letters[i] = letter
                Stats.remaining -= 1
        return ' '.join(letters)

class View:
        View is for showing the game window
    def __init__(self, parent):
        self.parent = parent
        self.parent.columnconfigure(0, weight=1)
        self.parent.rowconfigure(0, weight=0)
        self.parent.rowconfigure(1, weight=0)
        self.parent.rowconfigure(2, weight=0)
        self.parent.rowconfigure(3, weight=1)

        # Setup the header
        header_box = tk.Frame(self.parent)
        header_box.grid(column=0, row=0, sticky='new', padx=5, pady=5)
        header_box.grid_columnconfigure(0, weight=3)

        header = tk.Label(header_box, text='Tkinter Word Game')
        header['font'] = (None, 28, 'bold')
        header.grid(column=0, row=0, sticky='new')

        # Setup stats row
        stats_box = tk.Frame(self.parent)
        stats_box['highlightbackground'] = 'black'
        stats_box['highlightcolor'] = 'black'
        stats_box['highlightthickness'] = 1
        stats_box.grid(column=0, row=1, sticky='new', padx=5, pady=5)
        stats_box.grid_columnconfigure(0, weight=3)

        self.stats = tk.Label(stats_box, anchor='w')
        self.stats['font'] = (None, 10, 'bold')
        self.stats['text'] = Stats()
        self.stats.grid(column=0, row=0, sticky='new', padx=5, pady=5)

        word_box = tk.Frame(self.parent)
        word_box['highlightbackground'] = 'black'
        word_box['highlightcolor'] = 'black'
        word_box['highlightthickness'] = 1
        word_box.grid(column=0, row=2, sticky='new', padx=5, pady=5)
        word_box.grid_columnconfigure(0, weight=0)
        word_box.grid_columnconfigure(1, weight=3)

        label = tk.Label(word_box, text='Random Word: ', anchor='w')
        label['font'] = (None, 10, 'bold')
        label.grid(column=0, row=0, sticky='new', padx=2.5, pady=5)

        self.word = tk.Label(word_box, anchor='w')
        self.word['font'] = (None, 10, 'normal')
        self.word.grid(column=1, row=0, sticky='new', padx=(2.5,5), pady=5)

        # Letter/Button row
        btn_box = tk.Frame(self.parent)
        btn_box['highlightbackground'] = 'black'
        btn_box['highlightcolor'] = 'black'
        btn_box['highlightthickness'] = 1
        btn_box.grid(column=0, row=3, sticky='new', padx=5, pady=5)

        btn_box.grid_columnconfigure(0, weight=1, uniform='btn')
        btn_box.grid_columnconfigure(2, weight=1, uniform='btn')
        btn_box.grid_columnconfigure(3, weight=1, uniform='btn')
        btn_box.grid_columnconfigure(1, weight=3)

        self.letter_btn = tk.Button(btn_box, text='Submit Letter', bg='powderblue')
        self.letter_btn['cursor'] = 'hand2'
        self.letter_btn['activebackground'] = 'skyblue'
        self.letter_btn['activeforeground'] = 'blue'
        self.letter_btn.grid(column=0, row=0, sticky='new', pady=5, padx=(5,2.5))

        self.entry = tk.Entry(btn_box)
        self.entry['font'] = (None, 14, 'normal')
        self.entry.grid(column=1, row=0, sticky='new', pady=5, padx=2.5)

        self.btn_new = tk.Button(btn_box, text='New Word', bg='powderblue')
        self.btn_new['cursor'] = 'hand2'
        self.btn_new['activebackground'] = 'skyblue'
        self.btn_new['activeforeground'] = 'blue'
        self.btn_new.grid(column=2, row=0, sticky='new', pady=5, padx=2.5)

        self.exit_btn = tk.Button(btn_box, text='Quit', bg='tomato')
        self.exit_btn['activebackground'] = 'red'
        self.exit_btn['activeforeground'] = 'white'
        self.exit_btn['cursor'] = 'hand2'
        self.exit_btn.grid(column=3, row=0, sticky='new', pady=5, padx=(2.5, 5))

class Controller:
        Controller class for communictions between the Model and View classes
    def __init__(self, view, model):
        self.view = view
        self.model = model
        self.word = self.model.random_word()
        self.letters = ['-']*len(self.word)
        self.view.word['text'] = self.letters
        Stats.tries = len(self.word) - round(len(self.word)/2)
        Stats.remaining = len(self.word)
        self.view.stats['text'] = Stats()

        # Buttons
        self.view.letter_btn['command'] = lambda: self.find(self.view.entry.get())
        self.view.btn_new['command'] = self.new
        self.view.exit_btn['command'] = self.view.parent.destroy

        # Button Binds
        self.view.parent.bind('<Return>', lambda letter: self.find(letter=self.view.entry.get()))
        self.view.parent.bind('<KP_Enter>', lambda letter: self.find(letter=self.view.entry.get()))

    def new(self):
        Stats.alist = []
        self.view.letter_btn['state'] = 'normal'
        self.view.entry['state'] = 'normal'
        self.word = self.model.random_word()
        self.letters = ['-']*len(self.word)
        self.view.word['text'] = self.letters
        Stats.tries = len(self.word) - round(len(self.word)/2)
        Stats.remaining = len(self.word)
        self.view.stats['text'] = Stats()
        self.view.entry.delete(0, tk.END)

    def find(self, letter):
        done = False
        if not letter or letter.isdigit():
            messagebox.showerror('Error', 'You must enter a letter')
            self.view.entry.delete(0, tk.END)
            Stats.tries += 1

        if len(letter) > 1:
            messagebox.showerror('Error!', 'Only one character can be entered at a time.')
            self.view.entry.delete(0, tk.END)
            Stats.tries += 1

        letter = letter.lower()
        found = self.model.find(letter, self.word, self.letters)

        if letter not in found:
            Stats.tries -= 1
            self.view.entry.delete(0, 'end')

            if Stats.tries == 0:
                self.view.letter_btn['state'] = 'disabled'
                self.view.entry['state'] = 'disabled'
                Stats.games += 1
                done = True
            self.view.entry.delete(0, 'end')
            if Stats.remaining == 0:
                self.view.letter_btn['state'] = 'disabled'
                self.view.entry['state'] = 'disabled'
                Stats.games += 1

        self.view.stats['text'] = Stats()
        if done:
            self.view.word['text'] = self.word
            self.view.word['text'] = found

    def game_over(self):
        messagebox.showinfo('Game Over!', 'You are out of guesses.')
        Stats.loss += 1

    def game_win(self):
        messagebox.showinfo('Congradulations!', 'You got the word!')
        Stats.wins += 1

if __name__ == '__main__':
    root = tk.Tk()
    root.title('Word Guessing Game')
    controller = Controller(View(root), Model())