Code for How to Create a Hangman Game using PyGame in Python Tutorial


View on Github

hangman.py

import pygame
from pygame.locals import *

import os
import random
from string import ascii_letters


pygame.init()
pygame.font.init()

screen = pygame.display.set_mode((400, 500))
pygame.display.set_caption("Hangman")

class Hangman():
    def __init__(self):
        with open("./words.txt", "r") as file:
            # picks secret word
            words = file.read().split("\n")
            self.secret_word = random.choice(words)
            # passing secret word's length for making letter blanks
            self.guessed_word = "*" * len(self.secret_word)
        self.wrong_guesses = []
        self.wrong_guess_count = 0
        self.taking_guess = True
        self.running = True

        self.background_color = (155, 120, 70)
        self.gallow_color = (0,0,0)
        self.body_color = (255,253,175)

        self.font = pygame.font.SysFont("Courier New", 20)
        self.FPS = pygame.time.Clock()


    # draws the gallow
    def _gallow(self):
        stand = pygame.draw.rect(screen, self.gallow_color, pygame.Rect(75, 280, 120, 10))
        body = pygame.draw.rect(screen, self.gallow_color, pygame.Rect(128, 40, 10, 240))
        hanger = pygame.draw.rect(screen, self.gallow_color, pygame.Rect(128, 40, 80, 10))
        rope = pygame.draw.rect(screen, self.gallow_color, pygame.Rect(205, 40,10, 30))


    # draw man's body parts for every wrong guess
    def _man_pieces(self):
        if self.wrong_guess_count == 1:
            head = pygame.draw.circle(screen, self.body_color, [210, 85], 20, 0)
        elif self.wrong_guess_count == 2:
            body = pygame.draw.rect(screen, self.body_color, pygame.Rect(206, 105, 8, 45))
        elif self.wrong_guess_count == 3:
            r_arm = pygame.draw.line(screen, self.body_color, [183, 149], [200, 107], 6)
        elif self.wrong_guess_count == 4:
            l_arm = pygame.draw.line(screen, self.body_color, [231, 149], [218, 107], 6),
        elif self.wrong_guess_count == 5:
            r_leg = pygame.draw.line(screen, self.body_color, [189, 198], [208, 148], 6),
        elif self.wrong_guess_count == 6:
            l_leg = pygame.draw.line(screen, self.body_color, [224, 198], [210, 148], 6)


    def _right_guess(self, guess_letter):
        index_positions = [index for index, item in enumerate(self.secret_word) if item == guess_letter]
        for i in index_positions:
            self.guessed_word = self.guessed_word[0:i] + guess_letter + self.guessed_word[i+1:]
        # stacks a layer of color on guessed word to hide multiple guessed_word stack
        screen.fill(pygame.Color(self.background_color), (10, 370, 390, 20))


    def _wrong_guess(self, guess_letter):
        self.wrong_guesses.append(guess_letter)
        self.wrong_guess_count += 1
        self._man_pieces()


    def _guess_taker(self, guess_letter):
        if guess_letter in ascii_letters:
            if guess_letter in self.secret_word and guess_letter not in self.guessed_word:
                self._right_guess(guess_letter)
            elif guess_letter not in self.secret_word and guess_letter not in self.wrong_guesses:
                self._wrong_guess(guess_letter)


    def _message(self):
        # win situation
        if self.guessed_word == self.secret_word:
            self.taking_guess = False
            screen.fill(pygame.Color(0,0,79), (40, 218, 320, 30))
            message = self.font.render("YOU WIN!!", True, (255,235,0))
            screen.blit(message,(152,224))

        # lose situation
        elif self.wrong_guess_count == 6:
            self.taking_guess = False
            screen.fill(pygame.Color("grey"), (40, 218, 320, 30))
            message = self.font.render("GAME OVER YOU LOSE!!", True, (150,0,10))
            screen.blit(message,(78,224))
            # shows the secret word if the player lose
            word = self.font.render(f"secret word: {self.secret_word}", True, (255,255,255))
            screen.blit(word,(10,300))

        # removes the instruction message if not taking guesses anymore
        if not self.taking_guess:
            screen.fill(pygame.Color(self.background_color), (35, 460, 390, 20))


    def main(self):
        # game's main components (no need to update)
        screen.fill(self.background_color)
        self._gallow()
        instructions = self.font.render('Press any key to take Guess', True, (9,255,78))
        screen.blit(instructions,(35,460))

        while self.running:
            # shows the guessed word in the game window
            guessed_word = self.font.render(f"guessed word: {self.guessed_word}", True, (0,0,138))
            screen.blit(guessed_word,(10,370))
            # shows the wrong guesses in the game window
            wrong_guesses = self.font.render(f"wrong guesses: {' '.join(map(str, self.wrong_guesses))}", True, (125,0,0))
            screen.blit(wrong_guesses,(10,420))

            # checking game state
            self._message()
        
            for self.event in pygame.event.get():
                if self.event.type == pygame.QUIT:
                    self.running = False

                # manages keys pressed
                elif self.event.type == pygame.KEYDOWN:
                    if self.taking_guess:
                        self._guess_taker(self.event.unicode)

            pygame.display.flip()
            self.FPS.tick(60)

        pygame.quit()


if __name__ =="__main__":
    h = Hangman()
    h.main()