#!/usr/bin/env python3 """ Catchphrase Author: Jerick Oates """ import random import time import threading import sys # ---------- CONFIG ---------- WORDS_FILE = "words.txt" # file with one word per line TIMER_SECONDS = 30 # how long the timer runs # ---------- HELPERS ---------- def load_words(path=WORDS_FILE): """Return a list of non‑empty stripped lines from the given file.""" try: with open(path, "r", encoding="utf-8") as f: words = [line.strip() for line in f if line.strip()] if not words: raise ValueError("Word file is empty.") return words except Exception as e: print(f"❌ Error loading words: {e}") sys.exit(1) def pick_random(words): """Return a random word from the list.""" return random.choice(words) # ---------- TIMER THREAD ---------- class CountdownTimer(threading.Thread): """ Background thread that counts down for TIMER_SECONDS. When it finishes, it calls an optional callback. """ def __init__(self, seconds=TIMER_SECONDS, on_finish=None): super().__init__() self.seconds = seconds self.on_finish = on_finish # function to call when timer ends self._running = threading.Event() self._running.set() def run(self): for _ in range(self.seconds): if not self._running.is_set(): break # stopped early by user time.sleep(1) # Timer finished (or was stopped) self._running.clear() if self.on_finish: self.on_finish() # announce completion def stop(self): """Stop the timer before it reaches zero.""" self._running.clear() @property def is_running(self): return self._running.is_set() # ---------- MAIN LOOP ---------- def main(): words = load_words() timer_thread = None print("=== Catchphrase ===") print("Commands:") print(" start – begin the 30‑second timer and show a word immediately") print(" next – show another random word while the timer is running") print(" stop – cancel the timer early") print(" exit / quit – leave the program") # Helper that prints when the timer ends def announce_finish(): print("\n⏰ Time’s up! Returning to menu.") print("=== Catchphrase ===") print("Commands:") print(" start – begin the 30‑second timer and show a word immediately") print(" next – show another random word while the timer is running") print(" stop – cancel the timer early") print(" exit / quit – leave the program") while True: try: cmd = input("\n> ").strip().lower() except EOFError: # Ctrl‑D break if cmd in ("exit", "quit"): if timer_thread and timer_thread.is_running: timer_thread.stop() timer_thread.join() print("👋 Goodbye!") break elif cmd == "start": if timer_thread and timer_thread.is_running: print("[!] Timer is already running.") else: # Start a new timer with the finish callback timer_thread = CountdownTimer(on_finish=announce_finish) timer_thread.daemon = True # exit when main thread exits timer_thread.start() # Show the first word right away print(pick_random(words)) print(f"[+] 30‑second timer started. ({TIMER_SECONDS}s)") elif cmd == "next": if not (timer_thread and timer_thread.is_running): print("[!] No active timer – use 'start' first.") else: print(pick_random(words)) elif cmd == "stop": if timer_thread and timer_thread.is_running: timer_thread.stop() timer_thread.join() print("[+] Timer stopped early.") else: print("[!] There is no running timer to stop.") else: print(f"[!] Unknown command: {cmd}") if __name__ == "__main__": main()