Skip to content

Commit ad64a9b

Browse files
Fix Emoji Memory Game for browser compatibility
- Added browser detection for Pyodide - Made input and clear_screen compatible with web app - Fixes steam-bell-92#1394
1 parent bcbfd44 commit ad64a9b

2 files changed

Lines changed: 51 additions & 45 deletions

File tree

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

Lines changed: 45 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,15 @@
2022
}
2123

2224

25+
# Detect if running in browser (Pyodide)
26+
def is_browser():
27+
"""Return True if running in browser environment (Pyodide)."""
28+
try:
29+
import js # Pyodide exposes this global
30+
return True
31+
except ImportError:
32+
return False
33+
2334

2435
# Core, testable logic (no I/O, no global state)
2536

@@ -34,11 +45,7 @@ def get_input_limit(choice):
3445

3546

3647
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-
"""
48+
"""Generate a random emoji sequence for the given level."""
4249
if level < 1:
4350
raise ValueError("level must be >= 1")
4451
return random.choices(emojis, k=level + 2)
@@ -72,17 +79,12 @@ def format_countdown_message(remaining_seconds):
7279

7380

7481
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-
"""
82+
"""Calculate score for a correctly-answered round."""
8083
base = level * 10
8184
streak_bonus = streak * 2
8285
return base + streak_bonus
8386

8487

85-
8688
# I/O helpers
8789

8890
def load_high_score():
@@ -110,34 +112,25 @@ def save_high_score(score):
110112

111113

112114
def clear_screen():
113-
os.system('cls' if os.name == 'nt' else 'clear')
115+
"""Safe clear screen that works in both terminal and browser."""
116+
if is_browser():
117+
print("\n" * 3) # Simple spacing for browser
118+
else:
119+
os.system('cls' if os.name == 'nt' else 'clear')
114120

115121

116122
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-
"""
123+
"""Original fancy countdown (terminal only)."""
131124
remaining = duration
132125
while remaining > 0:
133126
if stop_event.wait(timeout=1):
134-
return # user already answered, stop counting
127+
return
135128
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
129+
sys.stdout.write("\0337")
130+
sys.stdout.write("\033[2A")
131+
sys.stdout.write("\r\033[2K")
139132
sys.stdout.write(format_countdown_message(remaining))
140-
sys.stdout.write("\0338") # restore cursor -> back to input line
133+
sys.stdout.write("\0338")
141134
sys.stdout.flush()
142135

143136

@@ -184,26 +177,33 @@ def main():
184177
time.sleep(display_time)
185178
clear_screen()
186179

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
180+
# Input Phase
190181
print(format_countdown_message(input_time))
191182
print("Type the emojis in order (separated by spaces):")
192183
sys.stdout.write("> ")
193184
sys.stdout.flush()
194185

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

201-
start_time = time.time()
202-
user_input_raw = input().strip()
203-
elapsed = time.time() - start_time
201+
start_time = time.time()
202+
user_input_raw = input().strip()
203+
elapsed = time.time() - start_time
204204

205-
stop_event.set()
206-
timer_thread.join(timeout=0.2)
205+
stop_event.set()
206+
timer_thread.join(timeout=0.2)
207207

208208
user_input = parse_input(user_input_raw)
209209
timed_out = is_timeout(elapsed, input_time)
@@ -261,4 +261,4 @@ def main():
261261

262262

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

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)