import tkinter as tk
from tkinter import messagebox, ttk
import random
from PIL import Image, ImageTk
import pygame # For sound
# Global variable to store selected character
SELECTED_CHARACTER = "Default" # Default character
# Define the dictionary with categories and words
word_categories = {
"Animals": ["elephant", "kangaroo", "penguin", "dolphin", "chameleon"],
"Fruits": ["banana", "strawberry", "pineapple", "grapefruit", "mango"],
"Countries": ["japan", "brazil", "finland", "australia", "mexico"]
}
class HangmanGame:
def __init__(self, root, back_callback):
self.root = root
self.back_callback = back_callback # Callback to go back to the menu
self.root.title("Hangman Game")
self.root.geometry("1920x1200")
# Initialize pygame mixer
pygame.mixer.init()
# Load sounds
self.start_sound = "start_sound.mp3"
self.background_music = "background_music.mp3"
self.win_sound = "win_sound.mp3"
self.lose_sound = "lose_sound.mp3"
# Play the starting sound and then load background music
self.play_starting_sound()
# Load the background image
self.bg_image = Image.open("background.jpg")
self.bg_image = self.bg_image.resize((1920, 1200),
Image.Resampling.LANCZOS)
self.bg_photo = ImageTk.PhotoImage(self.bg_image)
# Create a label to display the background image
self.bg_label = tk.Label(root, image=self.bg_photo)
self.bg_label.place(relwidth=1, relheight=1)
# Load character-specific hangman images
self.load_character_images()
# Game Variables
self.category = None
self.word = ""
self.guessed_letters = set()
self.remaining_attempts = 6
# Title Label
self.title_label = tk.Label(root, text="Hangman Game", font=("Arial", 32,
"bold"), bg="#ADD8E6", fg="#2E4A62")
self.title_label.pack(pady=20)
# Category Selection
self.category_label = tk.Label(root, text="Choose a Category:",
font=("Arial", 18), bg="#ADD8E6")
self.category_label.pack(pady=5)
self.category_var = tk.StringVar(value="Select")
self.category_menu = ttk.Combobox(root, textvariable=self.category_var,
values=list(word_categories.keys()), font=("Arial", 16))
self.category_menu.pack(pady=5)
self.start_button = ttk.Button(root, text="Start Game",
command=self.start_game, width=20)
self.start_button.pack(pady=10)
# Word Display
self.word_display = tk.Label(root, text="", font=("Arial", 28, "bold"),
bg="#ADD8E6", fg="#2E4A62")
self.word_display.pack(pady=20)
# Feedback and Attempts Left
self.feedback_label = tk.Label(root, text="", font=("Arial", 18, "italic"),
bg="#ADD8E6", fg="#2E4A62")
self.feedback_label.pack(pady=10)
self.attempts_label = tk.Label(root, text="Attempts Left: 6",
font=("Arial", 18), bg="#ADD8E6", fg="#2E4A62")
self.attempts_label.pack(pady=10)
# Hangman Figure Canvas
self.hangman_label = tk.Label(root, image="")
self.hangman_label.place(x=100, y=100)
# Sound Volume Control
self.volume_label = tk.Label(root, text="Volume Control", font=("Arial",
18), bg="#ADD8E6")
self.volume_label.place(x=100, y=0)
self.volume_slider = tk.Scale(
root,
from_=0,
to=100,
orient="horizontal",
command=self.adjust_volume,
length=300,
sliderlength=20,
font=("Arial", 14)
)
self.volume_slider.set(50)
self.volume_slider.place(x=100, y=40)
# Alphabet Buttons Frame
self.alphabet_frame = tk.Frame(root, bg="#ADD8E6")
self.alphabet_frame.pack(pady=10)
self.create_alphabet_buttons()
# Back Button
self.back_button = ttk.Button(root, text="Back to Menu",
command=self.back_to_menu, width=20)
self.back_button.pack(pady=10)
def load_character_images(self):
"""Load the appropriate set of hangman images based on selected
character."""
global SELECTED_CHARACTER
# Define image paths based on character
if SELECTED_CHARACTER == "Default":
image_prefix = "default_h"
else: # Chill Guy
image_prefix = "chillguy_h"
try:
self.hangman_images = [
Image.open(f"{image_prefix}{i}.jpg") for i in range(1, 8)
]
self.hangman_photos = [
ImageTk.PhotoImage(img.resize((300, 300),
Image.Resampling.LANCZOS))
for img in self.hangman_images
]
except FileNotFoundError as e:
messagebox.showerror("Error", f"Could not load images for
{SELECTED_CHARACTER}: {e}")
# Fallback to default images if character images not found
try:
self.hangman_images = [
Image.open(f"h{i}.jpg") for i in range(1, 8)
]
self.hangman_photos = [
ImageTk.PhotoImage(img.resize((300, 300),
Image.Resampling.LANCZOS))
for img in self.hangman_images
]
except FileNotFoundError:
messagebox.showerror("Error", "Could not load any hangman images!")
def refresh_character(self):
"""Refresh the hangman images when character is changed."""
self.load_character_images()
self.update_hangman_image()
def back_to_menu(self):
"""Go back to the main menu."""
self.back_callback()
def play_starting_sound(self):
"""Play the starting sound effect and then load background music."""
pygame.mixer.Sound(self.start_sound).play()
self.root.after(3000, self.play_background_music)
def play_background_music(self):
"""Play background music in a loop."""
pygame.mixer.music.load(self.background_music)
pygame.mixer.music.play(-1)
def adjust_volume(self, value):
"""Adjust the volume based on the soundbar position."""
volume = int(value) / 100
pygame.mixer.music.set_volume(volume)
def start_game(self):
"""Initialize the game with the selected category."""
self.category = self.category_var.get()
if self.category not in word_categories:
messagebox.showerror("Error", "Please select a valid category!")
return
self.word = random.choice(word_categories[self.category])
self.guessed_letters = set()
self.remaining_attempts = 6
self.update_word_display()
self.feedback_label.config(text="")
self.attempts_label.config(text="Attempts Left: 6")
self.hangman_label.config(image="")
messagebox.showinfo("Game Started", f"Category: {self.category}")
def update_word_display(self):
"""Update the word display with guessed letters."""
displayed_word = " ".join([letter if letter in self.guessed_letters else
"_" for letter in self.word])
self.word_display.config(text=displayed_word)
def make_guess(self, guess):
"""Process a letter guess."""
guess = guess.lower()
if not guess.isalpha() or len(guess) != 1:
self.feedback_label.config(text="Enter a single valid letter.",
fg="red")
return
if guess in self.guessed_letters:
self.feedback_label.config(text="You already guessed that letter!",
fg="red")
return
self.guessed_letters.add(guess)
if guess in self.word:
self.feedback_label.config(text="Correct guess!", fg="green")
else:
self.feedback_label.config(text="Wrong guess!", fg="red")
self.remaining_attempts -= 1
self.update_hangman_image()
self.update_word_display()
self.attempts_label.config(text=f"Attempts Left:
{self.remaining_attempts}")
if set(self.word) <= self.guessed_letters:
pygame.mixer.Sound(self.win_sound).play()
messagebox.showinfo("Congratulations!", f"You guessed the word:
{self.word}")
self.start_game()
elif self.remaining_attempts == 0:
pygame.mixer.Sound(self.lose_sound).play()
messagebox.showinfo("Game Over", f"You ran out of attempts! The word
was: {self.word}")
self.start_game()
def update_hangman_image(self):
"""Display the appropriate hangman image based on remaining attempts."""
if self.remaining_attempts > 0:
self.hangman_label.config(image=self.hangman_photos[6 -
self.remaining_attempts])
def create_alphabet_buttons(self):
"""Create buttons for each letter of the alphabet."""
self.alphabet_frame.config(bg="#ADD8E6")
for i, letter in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
button = tk.Button(
self.alphabet_frame,
text=letter,
font=("Arial", 14, "bold"),
width=3,
command=lambda l=letter: self.make_guess(l),
bg="#90EE90",
fg="#04F489",
activebackground="#A1C4D7",
activeforeground="white"
)
button.grid(row=i // 8, column=i % 8, padx=5, pady=5)
class OptionsMenu:
def __init__(self, root, back_callback):
self.root = root
self.back_callback = back_callback
self.root.title("Options")
self.root.geometry("1920x1200")
try:
self.bg_image = Image.open("options_background.jpg")
self.bg_image = self.bg_image.resize((1920, 1200),
Image.Resampling.LANCZOS)
self.bg_photo = ImageTk.PhotoImage(self.bg_image)
except FileNotFoundError:
print("Error: options_background.jpg not found. Check the file path.")
self.bg_photo = None
if self.bg_photo:
self.bg_label = tk.Label(root, image=self.bg_photo)
self.bg_label.place(x=0, y=0, relwidth=1, relheight=1)
self.content_frame = tk.Frame(root, bg="#ADD8E6")
self.content_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
self.title_label = tk.Label(
self.content_frame,
text="Options Menu",
font=("Arial", 32, "bold"),
bg="#ADD8E6",
fg="#2E4A62"
)
self.title_label.pack(pady=20)
self.character_var = tk.StringVar(value="Default")
self.default_image = Image.open("Default.png").resize((150, 150),
Image.Resampling.LANCZOS)
self.chill_guy_image = Image.open("Chillguy.png").resize((150, 150),
Image.Resampling.LANCZOS)
self.default_photo = ImageTk.PhotoImage(self.default_image)
self.chill_guy_photo = ImageTk.PhotoImage(self.chill_guy_image)
self.default_button = tk.Button(self.content_frame,
image=self.default_photo, command=self.select_default, borderwidth=0)
self.default_button.pack(side=tk.LEFT, padx=20)
self.chill_guy_button = tk.Button(self.content_frame,
image=self.chill_guy_photo, command=self.select_chill_guy, borderwidth=0)
self.chill_guy_button.pack(side=tk.LEFT, padx=20)
self.back_button = ttk.Button(
self.content_frame,
text="Back to Menu",
command=self.back_to_menu,
width=20
)
self.back_button.pack(pady=10)
def select_default(self):
"""Set the character to Default."""
global SELECTED_CHARACTER
SELECTED_CHARACTER = "Default"
messagebox.showinfo("Character Selected", "You have selected Default.")
def select_chill_guy(self):
"""Set the character to Chill Guy."""
global SELECTED_CHARACTER
SELECTED_CHARACTER = "Chill Guy"
messagebox.showinfo("Character Selected", "You have selected Chill Guy.")
def back_to_menu(self):
"""Return to the main menu."""
self.back_callback()
class MainMenu:
def __init__(self, root):
self.root = root
self.root.title("Hangman Game - Main Menu")
self.root.geometry("1920x1200")
self.bg_image = Image.open("background.jpg")
self.bg_image = self.bg_image.resize((1920, 1200),
Image.Resampling.LANCZOS)
self.bg_photo = ImageTk.PhotoImage(self.bg_image)
self.bg_label = tk.Label(root, image=self.bg_photo)
self.bg_label.place(relwidth=1, relheight=1)
self.title_label = tk.Label(root, text="Welcome to Hangman Game!",
font=("Arial", 32, "bold"), bg="#ADD8E6", fg="#2E4A62")
self.title_label.pack(pady=20)
self.start_button = ttk.Button(root, text="Play Game",
command=self.play_game, width=20)
self.start_button.pack(pady=10)
self.options_button = ttk.Button(root, text="Options",
command=self.open_options, width=20)
self.options_button.pack(pady=10)
self.quit_button = ttk.Button(root, text="Quit", command=root.quit,
width=20)
self.quit_button.pack(pady=10)
def play_game(self):
"""Switch to the Hangman game interface."""
self.root.destroy()
self.root = tk.