Skip to content

Commit 043ce83

Browse files
authored
Create Number-Guessing-Game.py
1 parent 9a44c00 commit 043ce83

1 file changed

Lines changed: 322 additions & 0 deletions

File tree

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
import sys
2+
import os
3+
import random
4+
import json
5+
import tkinter as tk
6+
from tkinter import ttk, messagebox
7+
import sv_ttk
8+
9+
# =========================
10+
# Resource Path Helper
11+
# =========================
12+
def resource_path(file_name):
13+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
14+
return os.path.join(base_path, file_name)
15+
16+
# =========================
17+
# Globals
18+
# =========================
19+
root = tk.Tk()
20+
root.title("Number Guessing Game with Leaderboard & Stats")
21+
root.geometry("750x600")
22+
# root.iconbitmap(resource_path("logo.ico"))
23+
24+
sv_ttk.set_theme("light")
25+
26+
target_number = None
27+
attempts = 0
28+
max_attempts = 0
29+
score = 0
30+
number_range = (1, 100)
31+
dark_mode_var = tk.BooleanVar(value=False)
32+
difficulty_var = tk.StringVar(value="Medium")
33+
34+
leaderboard_file = resource_path("leaderboard.json")
35+
stats_file = resource_path("player_stats.json")
36+
leaderboard_data = []
37+
player_stats = {
38+
"total_games": 0,
39+
"attempts_list": [],
40+
"high_score_streak": 0,
41+
"current_streak": 0
42+
}
43+
44+
# =========================
45+
# Helper Functions
46+
# =========================
47+
def set_status(msg):
48+
status_var.set(msg)
49+
root.update_idletasks()
50+
51+
def toggle_theme():
52+
style.theme_use("clam")
53+
if dark_mode_var.get():
54+
root.configure(bg="#2E2E2E")
55+
style.configure("TLabel", background="#2E2E2E", foreground="white")
56+
style.configure("TFrame", background="#2E2E2E")
57+
style.configure("TButton", background="#4CAF50", foreground="white")
58+
style.configure("Treeview", background="#3C3C3C", foreground="white", fieldbackground="#3C3C3C")
59+
else:
60+
root.configure(bg="#FFFFFF")
61+
style.configure("TLabel", background="#FFFFFF", foreground="black")
62+
style.configure("TFrame", background="#FFFFFF")
63+
style.configure("TButton", background="#4CAF50", foreground="white")
64+
style.configure("Treeview", background="white", foreground="black", fieldbackground="white")
65+
update_leaderboard_tree()
66+
update_stats_labels()
67+
set_status(f"Theme switched to {'Dark' if dark_mode_var.get() else 'Light'} mode")
68+
69+
# =========================
70+
# Leaderboard Functions
71+
# =========================
72+
def load_leaderboard():
73+
global leaderboard_data
74+
if os.path.exists(leaderboard_file):
75+
try:
76+
with open(leaderboard_file, "r", encoding="utf-8") as f:
77+
leaderboard_data = json.load(f)
78+
except:
79+
leaderboard_data = []
80+
else:
81+
leaderboard_data = []
82+
83+
def save_leaderboard():
84+
with open(leaderboard_file, "w", encoding="utf-8") as f:
85+
json.dump(leaderboard_data, f, indent=4)
86+
87+
def update_leaderboard_tree():
88+
for row in leaderboard_tree.get_children():
89+
leaderboard_tree.delete(row)
90+
for entry in sorted(leaderboard_data, key=lambda x: x["score"], reverse=True)[:10]:
91+
leaderboard_tree.insert("", "end", values=(entry["name"], entry["score"], entry["difficulty"]))
92+
93+
# =========================
94+
# Player Stats Functions
95+
# =========================
96+
def load_stats():
97+
global player_stats
98+
if os.path.exists(stats_file):
99+
try:
100+
with open(stats_file, "r", encoding="utf-8") as f:
101+
player_stats = json.load(f)
102+
except:
103+
player_stats = {
104+
"total_games": 0,
105+
"attempts_list": [],
106+
"high_score_streak": 0,
107+
"current_streak": 0
108+
}
109+
else:
110+
player_stats = {
111+
"total_games": 0,
112+
"attempts_list": [],
113+
"high_score_streak": 0,
114+
"current_streak": 0
115+
}
116+
117+
def save_stats():
118+
with open(stats_file, "w", encoding="utf-8") as f:
119+
json.dump(player_stats, f, indent=4)
120+
121+
def update_stats_labels():
122+
total_games_label.config(text=f"Total Games Played: {player_stats['total_games']}")
123+
avg_attempts = (sum(player_stats['attempts_list']) / len(player_stats['attempts_list'])) if player_stats['attempts_list'] else 0
124+
avg_attempts_label.config(text=f"Average Attempts per Game: {avg_attempts:.2f}")
125+
high_streak_label.config(text=f"High Score Streak: {player_stats['high_score_streak']}")
126+
127+
# =========================
128+
# Difficulty & Game Logic
129+
# =========================
130+
def set_difficulty():
131+
global max_attempts, number_range
132+
diff = difficulty_var.get()
133+
if diff == "Easy":
134+
max_attempts = 15
135+
number_range = (1, 50)
136+
elif diff == "Medium":
137+
max_attempts = 10
138+
number_range = (1, 100)
139+
elif diff == "Hard":
140+
max_attempts = 5
141+
number_range = (1, 200)
142+
start_game()
143+
144+
def start_game():
145+
global target_number, attempts
146+
target_number = random.randint(*number_range)
147+
attempts = 0
148+
feedback_label.config(text="")
149+
attempts_label.config(text=f"Attempts left: {max_attempts}")
150+
guess_entry.delete(0, tk.END)
151+
set_status(f"New game! Guess a number between {number_range[0]} and {number_range[1]}.")
152+
153+
def check_guess():
154+
global attempts, score
155+
guess = guess_entry.get()
156+
if not guess.isdigit():
157+
messagebox.showwarning("Invalid Input", "Please enter a valid number!")
158+
return
159+
guess = int(guess)
160+
attempts += 1
161+
remaining = max_attempts - attempts
162+
diff = abs(target_number - guess)
163+
164+
if guess < target_number:
165+
hint = "📉 Too low!"
166+
elif guess > target_number:
167+
hint = "📈 Too high!"
168+
else:
169+
hint = f"🎉 Correct! The number was {target_number}"
170+
points = max(0, 100 - attempts * 5)
171+
update_score(points)
172+
feedback_label.config(text=hint)
173+
save_score_dialog()
174+
return
175+
176+
if diff <= 2:
177+
hint += " 🔥 Very close!"
178+
elif diff <= 5:
179+
hint += " 😊 Close!"
180+
181+
feedback_label.config(text=hint)
182+
183+
if remaining <= 0:
184+
feedback_label.config(text=f"💥 Game Over! The number was {target_number}")
185+
set_status("Game Over! Start a new game.")
186+
187+
else:
188+
attempts_label.config(text=f"Attempts left: {remaining}")
189+
set_status(f"Attempts used: {attempts}, remaining: {remaining}")
190+
191+
def update_score(points):
192+
global score
193+
score += points
194+
score_label.config(text=f"Score: {score}")
195+
196+
# =========================
197+
# Score Saving
198+
# =========================
199+
def save_score_dialog():
200+
def save_name():
201+
name = name_entry.get().strip()
202+
if name:
203+
# Update leaderboard
204+
leaderboard_data.append({
205+
"name": name,
206+
"score": score,
207+
"difficulty": difficulty_var.get()
208+
})
209+
save_leaderboard()
210+
update_leaderboard_tree()
211+
# Update player stats
212+
player_stats['total_games'] += 1
213+
player_stats['attempts_list'].append(attempts)
214+
# High score streak logic (score >= 80)
215+
if score >= 80:
216+
player_stats['current_streak'] += 1
217+
player_stats['high_score_streak'] = max(player_stats['high_score_streak'], player_stats['current_streak'])
218+
else:
219+
player_stats['current_streak'] = 0
220+
save_stats()
221+
update_stats_labels()
222+
dialog.destroy()
223+
else:
224+
messagebox.showwarning("Invalid Input", "Please enter your name.")
225+
226+
dialog = tk.Toplevel(root)
227+
dialog.title("Save Score")
228+
dialog.geometry("300x150")
229+
ttk.Label(dialog, text=f"Congratulations! Score: {score}", font=("Segoe UI", 12)).pack(pady=10)
230+
ttk.Label(dialog, text="Enter your name:", font=("Segoe UI", 11)).pack(pady=5)
231+
name_entry = ttk.Entry(dialog, font=("Segoe UI", 12))
232+
name_entry.pack(pady=5)
233+
ttk.Button(dialog, text="Save", command=save_name, style="Action.TButton").pack(pady=5)
234+
dialog.grab_set()
235+
236+
# =========================
237+
# Styles
238+
# =========================
239+
style = ttk.Style()
240+
style.theme_use("clam")
241+
style.configure("Action.TButton", font=("Segoe UI", 11, "bold"),
242+
foreground="white", background="#4CAF50", padding=8)
243+
style.map("Action.TButton", background=[("active", "#45a049")])
244+
245+
# =========================
246+
# Status Bar
247+
# =========================
248+
status_var = tk.StringVar(value="Welcome to Number Guessing Game!")
249+
ttk.Label(root, textvariable=status_var, anchor="w", font=("Segoe UI", 10)).pack(side=tk.BOTTOM, fill="x")
250+
251+
# =========================
252+
# Notebook
253+
# =========================
254+
tabs = ttk.Notebook(root)
255+
tabs.pack(expand=True, fill="both", padx=20, pady=20)
256+
257+
# =========================
258+
# Game Tab
259+
# =========================
260+
game_tab = ttk.Frame(tabs, padding=20)
261+
tabs.add(game_tab, text="🎮 Play Game")
262+
263+
# Difficulty
264+
ttk.Label(game_tab, text="Select Difficulty:", font=("Segoe UI", 12)).pack(pady=(5,2))
265+
ttk.Combobox(game_tab, textvariable=difficulty_var, values=["Easy","Medium","Hard"],
266+
state="readonly", font=("Segoe UI", 12)).pack(pady=2)
267+
ttk.Button(game_tab, text="Apply Difficulty", command=set_difficulty, style="Action.TButton").pack(pady=5)
268+
269+
# Guess input
270+
ttk.Label(game_tab, text="Enter your guess:", font=("Segoe UI", 12)).pack(pady=(10,5))
271+
guess_entry = ttk.Entry(game_tab, font=("Segoe UI", 14))
272+
guess_entry.pack(pady=5)
273+
274+
# Feedback, attempts, score
275+
feedback_label = ttk.Label(game_tab, text="", font=("Segoe UI", 12, "bold"))
276+
feedback_label.pack(pady=10)
277+
attempts_label = ttk.Label(game_tab, text=f"Attempts left: {max_attempts}", font=("Segoe UI", 12))
278+
attempts_label.pack(pady=5)
279+
score_label = ttk.Label(game_tab, text=f"Score: {score}", font=("Segoe UI", 12, "bold"))
280+
score_label.pack(pady=5)
281+
282+
# Buttons
283+
ttk.Button(game_tab, text="Start New Game", command=start_game, style="Action.TButton").pack(pady=5)
284+
ttk.Button(game_tab, text="Submit Guess", command=check_guess, style="Action.TButton").pack(pady=5)
285+
286+
# Dark Mode
287+
ttk.Checkbutton(game_tab, text="Dark Mode", variable=dark_mode_var, command=toggle_theme).pack(pady=10)
288+
289+
# =========================
290+
# Leaderboard Tab
291+
# =========================
292+
leader_tab = ttk.Frame(tabs, padding=20)
293+
tabs.add(leader_tab, text="🏆 Leaderboard")
294+
295+
leaderboard_tree = ttk.Treeview(leader_tab, columns=("Name", "Score", "Difficulty"), show="headings", height=15)
296+
leaderboard_tree.heading("Name", text="Name")
297+
leaderboard_tree.heading("Score", text="Score")
298+
leaderboard_tree.heading("Difficulty", text="Difficulty")
299+
leaderboard_tree.pack(fill="both", expand=True, pady=10)
300+
301+
# =========================
302+
# Stats Tab
303+
# =========================
304+
stats_tab = ttk.Frame(tabs, padding=20)
305+
tabs.add(stats_tab, text="📊 Player Stats")
306+
307+
total_games_label = ttk.Label(stats_tab, text="Total Games Played: 0", font=("Segoe UI", 12))
308+
total_games_label.pack(pady=5)
309+
avg_attempts_label = ttk.Label(stats_tab, text="Average Attempts per Game: 0", font=("Segoe UI", 12))
310+
avg_attempts_label.pack(pady=5)
311+
high_streak_label = ttk.Label(stats_tab, text="High Score Streak: 0", font=("Segoe UI", 12))
312+
high_streak_label.pack(pady=5)
313+
314+
# =========================
315+
# Run App
316+
# =========================
317+
load_leaderboard()
318+
load_stats()
319+
update_leaderboard_tree()
320+
update_stats_labels()
321+
set_difficulty()
322+
root.mainloop()

0 commit comments

Comments
 (0)