Skip to content

Commit 617cc28

Browse files
Merge branch 'main' into fix-word-scramble-quit
2 parents efac3e5 + 3a3b78c commit 617cc28

15 files changed

Lines changed: 962 additions & 320 deletions

File tree

games/2048-Game/2048-Game.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ def __init__(self, root):
8787
self.board = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]
8888

8989
self.game_over_label = None
90+
self.win_label = None
91+
self.game_won = False
9092

9193
self.create_grid()
9294
self.start_new_game()
@@ -146,6 +148,7 @@ def start_new_game(self):
146148
self.board = [[0] * GRID_SIZE for _ in range(GRID_SIZE)]
147149
self.score = 0
148150
self.moves_left = TOTAL_MOVES
151+
self.game_won = False
149152

150153
self.add_new_tile()
151154
self.add_new_tile()
@@ -261,6 +264,9 @@ def check_game_over(self):
261264

262265
return True
263266

267+
def check_win(self):
268+
return any(2048 in row for row in self.board)
269+
264270
def handle_keypress(self, event):
265271
key = event.keysym.lower() if len(event.keysym) == 1 else event.keysym
266272
move_map = {
@@ -284,11 +290,32 @@ def handle_keypress(self, event):
284290

285291
self.update_grid()
286292

287-
# FIXED BUG:
288-
# Game over is now checked even when no movement happens
293+
if not self.game_won and self.check_win():
294+
self.you_win()
295+
return
296+
297+
# Check for game over even if no movement happens
289298
if self.check_game_over() or self.moves_left <= 0:
290299
self.game_over()
291300

301+
def you_win(self):
302+
303+
if self.game_won:
304+
return
305+
306+
self.game_won = True
307+
308+
self.root.unbind("<Key>")
309+
310+
self.win_label = tk.Label(
311+
self.root,
312+
text="🎉 YOU WIN! 🎉",
313+
font=("Arial", 24, "bold"),
314+
fg="green"
315+
)
316+
317+
self.win_label.grid(pady=10)
318+
292319
def game_over(self):
293320

294321
# Prevent duplicate labels
@@ -314,6 +341,11 @@ def restart_game(self):
314341
self.game_over_label.destroy()
315342
self.game_over_label = None
316343

344+
# Remove old win label
345+
if self.win_label is not None:
346+
self.win_label.destroy()
347+
self.win_label = None
348+
317349
self.start_new_game()
318350

319351
# Re-enable keyboard controls
@@ -325,5 +357,6 @@ def main():
325357
game = Game2048(root)
326358
root.mainloop()
327359

360+
328361
if __name__ == "__main__":
329362
main()

games/Emoji-Memory-Game/Emoji-Memory-Game.py

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import sys
55
import threading
66

7+
# Note: Works best in a terminal. Browser version (Pyodide) uses simplified input.
8+
79
EMOJIS = ["🍎", "🚗", "⚽", "🐍", "🎧", "🔥", "🌈", "🚀"]
810
HIGH_SCORE_FILE = "highscore.txt"
911

@@ -20,6 +22,11 @@
2022
}
2123

2224

25+
# Detect if running in browser (Pyodide)
26+
def is_browser():
27+
"""Return True if running in a browser environment (Pyodide)."""
28+
return sys.platform == "emscripten"
29+
2330

2431
# Core, testable logic (no I/O, no global state)
2532

@@ -34,11 +41,7 @@ def get_input_limit(choice):
3441

3542

3643
def generate_sequence(emojis, level):
37-
"""Generate a random emoji sequence for the given level.
38-
39-
Sequence length grows with level (level + 2), matching the
40-
original game's difficulty curve.
41-
"""
44+
"""Generate a random emoji sequence for the given level."""
4245
if level < 1:
4346
raise ValueError("level must be >= 1")
4447
return random.choices(emojis, k=level + 2)
@@ -72,17 +75,12 @@ def format_countdown_message(remaining_seconds):
7275

7376

7477
def calculate_score(level, streak):
75-
"""Calculate score for a correctly-answered round.
76-
77-
Base score scales with level; a streak bonus rewards consecutive
78-
correct answers.
79-
"""
78+
"""Calculate score for a correctly-answered round."""
8079
base = level * 10
8180
streak_bonus = streak * 2
8281
return base + streak_bonus
8382

8483

85-
8684
# I/O helpers
8785

8886
def load_high_score():
@@ -110,34 +108,25 @@ def save_high_score(score):
110108

111109

112110
def clear_screen():
113-
os.system('cls' if os.name == 'nt' else 'clear')
111+
"""Safe clear screen that works in both terminal and browser."""
112+
if is_browser():
113+
print("\n" * 3) # Simple spacing for browser
114+
else:
115+
os.system('cls' if os.name == 'nt' else 'clear')
114116

115117

116118
def run_countdown(duration, stop_event):
117-
"""Update a single countdown line once per second while waiting for input.
118-
119-
Runs in a background thread. Instead of printing a new line each
120-
tick, it:
121-
1. Saves the cursor's current position (which is on the input
122-
line, wherever the user has typed so far).
123-
2. Moves the cursor up 2 lines to the dedicated countdown line.
124-
3. Clears that line and writes the new remaining-time message.
125-
4. Restores the cursor back to the input line, so the user's
126-
typing is completely undisturbed.
127-
128-
stop_event is set as soon as the user submits their answer, so the
129-
countdown stops immediately rather than continuing to update.
130-
"""
119+
"""Original fancy countdown (terminal only)."""
131120
remaining = duration
132121
while remaining > 0:
133122
if stop_event.wait(timeout=1):
134-
return # user already answered, stop counting
123+
return
135124
remaining -= 1
136-
sys.stdout.write("\0337") # save cursor position
137-
sys.stdout.write("\033[2A") # move up 2 lines -> countdown line
138-
sys.stdout.write("\r\033[2K") # jump to col 0 and clear the line
125+
sys.stdout.write("\0337")
126+
sys.stdout.write("\033[2A")
127+
sys.stdout.write("\r\033[2K")
139128
sys.stdout.write(format_countdown_message(remaining))
140-
sys.stdout.write("\0338") # restore cursor -> back to input line
129+
sys.stdout.write("\0338")
141130
sys.stdout.flush()
142131

143132

@@ -184,26 +173,33 @@ def main():
184173
time.sleep(display_time)
185174
clear_screen()
186175

187-
# Line 1: countdown line (updated in place by run_countdown)
188-
# Line 2: static prompt text
189-
# Line 3: "> " where the user actually types
176+
# Input Phase
190177
print(format_countdown_message(input_time))
191178
print("Type the emojis in order (separated by spaces):")
192179
sys.stdout.write("> ")
193180
sys.stdout.flush()
194181

195-
stop_event = threading.Event()
196-
timer_thread = threading.Thread(
197-
target=run_countdown, args=(input_time, stop_event), daemon=True
198-
)
199-
timer_thread.start()
182+
if is_browser():
183+
# Simplified version for browser (no threads/ANSI)
184+
print("\n⚠️ Browser mode active - enter your answer below.")
185+
start_time = time.time()
186+
user_input_raw = input().strip()
187+
elapsed = time.time() - start_time
188+
else:
189+
# Original fancy terminal version
190+
stop_event = threading.Event()
191+
timer_thread = threading.Thread(
192+
target=run_countdown, args=(
193+
input_time, stop_event), daemon=True
194+
)
195+
timer_thread.start()
200196

201-
start_time = time.time()
202-
user_input_raw = input().strip()
203-
elapsed = time.time() - start_time
197+
start_time = time.time()
198+
user_input_raw = input().strip()
199+
elapsed = time.time() - start_time
204200

205-
stop_event.set()
206-
timer_thread.join(timeout=0.2)
201+
stop_event.set()
202+
timer_thread.join(timeout=0.2)
207203

208204
user_input = parse_input(user_input_raw)
209205
timed_out = is_timeout(elapsed, input_time)
@@ -261,4 +257,4 @@ def main():
261257

262258

263259
if __name__ == '__main__':
264-
main()
260+
main()

games/FLAMES-Game/FLAMES-Game.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,23 @@
44

55
def main():
66
global char, choice, count, final, flames, index, mapping, matched_chars, name1, name1_list, name2, name2_list, original_name1, original_name2, result, score, share_text, total_len, valid_game
7+
8+
# Session statistics tracker
9+
session = {
10+
"rounds": 0,
11+
"results": {r: 0 for r in "FLAMES"},
12+
"total_score": 0,
13+
}
14+
15+
mapping = {
16+
'F': {"rel": "Friends", "emoji": "🤝", "metric": "Bond Strength"},
17+
'L': {"rel": "Love", "emoji": "❤️", "metric": "Compatibility Score"},
18+
'A': {"rel": "Affection","emoji": "😊", "metric": "Crush Intensity"},
19+
'M': {"rel": "Marriage", "emoji": "💍", "metric": "Marital Bliss"},
20+
'E': {"rel": "Enemies", "emoji": "😈", "metric": "Rivalry Quotient"},
21+
'S': {"rel": "Siblings", "emoji": "🏠", "metric": "Nuisance Factor"},
22+
}
23+
724
while True:
825
print("\n" + "=" * 50)
926
print("🔥 FLAMES GAME - FIND YOUR RELATIONSHIP STATUS! 🔥")
@@ -71,17 +88,13 @@ def main():
7188
flames.pop(index)
7289

7390
result = flames[0]
74-
75-
mapping = {
76-
'F': {"rel": "Friends", "emoji": "🤝", "metric": "Bond Strength"},
77-
'L': {"rel": "Love", "emoji": "❤️", "metric": "Compatibility Score"},
78-
'A': {"rel": "Affection", "emoji": "😊", "metric": "Crush Intensity"},
79-
'M': {"rel": "Marriage", "emoji": "💍", "metric": "Marital Bliss"},
80-
'E': {"rel": "Enemies", "emoji": "😈", "metric": "Rivalry Quotient"},
81-
'S': {"rel": "Siblings", "emoji": "🏠", "metric": "Nuisance Factor"}
82-
}
8391
final = mapping[result]
8492

93+
# Update session statistics
94+
session["rounds"] += 1
95+
session["results"][result] += 1
96+
session["total_score"] += score
97+
8598
print("\n" + "=" * 50)
8699
print("📝 MATCH REPORT CARD")
87100
print("=" * 50)
@@ -107,6 +120,23 @@ def main():
107120
print("⚠️ Invalid choice. Please enter 'y' or 'n'.")
108121

109122
if choice in ('n', 'no'):
123+
# Display session statistics on exit
124+
if session["rounds"] > 0:
125+
avg = session["total_score"] / session["rounds"]
126+
top = max(session["results"], key=session["results"].get)
127+
print("\n" + "=" * 50)
128+
print("📊 SESSION STATS")
129+
print("=" * 50)
130+
print(f" Total Rounds Played : {session['rounds']}")
131+
print("-" * 50)
132+
for letter, count in session["results"].items():
133+
label = mapping[letter]["rel"]
134+
bar = "█" * session["results"][letter]
135+
print(f" {label:<12}: {count:>2} {bar}")
136+
print("-" * 50)
137+
print(f" Most Common Result : {mapping[top]['rel']} {mapping[top]['emoji']}")
138+
print(f" Avg Score : {avg:.1f}%")
139+
print("=" * 50)
110140
print("\n👋 Thanks for playing FLAMES! Goodbye!")
111141
break
112142

games/Word-Building/word_building.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ def Main():
3535
# Game loop
3636
while True:
3737
# User input and validation
38-
user_word = input("Your word: ")
38+
user_word = input("Your word: ").strip()
39+
if not user_word:
40+
print("\nPlease enter a valid word!")
41+
continue
3942
if (bot_word is not None) and (user_word[0].lower() != bot_word[-1].lower()):
4043
print("\nInvalid word! Your word must start with the last letter of bot's word.")
4144
win = False

0 commit comments

Comments
 (0)