Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions games/Number-Sliding-Puzzle/Number-Sliding-Puzzle.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import sys
import os

# Point Python to the root directory so it can find the utils folder
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../..')))
from utils.validation import get_int, get_yes_no
import random


print("🧩 Emoji Sliding Puzzle Game 🧩")

while True:
Expand Down Expand Up @@ -37,14 +44,7 @@
print("\n🎉 Congratulations! You solved the puzzle!")
break

try:
choice_str = input("\n🎯 Enter number to move: ").strip()
if not choice_str:
continue
choice = int(choice_str)
except ValueError:
print("❌ Please enter a valid number!")
continue
choice = get_int("\n🎯 Enter number to move: ", min_value=1, max_value=8)

empty_row = 0
empty_col = 0
Expand Down Expand Up @@ -75,10 +75,6 @@

print("\n👋 Thanks for playing Emoji Sliding Puzzle!\n")

while True:
replay = input("🔄 Play again? (y/n): ").strip().lower()
if replay in ['y', 'yes', 'n', 'no']:
break
print("⚠️ Invalid input. Enter 'y' or 'n'.")
if replay in ['n', 'no']:
# get_yes_no loops automatically and returns True for 'y' and False for 'n'
if not get_yes_no("\n🔄 Play again? (y/n): "):
break
145 changes: 88 additions & 57 deletions web-app/js/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,105 @@
// Each project's HTML and logic lives in its own file under js/projects/

const projectInstructions = {
// Project instructions moved to modular files under js/projects/
// Project instructions moved to modular files under js/projects/
};


function toPascalCase(slug) {
return slug.split(/[^a-zA-Z0-9]+/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
return slug
.split(/[^a-zA-Z0-9]+/)
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
.join("");
}

function getProjectHTML(projectName) {
const fnName = 'get' + toPascalCase(projectName) + 'HTML';
if (typeof window[fnName] === 'function') return window[fnName]();
return `<div class="project-content"><p>Project '${projectName}' content not available.</p></div>`;
const fnName = "get" + toPascalCase(projectName) + "HTML";

try {
// 1. Check if the project module actually loaded
if (typeof window[fnName] === "function") {
return window[fnName]();
} else {
// Throw an error so the catch block handles the missing module
throw new Error(`Module ${fnName} is missing or failed to initialize.`);
}
} catch (error) {
// 2. Log it for the developers
console.warn(`[Project Loader] Failed to load ${projectName}:`, error);

// 3. Return a user-friendly UI error state for the user
return `
<div class="project-content error-state" style="text-align: center; padding: 3rem 1rem;">
<div style="font-size: 3rem; margin-bottom: 1rem;">⚠️</div>
<h3 style="color: var(--danger-color, #ff4444); margin-bottom: 0.5rem; font-family: monospace;">
SYSTEM ERROR: PROJECT OFFLINE
</h3>
<p style="color: var(--text-secondary, #a0aec0); margin-bottom: 1.5rem; max-width: 400px; margin-left: auto; margin-right: auto;">
We couldn't initialize the interactive environment for <strong>${projectName}</strong>. The underlying module may be missing or corrupted.
</p>
<button onclick="window.location.reload()"
style="background: var(--primary-color, #4CAF50); color: white; border: none; padding: 0.75rem 1.5rem; border-radius: 6px; cursor: pointer; font-weight: 600; font-family: monospace; transition: opacity 0.2s;">
>_ RETRY_CONNECTION
</button>
</div>
`;
}
}

function getProjectInstructions(projectName) {
// Modules may provide richer instructions; fall back to a simple hint.
const fnName = 'get' + toPascalCase(projectName) + 'Instructions';
if (typeof window[fnName] === 'function') return window[fnName]();
return { title: projectName, steps: ['Open the project and follow on-screen instructions.'] };
// Modules may provide richer instructions; fall back to a simple hint.
const fnName = "get" + toPascalCase(projectName) + "Instructions";
if (typeof window[fnName] === "function") return window[fnName]();
return {
title: projectName,
steps: ["Open the project and follow on-screen instructions."],
};
}


function initializeProject(projectName) {
const initializers = {
"tic-tac-toe": "initTicTacToe",
"rock-paper-scissor": "initRockPaperScissor",
"dice-rolling": "initDiceRolling",
"coin-flip": "initCoinFlip",
"blackjack-21": "initBlackjack",
"number-guessing": "initNumberGuessing",
hangman: "initHangman",
"word-scramble": "initWordScramble",
flames: "initFlames",
"dots-boxes": "initDotsBoxes",
"emoji-memory": "initEmojiMemoryGame",
fibonacci: "initFibonacci",
"binary-search": "initBinarySearch",
"bubble-sort": "initBubbleSort",
"progression-recognizer": "initProgressionRecognizer",
"pascal-triangle": "initPascalTriangle",
armstrong: "initArmstrong",
calculator: "initCalculator",
collatz: "initCollatz",
"prime-analyzer": "initPrimeAnalyzer",
"projectile-motion": "initProjectileMotion",
"coordinate-polar-transform": "initCoordinatePolarTransform",
"derivative-calculator": "initDerivativeCalculator",
"morse-code": "initMorseCode",
"tower-of-hanoi": "initTowerOfHanoi",
"number-converter": "initNumberConverter",
"typing-speed-tester": "initTypingSpeedTester",
"snake-game": "initSnakeGame",
"password-forge": "initPasswordForge",
"spot-the-difference": "initSpotTheDifference",
"whack-a-mole": "initWhackaMole",
"flappy-game": "initFlappyGame",
"productive-pet": "initProductivePet",
"simon-says": "initSimonSays",
"2048-game": "init2048Game",
"color-palette": "initColorPalette",
"math-quiz": "initMathQuiz",
"resume-analyzer": "initAIResumeAnalyzer",
"caesar-cipher": "initCaesarCipher",
};

const initializers = {
'tic-tac-toe': 'initTicTacToe',
'rock-paper-scissor': 'initRockPaperScissor',
'dice-rolling': 'initDiceRolling',
'coin-flip': 'initCoinFlip',
'blackjack-21': 'initBlackjack',
'number-guessing': 'initNumberGuessing',
'hangman': 'initHangman',
'word-scramble': 'initWordScramble',
'flames': 'initFlames',
'dots-boxes': 'initDotsBoxes',
'emoji-memory': 'initEmojiMemoryGame',
'fibonacci': 'initFibonacci',
'binary-search': 'initBinarySearch',
'bubble-sort': 'initBubbleSort',
'progression-recognizer': 'initProgressionRecognizer',
'pascal-triangle': 'initPascalTriangle',
'armstrong': 'initArmstrong',
'calculator': 'initCalculator',
'collatz': 'initCollatz',
'prime-analyzer': 'initPrimeAnalyzer',
'projectile-motion': 'initProjectileMotion',
'coordinate-polar-transform': 'initCoordinatePolarTransform',
'derivative-calculator': 'initDerivativeCalculator',
'morse-code': 'initMorseCode',
'tower-of-hanoi': 'initTowerOfHanoi',
'number-converter': 'initNumberConverter',
'typing-speed-tester': 'initTypingSpeedTester',
'snake-game': 'initSnakeGame',
'password-forge': 'initPasswordForge',
'spot-the-difference': 'initSpotTheDifference',
'whack-a-mole': 'initWhackaMole',
'flappy-game': 'initFlappyGame',
'productive-pet': 'initProductivePet',
'simon-says': 'initSimonSays',
'2048-game': 'init2048Game',
'color-palette': 'initColorPalette',
'math-quiz': 'initMathQuiz',
'resume-analyzer': 'initAIResumeAnalyzer',
'caesar-cipher': 'initCaesarCipher'
};

const initializerName = initializers[projectName];
if (initializerName && typeof window[initializerName] === 'function') {
window[initializerName]();
}
const initializerName = initializers[projectName];
if (initializerName && typeof window[initializerName] === "function") {
window[initializerName]();
}
}
Loading