diff --git a/projects_registry.json b/projects_registry.json new file mode 100644 index 00000000..cee7e4df --- /dev/null +++ b/projects_registry.json @@ -0,0 +1,274 @@ +[ + { + "name": "Rock Paper Scissors", + "emoji": "๐Ÿชจ", + "category": "games", + "difficulty": "beginner", + "description": "Battle against the computer in this classic hand game.", + "keywords": [ + "rock", + "paper", + "scissors", + "game", + "battle", + "computer" + ], + "path": "games/Rock-Paper-Scissor/Rock-Paper-Scissor.py" + }, + { + "name": "Dice Rolling", + "emoji": "๐ŸŽฒ", + "category": "games", + "difficulty": "beginner", + "description": "Roll two dice and calculate your fortune with emoji dice!", + "keywords": [ + "dice", + "roll", + "random", + "luck", + "board" + ], + "path": "games/Roling-Dice/Roling-Dice.py" + }, + { + "name": "Coin Flip", + "emoji": "๐Ÿช™", + "category": "games", + "difficulty": "beginner", + "description": "Predict heads or tails โ€” a quick decision maker.", + "keywords": [ + "coin", + "flip", + "heads", + "tails", + "random" + ], + "path": "games/Flipping-toss/Flipping-toss.py" + }, + { + "name": "Number Guessing Game", + "emoji": "๐ŸŽฏ", + "category": "games", + "difficulty": "beginner", + "description": "Guess the computer's secret number with smart hints.", + "keywords": [ + "guess", + "number", + "hints", + "game", + "interactive" + ], + "path": "games/Number-Guessing-Game/Number-Guessing-Game.py" + }, + { + "name": "Hangman Game", + "emoji": "๐ŸŽฎ", + "category": "games", + "difficulty": "intermediate", + "description": "Classic word-guessing game with 6 attempts.", + "keywords": [ + "hangman", + "word", + "guess", + "letters", + "classic" + ], + "path": "games/Hangman-Game/Hangman-Game.py" + }, + { + "name": "FLAMES Game", + "emoji": "๐Ÿ’–", + "category": "games", + "difficulty": "beginner", + "description": "Discover your relationship status with two names!", + "keywords": [ + "flames", + "love", + "relationship", + "names", + "fun" + ], + "path": "games/FLAMES-Game/FLAMES-Game.py" + }, + { + "name": "Fibonacci Series", + "emoji": "โœจ", + "category": "math", + "difficulty": "beginner", + "description": "Generate beautiful Fibonacci sequences visually.", + "keywords": [ + "fibonacci", + "series", + "sequence", + "math", + "pattern" + ], + "path": "math/Fibonacci-Series/Fibonacci-Series.py" + }, + { + "name": "Pascal's Triangle", + "emoji": "๐Ÿ”บ", + "category": "math", + "difficulty": "intermediate", + "description": "Explore mathematical beauty in Pascal's triangle.", + "keywords": [ + "pascal", + "triangle", + "pattern", + "math", + "rows" + ], + "path": "math/Pascal-Triangle/Pascal-Triangle.py" + }, + { + "name": "Armstrong Number Checker", + "emoji": "๐Ÿ’Ž", + "category": "math", + "difficulty": "beginner", + "description": "Check if a number is an Armstrong number with breakdown.", + "keywords": [ + "armstrong", + "number", + "checker", + "narcissistic", + "math" + ], + "path": "math/Armstrong-Number/Armstrong-Number.py" + }, + { + "name": "Simple Calculator", + "emoji": "๐Ÿงฎ", + "category": "math", + "difficulty": "beginner", + "description": "All basic math operations plus power and modulus.", + "keywords": [ + "calculator", + "math", + "arithmetic", + "add", + "subtract" + ], + "path": "math/Simple-Calculator/Simple-Calculator.py" + }, + { + "name": "Prime Number Analyzer", + "emoji": "๐Ÿ”ฑ", + "category": "math", + "difficulty": "intermediate", + "description": "Check, generate, and factorize prime numbers.", + "keywords": [ + "prime", + "factor", + "analyze", + "sieve", + "number theory" + ], + "path": "math/Prime-Number-Analyzer/Prime-Number-Analyzer.py" + }, + { + "name": "Collatz Conjecture", + "emoji": "๐Ÿ”ข", + "category": "math", + "difficulty": "intermediate", + "description": "Explore the famous 3n+1 sequence until it reaches 1.", + "keywords": [ + "collatz", + "conjecture", + "sequence", + "3n+1", + "math" + ], + "path": "math/Collatz-Conjecture/Collatz-Conjecture.py" + }, + { + "name": "Projectile Motion Game", + "emoji": "๐Ÿš€", + "category": "math", + "difficulty": "advanced", + "description": "Launch projectiles and visualize trajectory stats with matplotlib.", + "keywords": [ + "projectile", + "physics", + "simulation", + "trajectory", + "matplotlib" + ], + "path": "math/Projectile-Motion-Game/Projectile-Motion-Game.py" + }, + { + "name": "Derivative Calculator", + "emoji": "โˆ‚", + "category": "math", + "difficulty": "advanced", + "description": "Compute first and nth polynomial derivatives at any point.", + "keywords": [ + "derivative", + "calculus", + "polynomial", + "math", + "algebra" + ], + "path": "math/Derivative-Calculator/Derivative-Calculator.py" + }, + { + "name": "Coordinate to Polar Transformation", + "emoji": "๐Ÿงญ", + "category": "math", + "difficulty": "intermediate", + "description": "Convert Cartesian (x,y) coordinates to polar form.", + "keywords": [ + "polar", + "cartesian", + "coordinate", + "geometry", + "angle" + ], + "path": "math/Coordinate-to-Polar-Transformation/Coordinate-to-Polar-Transformation.py" + }, + { + "name": "AP/GP/AGP/HP Recognizer", + "emoji": "๐Ÿ“", + "category": "math", + "difficulty": "intermediate", + "description": "Identify progression types from any number sequence.", + "keywords": [ + "progression", + "arithmetic", + "geometric", + "harmonic", + "sequence" + ], + "path": "math/AP-GP-AGP-HP-Recognizer/AP-GP-AGP-HP-Recognizer.py" + }, + { + "name": "Morse Code Translator", + "emoji": "๐Ÿ“ป", + "category": "utilities", + "difficulty": "beginner", + "description": "Translate text to Morse code and back โ€” bidirectional.", + "keywords": [ + "morse", + "code", + "translate", + "encrypt", + "dots", + "dashes" + ], + "path": "utilities/Text-to-Morse/Text-to-Morse.py" + }, + { + "name": "Tower of Hanoi", + "emoji": "๐Ÿ—ผ", + "category": "utilities", + "difficulty": "intermediate", + "description": "Solve the classic Tower of Hanoi puzzle step by step.", + "keywords": [ + "tower", + "hanoi", + "puzzle", + "recursion", + "algorithm" + ], + "path": "utilities/Tower-of-Hanoi/Tower-of-Hanoi.py" + } +] \ No newline at end of file diff --git a/search_projects.py b/search_projects.py index cf7884aa..f226f813 100644 --- a/search_projects.py +++ b/search_projects.py @@ -8,504 +8,19 @@ import os import subprocess import sys +import json # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ # Project Registry # โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -PROJECTS = [ - { - "name": "Rock Paper Scissors", - "emoji": "๐Ÿชจ", - "category": "games", - "difficulty": "beginner", - "description": "Battle against the computer in this classic hand game.", - "keywords": ["rock", "paper", "scissors", "game", "battle", "computer"], - "path": "games/Rock-Paper-Scissor/Rock-Paper-Scissor.py", - }, - { - "name": "Dice Rolling", - "emoji": "๐ŸŽฒ", - "category": "games", - "difficulty": "beginner", - "description": "Roll two dice and calculate your fortune with emoji dice!", - "keywords": ["dice", "roll", "random", "luck", "board"], - "path": "games/Roling-Dice/Roling-Dice.py", - }, - { - "name": "Coin Flip", - "emoji": "๐Ÿช™", - "category": "games", - "difficulty": "beginner", - "description": "Predict heads or tails โ€” a quick decision maker.", - "keywords": ["coin", "flip", "heads", "tails", "random"], - "path": "games/Flipping-toss/Flipping-toss.py", - }, - { - "name": "Number Guessing Game", - "emoji": "๐ŸŽฏ", - "category": "games", - "difficulty": "beginner", - "description": "Guess the computer's secret number with smart hints.", - "keywords": ["guess", "number", "hints", "game", "interactive"], - "path": "games/Number-Guessing-Game/Number-Guessing-Game.py", - }, - { - "name": "Hangman Game", - "emoji": "๐ŸŽฎ", - "category": "games", - "difficulty": "intermediate", - "description": "Classic word-guessing game with 6 attempts.", - "keywords": ["hangman", "word", "guess", "letters", "classic"], - "path": "games/Hangman-Game/Hangman-Game.py", - }, - { - "name": "FLAMES Game", - "emoji": "๐Ÿ’–", - "category": "games", - "difficulty": "beginner", - "description": "Discover your relationship status with two names!", - "keywords": ["flames", "love", "relationship", "names", "fun"], - "path": "games/FLAMES-Game/FLAMES-Game.py", - }, - { - "name": "Fibonacci Series", - "emoji": "โœจ", - "category": "math", - "difficulty": "beginner", - "description": "Generate beautiful Fibonacci sequences visually.", - "keywords": ["fibonacci", "series", "sequence", "math", "pattern"], - "path": "math/Fibonacci-Series/Fibonacci-Series.py", - }, - { - "name": "Pascal's Triangle", - "emoji": "๐Ÿ”บ", - "category": "math", - "difficulty": "intermediate", - "description": "Explore mathematical beauty in Pascal's triangle.", - "keywords": ["pascal", "triangle", "pattern", "math", "rows"], - "path": "math/Pascal-Triangle/Pascal-Triangle.py", - }, - { - "name": "Armstrong Number Checker", - "emoji": "๐Ÿ’Ž", - "category": "math", - "difficulty": "beginner", - "description": "Check if a number is an Armstrong number with breakdown.", - "keywords": ["armstrong", "number", "checker", "narcissistic", "math"], - "path": "math/Armstrong-Number/Armstrong-Number.py", - }, - { - "name": "Simple Calculator", - "emoji": "๐Ÿงฎ", - "category": "math", - "difficulty": "beginner", - "description": "All basic math operations plus power and modulus.", - "keywords": ["calculator", "math", "arithmetic", "add", "subtract"], - "path": "math/Simple-Calculator/Simple-Calculator.py", - }, - { - "name": "Prime Number Analyzer", - "emoji": "๐Ÿ”ฑ", - "category": "math", - "difficulty": "intermediate", - "description": "Check, generate, and factorize prime numbers.", - "keywords": ["prime", "factor", "analyze", "sieve", "number theory"], - "path": "math/Prime-Number-Analyzer/Prime-Number-Analyzer.py", - }, - { - "name": "Collatz Conjecture", - "emoji": "๐Ÿ”ข", - "category": "math", - "difficulty": "intermediate", - "description": "Explore the famous 3n+1 sequence until it reaches 1.", - "keywords": ["collatz", "conjecture", "sequence", "3n+1", "math"], - "path": "math/Collatz-Conjecture/Collatz-Conjecture.py", - }, - { - "name": "Projectile Motion Game", - "emoji": "๐Ÿš€", - "category": "math", - "difficulty": "advanced", - "description": "Launch projectiles and visualize trajectory stats with matplotlib.", - "keywords": ["projectile", "physics", "simulation", "trajectory", "matplotlib"], - "path": "math/Projectile-Motion-Game/Projectile-Motion-Game.py", - }, - { - "name": "Derivative Calculator", - "emoji": "โˆ‚", - "category": "math", - "difficulty": "advanced", - "description": "Compute first and nth polynomial derivatives at any point.", - "keywords": ["derivative", "calculus", "polynomial", "math", "algebra"], - "path": "math/Derivative-Calculator/Derivative-Calculator.py", - }, - { - "name": "Coordinate to Polar Transformation", - "emoji": "๐Ÿงญ", - "category": "math", - "difficulty": "intermediate", - "description": "Convert Cartesian (x,y) coordinates to polar form.", - "keywords": ["polar", "cartesian", "coordinate", "geometry", "angle"], - "path": "math/Coordinate-to-Polar-Transformation/Coordinate-to-Polar-Transformation.py", - }, - { - "name": "AP/GP/AGP/HP Recognizer", - "emoji": "๐Ÿ“", - "category": "math", - "difficulty": "intermediate", - "description": "Identify progression types from any number sequence.", - "keywords": ["progression", "arithmetic", "geometric", "harmonic", "sequence"], - "path": "math/AP-GP-AGP-HP-Recognizer/AP-GP-AGP-HP-Recognizer.py", - }, - { - "name": "Morse Code Translator", - "emoji": "๐Ÿ“ป", - "category": "utilities", - "difficulty": "beginner", - "description": "Translate text to Morse code and back โ€” bidirectional.", - "keywords": ["morse", "code", "translate", "encrypt", "dots", "dashes"], - "path": "utilities/Text-to-Morse/Text-to-Morse.py", - }, - { - "name": "Tower of Hanoi", - "emoji": "๐Ÿ—ผ", - "category": "utilities", - "difficulty": "intermediate", - "description": "Solve the classic Tower of Hanoi puzzle step by step.", - "keywords": ["tower", "hanoi", "puzzle", "recursion", "algorithm"], - "path": "utilities/Tower-of-Hanoi/Tower-of-Hanoi.py", - }, -] - -DIFFICULTY_ORDER = {"beginner": 1, "intermediate": 2, "advanced": 3} - -DIFFICULTY_BADGE = { - "beginner": "๐ŸŸข Beginner", - "intermediate": "๐ŸŸก Intermediate", - "advanced": "๐Ÿ”ด Advanced", -} - -CATEGORY_BADGE = { - "games": "๐ŸŽฎ Games", - "math": "๐Ÿ”ข Math", - "utilities": "๐Ÿ”ง Utilities", -} - - -def banner(): - print("\n" + "โ•" * 56) - print(" ๐Ÿ” Python Mini Projects โ€” Interactive Search") - print("โ•" * 56) - - -def divider(): - print("โ”€" * 56) - - -def display_project(idx, p, show_path=False): - print(f"\n [{idx}] {p['emoji']} {p['name']}") - print(f" {CATEGORY_BADGE[p['category']]} {DIFFICULTY_BADGE[p['difficulty']]}") - print(f" {p['description']}") - if show_path: - print(f" ๐Ÿ“‚ {p['path']}") - - -def display_results(results, show_path=False): - if not results: - print("\n โš ๏ธ No projects found. Try a different search term.") - return - print(f"\n โœ… Found {len(results)} project(s):\n") - for idx, p in enumerate(results, start=1): - display_project(idx, p, show_path) - divider() - - -def search_by_keyword(query): - q = query.lower().strip() - return [ - p for p in PROJECTS - if q in p["name"].lower() - or q in p["description"].lower() - or any(q in kw for kw in p["keywords"]) - ] - - -def filter_by_category(category): - return [p for p in PROJECTS if p["category"] == category.lower().strip()] - - -def filter_by_difficulty(level): - return [p for p in PROJECTS if p["difficulty"] == level.lower().strip()] - - -def launch_project(projects): - if not projects: - return - divider() - choice = input(" โ–ถ Enter project number to launch (or press Enter to skip): ").strip() - if not choice: - return - try: - idx = int(choice) - 1 - if 0 <= idx < len(projects): - path = projects[idx]["path"] - if os.path.exists(path): - print(f"\n ๐Ÿš€ Launching: {path}\n") - subprocess.run([sys.executable, path]) - else: - print(f"\n โš ๏ธ File not found: {path}") - print(" Make sure you're running this from the repo root.") - else: - print(" โš ๏ธ Invalid number.") - except ValueError: - print(" โš ๏ธ Please enter a valid number.") - - -def main(): - banner() - - while True: - print(""" - ๐Ÿ“Œ What would you like to do? - - 1 ๐Ÿ” Search by keyword - 2 ๐Ÿ“‚ Browse by category (games / math / utilities) - 3 ๐Ÿ“Š Filter by difficulty (beginner / intermediate / advanced) - 4 ๐Ÿ“‹ List all projects - 5 โŒ Exit -""") - choice = input(" Enter choice (1-5): ").strip() - - if choice == "1": - divider() - query = input(" ๐Ÿ” Search Project: ").strip() - if query: - results = search_by_keyword(query) - display_results(results, show_path=True) - launch_project(results) - else: - print(" โš ๏ธ Please enter a search term.") - - elif choice == "2": - divider() - print(" Categories: games | math | utilities") - cat = input(" ๐Ÿ“‚ Enter category: ").strip() - if cat in ("games", "math", "utilities"): - results = filter_by_category(cat) - display_results(results, show_path=True) - launch_project(results) - else: - print(" โš ๏ธ Unknown category. Use: games, math, or utilities.") - - elif choice == "3": - divider() - print(" Levels: beginner | intermediate | advanced") - level = input(" ๐Ÿ“Š Enter difficulty: ").strip() - if level in ("beginner", "intermediate", "advanced"): - results = filter_by_difficulty(level) - results = sorted(results, key=lambda p: p["name"]) - display_results(results, show_path=True) - launch_project(results) - else: - print(" โš ๏ธ Unknown level. Use: beginner, intermediate, or advanced.") - - elif choice == "4": - all_sorted = sorted( - PROJECTS, - key=lambda p: (p["category"], DIFFICULTY_ORDER[p["difficulty"]]) - ) - display_results(all_sorted, show_path=False) - launch_project(all_sorted) - - elif choice == "5": - print("\n ๐Ÿ‘‹ Happy coding! See you next time.\n") - break - - else: - print(" โš ๏ธ Please enter a number from 1 to 5.") - - -if __name__ == "__main__": - main() -EOFcat > search_projects.py << 'EOF' -""" -๐Ÿ” Interactive Search System for Python Mini Projects -===================================================== -Search, filter, and explore all projects by keyword, -category, or difficulty level. -""" - -import os -import subprocess -import sys - -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -# Project Registry -# โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -PROJECTS = [ - { - "name": "Rock Paper Scissors", - "emoji": "๐Ÿชจ", - "category": "games", - "difficulty": "beginner", - "description": "Battle against the computer in this classic hand game.", - "keywords": ["rock", "paper", "scissors", "game", "battle", "computer"], - "path": "games/Rock-Paper-Scissor/Rock-Paper-Scissor.py", - }, - { - "name": "Dice Rolling", - "emoji": "๐ŸŽฒ", - "category": "games", - "difficulty": "beginner", - "description": "Roll two dice and calculate your fortune with emoji dice!", - "keywords": ["dice", "roll", "random", "luck", "board"], - "path": "games/Roling-Dice/Roling-Dice.py", - }, - { - "name": "Coin Flip", - "emoji": "๐Ÿช™", - "category": "games", - "difficulty": "beginner", - "description": "Predict heads or tails โ€” a quick decision maker.", - "keywords": ["coin", "flip", "heads", "tails", "random"], - "path": "games/Flipping-toss/Flipping-toss.py", - }, - { - "name": "Number Guessing Game", - "emoji": "๐ŸŽฏ", - "category": "games", - "difficulty": "beginner", - "description": "Guess the computer's secret number with smart hints.", - "keywords": ["guess", "number", "hints", "game", "interactive"], - "path": "games/Number-Guessing-Game/Number-Guessing-Game.py", - }, - { - "name": "Hangman Game", - "emoji": "๐ŸŽฎ", - "category": "games", - "difficulty": "intermediate", - "description": "Classic word-guessing game with 6 attempts.", - "keywords": ["hangman", "word", "guess", "letters", "classic"], - "path": "games/Hangman-Game/Hangman-Game.py", - }, - { - "name": "FLAMES Game", - "emoji": "๐Ÿ’–", - "category": "games", - "difficulty": "beginner", - "description": "Discover your relationship status with two names!", - "keywords": ["flames", "love", "relationship", "names", "fun"], - "path": "games/FLAMES-Game/FLAMES-Game.py", - }, - { - "name": "Fibonacci Series", - "emoji": "โœจ", - "category": "math", - "difficulty": "beginner", - "description": "Generate beautiful Fibonacci sequences visually.", - "keywords": ["fibonacci", "series", "sequence", "math", "pattern"], - "path": "math/Fibonacci-Series/Fibonacci-Series.py", - }, - { - "name": "Pascal's Triangle", - "emoji": "๐Ÿ”บ", - "category": "math", - "difficulty": "intermediate", - "description": "Explore mathematical beauty in Pascal's triangle.", - "keywords": ["pascal", "triangle", "pattern", "math", "rows"], - "path": "math/Pascal-Triangle/Pascal-Triangle.py", - }, - { - "name": "Armstrong Number Checker", - "emoji": "๐Ÿ’Ž", - "category": "math", - "difficulty": "beginner", - "description": "Check if a number is an Armstrong number with breakdown.", - "keywords": ["armstrong", "number", "checker", "narcissistic", "math"], - "path": "math/Armstrong-Number/Armstrong-Number.py", - }, - { - "name": "Simple Calculator", - "emoji": "๐Ÿงฎ", - "category": "math", - "difficulty": "beginner", - "description": "All basic math operations plus power and modulus.", - "keywords": ["calculator", "math", "arithmetic", "add", "subtract"], - "path": "math/Simple-Calculator/Simple-Calculator.py", - }, - { - "name": "Prime Number Analyzer", - "emoji": "๐Ÿ”ฑ", - "category": "math", - "difficulty": "intermediate", - "description": "Check, generate, and factorize prime numbers.", - "keywords": ["prime", "factor", "analyze", "sieve", "number theory"], - "path": "math/Prime-Number-Analyzer/Prime-Number-Analyzer.py", - }, - { - "name": "Collatz Conjecture", - "emoji": "๐Ÿ”ข", - "category": "math", - "difficulty": "intermediate", - "description": "Explore the famous 3n+1 sequence until it reaches 1.", - "keywords": ["collatz", "conjecture", "sequence", "3n+1", "math"], - "path": "math/Collatz-Conjecture/Collatz-Conjecture.py", - }, - { - "name": "Projectile Motion Game", - "emoji": "๐Ÿš€", - "category": "math", - "difficulty": "advanced", - "description": "Launch projectiles and visualize trajectory stats with matplotlib.", - "keywords": ["projectile", "physics", "simulation", "trajectory", "matplotlib"], - "path": "math/Projectile-Motion-Game/Projectile-Motion-Game.py", - }, - { - "name": "Derivative Calculator", - "emoji": "โˆ‚", - "category": "math", - "difficulty": "advanced", - "description": "Compute first and nth polynomial derivatives at any point.", - "keywords": ["derivative", "calculus", "polynomial", "math", "algebra"], - "path": "math/Derivative-Calculator/Derivative-Calculator.py", - }, - { - "name": "Coordinate to Polar Transformation", - "emoji": "๐Ÿงญ", - "category": "math", - "difficulty": "intermediate", - "description": "Convert Cartesian (x,y) coordinates to polar form.", - "keywords": ["polar", "cartesian", "coordinate", "geometry", "angle"], - "path": "math/Coordinate-to-Polar-Transformation/Coordinate-to-Polar-Transformation.py", - }, - { - "name": "AP/GP/AGP/HP Recognizer", - "emoji": "๐Ÿ“", - "category": "math", - "difficulty": "intermediate", - "description": "Identify progression types from any number sequence.", - "keywords": ["progression", "arithmetic", "geometric", "harmonic", "sequence"], - "path": "math/AP-GP-AGP-HP-Recognizer/AP-GP-AGP-HP-Recognizer.py", - }, - { - "name": "Morse Code Translator", - "emoji": "๐Ÿ“ป", - "category": "utilities", - "difficulty": "beginner", - "description": "Translate text to Morse code and back โ€” bidirectional.", - "keywords": ["morse", "code", "translate", "encrypt", "dots", "dashes"], - "path": "utilities/Text-to-Morse/Text-to-Morse.py", - }, - { - "name": "Tower of Hanoi", - "emoji": "๐Ÿ—ผ", - "category": "utilities", - "difficulty": "intermediate", - "description": "Solve the classic Tower of Hanoi puzzle step by step.", - "keywords": ["tower", "hanoi", "puzzle", "recursion", "algorithm"], - "path": "utilities/Tower-of-Hanoi/Tower-of-Hanoi.py", - }, -] +REGISTRY_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "projects_registry.json") + +try: + with open(REGISTRY_PATH, "r", encoding="utf-8") as f: + PROJECTS = json.load(f) +except Exception as e: + print(f"Error loading project registry: {e}") + PROJECTS = [] DIFFICULTY_ORDER = {"beginner": 1, "intermediate": 2, "advanced": 3} diff --git a/utilities/Progress-Tracker/Progress-Tracker.py b/utilities/Progress-Tracker/Progress-Tracker.py index 787fccda..38ce83ae 100644 --- a/utilities/Progress-Tracker/Progress-Tracker.py +++ b/utilities/Progress-Tracker/Progress-Tracker.py @@ -10,33 +10,34 @@ # โ”€โ”€ Config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ DATA_FILE = "completed_projects.json" +# Load Project Registry from projects_registry.json +REGISTRY_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "projects_registry.json")) + ALL_PROJECTS = { - "๐ŸŽฒ Games": [ - "Rock-Paper-Scissor", - "Dice-Rolling", - "Coin-Flip", - "Number-Guessing-Game", - "Hangman-Game", - "FLAMES-Game", - ], - "๐Ÿ”ข Math": [ - "Fibonacci-Series", - "Pascals-Triangle", - "Armstrong-Number", - "Simple-Calculator", - "Collatz-Conjecture", - "Prime-Number-Analyzer", - "Projectile-Motion-Game", - "Coordinate-to-Polar-Transformation", - "Derivative-Calculator", - "AP-GP-AGP-HP-Recognizer", - ], - "๐Ÿ” Utilities": [ - "Text-to-Morse", - "Tower-of-Hanoi", - ], + "๐ŸŽฒ Games": [], + "๐Ÿ”ข Math": [], + "๐Ÿ” Utilities": [] +} + +CATEGORY_MAP = { + "games": "๐ŸŽฒ Games", + "math": "๐Ÿ”ข Math", + "utilities": "๐Ÿ” Utilities" } +try: + with open(REGISTRY_PATH, "r", encoding="utf-8") as f: + registry = json.load(f) + for p in registry: + cat_key = CATEGORY_MAP.get(p["category"]) + if cat_key: + parts = p["path"].split("/") + if len(parts) >= 2: + proj_name = parts[-2] + ALL_PROJECTS[cat_key].append(proj_name) +except Exception as e: + print(f"Error loading project registry: {e}") + # Flatten for quick lookup ALL_PROJECT_NAMES = [p for projects in ALL_PROJECTS.values() for p in projects] TOTAL = len(ALL_PROJECT_NAMES) @@ -48,7 +49,26 @@ def load_data() -> dict: """Load saved progress from JSON file, or return a fresh state.""" if os.path.exists(DATA_FILE): with open(DATA_FILE, "r") as f: - return json.load(f) + data = json.load(f) + # Migrate old names to new folder names + migrations = { + "Dice-Rolling": "Roling-Dice", + "Coin-Flip": "Flipping-toss", + "Pascals-Triangle": "Pascal-Triangle" + } + completed = data.get("completed", {}) + updated_completed = {} + mutated = False + for k, v in completed.items(): + if k in migrations: + updated_completed[migrations[k]] = v + mutated = True + else: + updated_completed[k] = v + if mutated: + data["completed"] = updated_completed + save_data(data) + return data return {"completed": {}} # {project_name: "YYYY-MM-DD HH:MM"} diff --git a/web-app/js/projects/progress-tracker.js b/web-app/js/projects/progress-tracker.js index b3c7c1d9..22464d60 100644 --- a/web-app/js/projects/progress-tracker.js +++ b/web-app/js/projects/progress-tracker.js @@ -52,65 +52,151 @@ function getProgressTrackerHTML() { } function initProgressTracker() { - const PROJECTS = { - '๐ŸŽฒ Games': ['Rock-Paper-Scissor','Dice-Rolling','Coin-Flip','Number-Guessing-Game','Hangman-Game','FLAMES-Game'], - '๐Ÿ”ข Math': ['Fibonacci-Series','Pascals-Triangle','Armstrong-Number','Simple-Calculator','Collatz-Conjecture','Prime-Number-Analyzer','Projectile-Motion-Game','Coordinate-to-Polar','Derivative-Calculator','AP-GP-AGP-HP-Recognizer'], - '๐Ÿ” Utilities': ['Text-to-Morse','Tower-of-Hanoi'] - }; - const TOTAL = Object.values(PROJECTS).flat().length; const KEY = 'pt_completed_v1'; + const migrations = { + "Dice-Rolling": "Roling-Dice", + "Coin-Flip": "Flipping-toss", + "Pascals-Triangle": "Pascal-Triangle" + }; - const load = () => { try { return JSON.parse(localStorage.getItem(KEY)) || []; } catch { return []; } }; + const load = () => { + try { + let list = JSON.parse(localStorage.getItem(KEY)) || []; + let mutated = false; + list = list.map(item => { + if (migrations[item]) { + mutated = true; + return migrations[item]; + } + return item; + }); + if (mutated) { + localStorage.setItem(KEY, JSON.stringify(list)); + } + return list; + } catch { + return []; + } + }; const save = (l) => localStorage.setItem(KEY, JSON.stringify(l)); - function render() { - const done = load(); - const count = done.length; - const pct = Math.round((count / TOTAL) * 100); - document.getElementById('pt-bar-fill').style.width = pct + '%'; - document.getElementById('pt-bar-label').textContent = count + ' / ' + TOTAL + ' completed'; - document.getElementById('pt-s-done').textContent = count; - document.getElementById('pt-s-left').textContent = TOTAL - count; - document.getElementById('pt-s-pct').textContent = pct + '%'; - const container = document.getElementById('pt-cats'); - if (!container) return; - container.textContent = ''; - for (const [cat, projects] of Object.entries(PROJECTS)) { - const catDone = projects.filter(p => done.includes(p)).length; - const sec = document.createElement('div'); - sec.textContent = '
' + cat + '  ยท  ' + catDone + '/' + projects.length + '
'; - const grid = document.createElement('div'); - grid.className = 'pt-grid'; - projects.forEach(name => { - const isDone = done.includes(name); - const card = document.createElement('div'); - card.className = 'pt-card' + (isDone ? ' done' : ''); - card.textContent = '' + (isDone ? 'โœ…' : 'โฌœ') + '' + name + ''; - card.onclick = () => toggle(name); - grid.appendChild(card); + fetch('./projects_registry.json') + .then(response => response.json()) + .then(data => { + const PROJECTS = { + '๐ŸŽฒ Games': [], + '๐Ÿ”ข Math': [], + '๐Ÿ” Utilities': [] + }; + const catMap = { + 'games': '๐ŸŽฒ Games', + 'math': '๐Ÿ”ข Math', + 'utilities': '๐Ÿ” Utilities' + }; + data.forEach(p => { + const catKey = catMap[p.category]; + if (catKey) { + const parts = p.path.split('/'); + if (parts.length >= 2) { + const projName = parts[parts.length - 2]; + PROJECTS[catKey].push(projName); + } + } }); - sec.appendChild(grid); - container.appendChild(sec); - } - } - function toggle(name) { - const list = load(); - const idx = list.indexOf(name); - if (idx === -1) { list.push(name); showToast('๐ŸŽŠ "' + name + '" completed!'); if (list.length === TOTAL) showToast('๐Ÿ… All done!'); } - else { list.splice(idx, 1); showToast('โ†ฉ "' + name + '" unmarked'); } - save(list); render(); - } + const TOTAL = Object.values(PROJECTS).flat().length; + + function render() { + const done = load(); + const count = done.length; + const pct = Math.round((count / TOTAL) * 100); + + const barFill = document.getElementById('pt-bar-fill'); + if (barFill) barFill.style.width = pct + '%'; + + const barLabel = document.getElementById('pt-bar-label'); + if (barLabel) barLabel.textContent = count + ' / ' + TOTAL + ' completed'; + + const sDone = document.getElementById('pt-s-done'); + if (sDone) sDone.textContent = count; + + const sLeft = document.getElementById('pt-s-left'); + if (sLeft) sLeft.textContent = TOTAL - count; + + const sPct = document.getElementById('pt-s-pct'); + if (sPct) sPct.textContent = pct + '%'; + + const container = document.getElementById('pt-cats'); + if (!container) return; + container.textContent = ''; + + for (const [cat, projects] of Object.entries(PROJECTS)) { + const catDone = projects.filter(p => done.includes(p)).length; + const sec = document.createElement('div'); + + const catTitle = document.createElement('div'); + catTitle.className = 'pt-cat-title'; + catTitle.innerHTML = cat + '  ยท  ' + catDone + '/' + projects.length; + sec.appendChild(catTitle); + + const grid = document.createElement('div'); + grid.className = 'pt-grid'; + projects.forEach(name => { + const isDone = done.includes(name); + const card = document.createElement('div'); + card.className = 'pt-card' + (isDone ? ' done' : ''); + card.innerHTML = '' + (isDone ? 'โœ…' : 'โฌœ') + '' + name + ''; + card.onclick = () => toggle(name); + grid.appendChild(card); + }); + sec.appendChild(grid); + container.appendChild(sec); + } + } - window.ptSelectAll = function() { save(Object.values(PROJECTS).flat()); render(); showToast('๐Ÿ… All marked done!'); }; - window.ptClearAll = function() { if (confirm('Reset all progress?')) { save([]); render(); showToast('๐Ÿ—‘ Progress cleared'); } }; + function toggle(name) { + const list = load(); + const idx = list.indexOf(name); + if (idx === -1) { + list.push(name); + showToast('๐ŸŽŠ "' + name + '" completed!'); + if (list.length === TOTAL) showToast('๐Ÿ… All done!'); + } else { + list.splice(idx, 1); + showToast('โ†ฉ "' + name + '" unmarked'); + } + save(list); + render(); + } + + window.ptSelectAll = function() { + save(Object.values(PROJECTS).flat()); + render(); + showToast('๐Ÿ… All marked done!'); + }; + window.ptClearAll = function() { + if (confirm('Reset all progress?')) { + save([]); + render(); + showToast('๐Ÿ—‘ Progress cleared'); + } + }; + + render(); + }) + .catch(err => { + console.error('Failed to load projects registry:', err); + const container = document.getElementById('pt-cats'); + if (container) { + container.innerHTML = '
โš ๏ธ Error loading project tracker registry.
'; + } + }); function showToast(msg) { const t = document.getElementById('pt-toast'); if (!t) return; - t.textContent = msg; t.classList.add('show'); + t.textContent = msg; + t.classList.add('show'); setTimeout(() => t.classList.remove('show'), 2800); } - - render(); } \ No newline at end of file diff --git a/web-app/projects_registry.json b/web-app/projects_registry.json new file mode 120000 index 00000000..9fcc53ba --- /dev/null +++ b/web-app/projects_registry.json @@ -0,0 +1 @@ +../projects_registry.json \ No newline at end of file