RiskScan – Professional File & Folder Risk Scanner

Breaking News

Rock–Paper–Scissors Mini-Game in Python with Tkinter

Rock–Paper–Scissors Mini-Game in Python



This Python script creates a GUI-based Rock–Paper–Scissors mini-game using Tkinter. It includes a dark mode toggle, animated computer choice, and a live scoreboard with score animations.

Features:

  • Graphical interface using Tkinter
  • Dark mode toggle
  • Computer choice animation for excitement
  • Live scoreboard with animated updates
  • Supports icons for Rock, Paper, and Scissors (optional)

Full Source Code:


import sys
import os
import tkinter as tk
from tkinter import ttk, scrolledtext
from PIL import Image, ImageTk
import random
import sv_ttk
import threading
import time

# =========================
# Helper: Resource Path
# =========================
def resource_path(file_name):
    """Get absolute path for resources (works with PyInstaller)."""
    base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, file_name)

# =========================
# App Setup
# =========================
root = tk.Tk()
root.title("Rock–Paper–Scissors Mini-Game")
root.geometry("650x600")
sv_ttk.set_theme("light")

# =========================
# Globals
# =========================
choices = ["Rock", "Paper", "Scissors"]
icons = {}
user_choice = tk.StringVar(value="None")
computer_choice = tk.StringVar(value="None")
result_var = tk.StringVar(value="Make your move!")
dark_mode_var = tk.BooleanVar(value=False)
shuffling = False  # Prevent multiple clicks during animation

# Scoreboard
score = {"Wins": 0, "Losses": 0, "Ties": 0}
score_label_values = {"Wins": 0, "Losses": 0, "Ties": 0}

# =========================
# Load Icons
# =========================
def load_icons():
    for choice in choices:
        path = resource_path(f"{choice.lower()}.png")
        if os.path.exists(path):
            img = Image.open(path).resize((64, 64), Image.ANTIALIAS)
            icons[choice] = ImageTk.PhotoImage(img)
        else:
            icons[choice] = None

load_icons()

# =========================
# Helper Functions
# =========================
def set_status(msg):
    status_var.set(msg)
    root.update_idletasks()

def compute_result(user, comp):
    if user == comp:
        return "It's a tie!"
    elif (user == "Rock" and comp == "Scissors") or \
         (user == "Paper" and comp == "Rock") or \
         (user == "Scissors" and comp == "Paper"):
        return "You win! 🎉"
    else:
        return "Computer wins! 💻"

def display_result(user, comp, final_result):
    result_text.config(state="normal")
    result_text.delete("1.0", tk.END)

    # Display user choice
    if icons.get(user):
        result_text.image_create(tk.END, image=icons[user])
        result_text.insert(tk.END, f" You chose {user}\n", "user")
    else:
        result_text.insert(tk.END, f"You chose {user}\n", "user")

    # Display computer choice
    if icons.get(comp):
        result_text.image_create(tk.END, image=icons[comp])
        result_text.insert(tk.END, f" Computer chose {comp}\n", "comp")
    else:
        result_text.insert(tk.END, f"Computer chose {comp}\n", "comp")

    # Display final result
    result_text.insert(tk.END, f"\n{final_result}", "result")
    result_text.config(state="disabled")
    result_var.set(final_result)
    update_scoreboard(final_result)
    set_status(f"You chose {user}, Computer chose {comp} -> {final_result}")

# =========================
# Scoreboard
# =========================
def animate_score(key, new_value):
    current = score_label_values[key]
    step = 1 if new_value > current else -1
    for val in range(current + step, new_value + step, step):
        score_label_values[key] = val
        update_scoreboard_label()
        time.sleep(0.05)

def update_scoreboard(result):
    global score_label_values
    score_label_values = {"Wins": score["Wins"], "Losses": score["Losses"], "Ties": score["Ties"]}
    if "win" in result.lower():
        score["Wins"] += 1
        threading.Thread(target=animate_score, args=("Wins", score["Wins"]), daemon=True).start()
    elif "loss" in result.lower():
        score["Losses"] += 1
        threading.Thread(target=animate_score, args=("Losses", score["Losses"]), daemon=True).start()
    else:
        score["Ties"] += 1
        threading.Thread(target=animate_score, args=("Ties", score["Ties"]), daemon=True).start()

def update_scoreboard_label():
    score_label.config(text=f"Wins: {score_label_values['Wins']}  "
                            f"Losses: {score_label_values['Losses']}  "
                            f"Ties: {score_label_values['Ties']}")

# =========================
# Dark Mode Toggle
# =========================
def toggle_theme():
    if dark_mode_var.get():
        root.configure(bg="#2E2E2E")
        style.configure("TLabel", background="#2E2E2E", foreground="white")
        style.configure("TFrame", background="#2E2E2E")
        style.configure("TButton", background="#444444", foreground="white")
        result_text.configure(bg="#3A3A3A", fg="white", insertbackground="white")
        score_label.configure(bg="#2E2E2E", fg="white")
    else:
        root.configure(bg="#FFFFFF")
        style.configure("TLabel", background="#FFFFFF", foreground="black")
        style.configure("TFrame", background="#FFFFFF")
        style.configure("TButton", background="#e0e0e0", foreground="black")
        result_text.configure(bg="white", fg="black", insertbackground="black")
        score_label.configure(bg="#FFFFFF", fg="black")
    set_status(f"Theme switched to {'Dark' if dark_mode_var.get() else 'Light'} mode")

# =========================
# Animate Computer Choice
# =========================
def shuffle_computer(user_choice_selected, iterations=15, delay=50):
    global shuffling
    if shuffling:
        return
    shuffling = True
    count = [0]

    def animate():
        nonlocal count
        if count[0] < iterations:
            temp_choice = random.choice(choices)
            computer_choice.set(temp_choice)
            result_text.config(state="normal")
            result_text.delete("1.0", tk.END)
            if icons.get(user_choice_selected):
                result_text.image_create(tk.END, image=icons[user_choice_selected])
                result_text.insert(tk.END, f" You chose {user_choice_selected}\n", "user")
            else:
                result_text.insert(tk.END, f"You chose {user_choice_selected}\n", "user")
            result_text.insert(tk.END, f" Computer is choosing...\n", "comp")
            result_text.config(state="disabled")
            count[0] += 1
            root.after(delay, animate)
        else:
            final_comp = random.choice(choices)
            computer_choice.set(final_comp)
            final_result = compute_result(user_choice_selected, final_comp)
            display_result(user_choice_selected, final_comp, final_result)
            global shuffling
            shuffling = False

    animate()

def play(choice):
    shuffle_computer(choice)

# =========================
# Styles
# =========================
style = ttk.Style()
style.theme_use("clam")
style.configure("Action.TButton", font=("Segoe UI", 12, "bold"),
                foreground="white", background="#4CAF50", padding=10)
style.map("Action.TButton", background=[("active", "#45a049")])
style.configure("TLabel", font=("Segoe UI", 12))

# =========================
# Status Bar
# =========================
status_var = tk.StringVar(value="Ready")
ttk.Label(root, textvariable=status_var, anchor="w", font=("Segoe UI", 10)).pack(side=tk.BOTTOM, fill="x")

# =========================
# Main Frame
# =========================
main_frame = ttk.Frame(root, padding=20)
main_frame.pack(expand=True, fill="both")

ttk.Label(main_frame, text="Rock–Paper–Scissors Mini-Game", font=("Segoe UI", 18, "bold")).pack(pady=10)
ttk.Label(main_frame, text="Choose your move:", font=("Segoe UI", 12)).pack(pady=5)

button_frame = ttk.Frame(main_frame)
button_frame.pack(pady=10)

for c in choices:
    btn = ttk.Button(button_frame, text=c, command=lambda ch=c: play(ch), style="Action.TButton")
    btn.pack(side="left", padx=5)

# Result display
result_text = scrolledtext.ScrolledText(main_frame, height=10, font=("Consolas", 12))
result_text.pack(fill="both", expand=True, pady=15)
result_text.tag_configure("user", foreground="#4CAF50", font=("Consolas", 12, "bold"))
result_text.tag_configure("comp", foreground="#F44336", font=("Consolas", 12, "bold"))
result_text.tag_configure("result", foreground="#2196F3", font=("Consolas", 14, "bold"))
result_text.config(state="disabled")

# Scoreboard
score_label = tk.Label(main_frame, text=f"Wins: 0  Losses: 0  Ties: 0", font=("Segoe UI", 12, "bold"))
score_label.pack(pady=5)

# Dark mode toggle
ttk.Checkbutton(main_frame, text="Dark Mode", variable=dark_mode_var, command=toggle_theme).pack(pady=10)

# =========================
# Run App
# =========================
root.mainloop()

Copy and save this script as rps_game.py and run it with Python 3. Make sure to have Pillow and sv_ttk installed via pip:

pip install pillow sv_ttk

You can optionally add Rock, Paper, and Scissors PNG icons in the same folder to enhance the display.

Download or Explore Useful Tools

Check out more useful tools and downloads here: MateTools on Gumroad

No comments