Skip to content
Merged
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
148 changes: 130 additions & 18 deletions web-app/js/projects/snake.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
function getsnakeGameHTML() {
function getSnakeGameHTML() {
return `
<div class="project-content">
<h2>🐍 Classic Snake Game</h2>
<div class="snake-container">
<div class="controls-top">
<div class="difficulty-box">
<label for="difficultySelect">Difficulty: </label>
<select id="difficultySelect">
<option value="easy">Easy (1x Score)</option>
<option value="medium" selected>Medium (2x Score)</option>
<option value="hard">Hard (3x Score)</option>
</select>
</div>
</div>

<div class="game-area">
<div id="canvas-wrapper" class="ui-canvas-frame">
<canvas id="snakeCanvas" width="600" height="400"></canvas>
Expand All @@ -19,6 +30,10 @@ function getsnakeGameHTML() {
<span>Score</span>
<div id="score">0</div>
</div>
<div class="score-card high-score-card">
<span>Best</span>
<div id="best-score">0</div>
</div>
</div>
</div>

Expand All @@ -40,6 +55,31 @@ function getsnakeGameHTML() {
padding: 20px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.controls-top {
margin-bottom: 15px;
margin-right: 140px; /* Aligns with canvas center offset */
}
.difficulty-box select {
padding: 6px 10px;
border-radius: 6px;
border: 1px solid var(--accent-border, #ccc);
background-color: #ffffff !important; /* Explicitly forces white background */
color: #222222 !important; /* Explicitly forces dark gray/black text */
font-size: 14px;
font-family: inherit;
font-weight: 500;
cursor: pointer;
outline: none;
}
.difficulty-box select {
padding: 4px 8px;
border-radius: 4px;
border: 1px solid #aaa;
background-color: #ffffff;
color: #222222;
font-weight: normal;
cursor: pointer;
}
.game-area {
display: flex;
align-items: flex-start;
Expand All @@ -52,16 +92,16 @@ function getsnakeGameHTML() {
}
#canvas-wrapper {
position: relative;
border: 4px solid var(--success-color);
border: 4px solid var(--success-color, #2ecc71);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 15px 35px rgba(0,0,0,0.3);
}
#snakeCanvas {
background-color: var(--panel-color);
background-color: var(--panel-color, #222);
background-image:
linear-gradient(var(--border-color) 1px, transparent 1px),
linear-gradient(90deg, var(--border-color) 1px, transparent 1px);
linear-gradient(var(--border-color, rgba(255,255,255,0.05)) 1px, transparent 1px),
linear-gradient(90deg, var(--border-color, rgba(255,255,255,0.05)) 1px, transparent 1px);
background-size: 20px 20px;
display: block;
}
Expand All @@ -71,14 +111,18 @@ function getsnakeGameHTML() {
gap: 15px;
}
.score-card {
background: var(--accent-soft);
border: 1px solid var(--accent-border);
color: var(--text-color);
background: var(--accent-soft, #fafafa);
border: 1px solid var(--accent-border, #ddd);
color: var(--text-color, #333);
padding: 10px 25px;
border-radius: 10px;
text-align: center;
min-width: 120px;
box-shadow: var(--shadow);
box-shadow: var(--shadow, 0 4px 6px rgba(0,0,0,0.1));
}
.high-score-card {
border-color: #f1c40f;
background: rgba(241, 196, 15, 0.05);
}
.score-card span {
font-size: 12px;
Expand All @@ -92,15 +136,15 @@ function getsnakeGameHTML() {
.button-group {
display: flex;
justify-content: center;
gap: 30px; /* Space between buttons fixed */
gap: 30px;
margin-top: 10px;
margin-right: 140px; /* Offset to align with canvas center */
margin-right: 140px;
}
.instruction-box {
margin-top: 20px;
margin-right: 140px;
text-align: center;
color: var(--text-secondary);
color: var(--text-secondary, #666);
font-size: 15px;
}
#game-over-overlay {
Expand All @@ -109,31 +153,40 @@ function getsnakeGameHTML() {
left: 0;
width: 100%;
height: 100%;
background: var(--overlay-color);
background: var(--overlay-color, rgba(0, 0, 0, 0.75));
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 10;
color: var(--success-color);
color: var(--success-color, #2ecc71);
}
#game-over-overlay h1 { font-size: 3rem; margin-bottom: 10px; }
.hidden { display: none !important; }
.btn-primary {
padding: 12px 25px;
cursor: pointer;
}
</style>
`;
}

// --- GAME LOGIC ---
// --- GAME LOGIC STATE ---
let direction = { x: 0, y: 0 };
let speed = 7;
let speed = 9; // System baseline operational configuration state
let scoreMultiplier = 2; // Baseline multiplier scalar state
let score = 0;
let lastPaintTime = 0;
let snakeArr = [{ x: 13, y: 10 }];
let food = { x: 6, y: 7 };

// Profile configuration mapping matrices
const CONFIG_DIFFICULTY = {
easy: { speed: 5, multiplier: 1 },
medium: { speed: 9, multiplier: 2 },
hard: { speed: 14, multiplier: 3 }
};

function main(ctime) {
window.requestAnimationFrame(main);
if ((ctime - lastPaintTime) / 1000 < 1 / speed) {
Expand All @@ -154,11 +207,44 @@ function isCollide(snake) {
return false;
}

function applyDifficultySettings() {
const selector = document.getElementById('difficultySelect');
if (selector) {
const value = selector.value;
speed = CONFIG_DIFFICULTY[value].speed;
scoreMultiplier = CONFIG_DIFFICULTY[value].multiplier;
}
}

function updateBestScoreUI() {
const bestScore = localStorage.getItem('snakeBestScore') || 0;
const bestScoreElement = document.getElementById('best-score');
if (bestScoreElement) {
bestScoreElement.innerHTML = bestScore;
}
}

function checkAndSaveHighScore() {
const currentBest = parseInt(localStorage.getItem('snakeBestScore') || '0', 10);
if (score > currentBest) {
localStorage.setItem('snakeBestScore', score);
updateBestScoreUI();
}
}

function gameEngine() {
if (isCollide(snakeArr)) {
direction = { x: 0, y: 0 };
document.getElementById('final-score').innerHTML = score;
document.getElementById('game-over-overlay').classList.remove('hidden');

// Execute persistent local evaluations
checkAndSaveHighScore();

// Restore controls visibility states
const selector = document.getElementById('difficultySelect');
if (selector) selector.disabled = false;

snakeArr = [{ x: 13, y: 10 }];
score = 0;
document.getElementById('score').innerHTML = score;
Expand All @@ -167,7 +253,7 @@ function gameEngine() {

// Eating food
if (snakeArr[0].y === food.y && snakeArr[0].x === food.x) {
score += 1;
score += (1 * scoreMultiplier); // Scaled multiplier calculations
document.getElementById('score').innerHTML = score;
snakeArr.unshift({ x: snakeArr[0].x + direction.x, y: snakeArr[0].y + direction.y });
let a = 2, b = 16;
Expand Down Expand Up @@ -199,11 +285,25 @@ function gameEngine() {
ctx.fillRect(food.x * 20, food.y * 20, 18, 18);
}

// IMPORTANT: Function to initialize listeners after HTML is loaded
// Initialize execution listeners
function initSnakeGame() {
window.requestAnimationFrame(main);

// Set initial historic rendering metrics
updateBestScoreUI();

// Map difficulty listener parameters
const selector = document.getElementById('difficultySelect');
if (selector) {
selector.addEventListener('change', applyDifficultySettings);
}
// Initialize standard values configuration parameters
applyDifficultySettings();

document.getElementById('startGameBtn').addEventListener('click', () => {
applyDifficultySettings();
// Prevent changing parameter matrices on an active engine run
if (selector) selector.disabled = true;
direction = { x: 1, y: 0 }; // Start moving right
});

Expand All @@ -213,13 +313,21 @@ function initSnakeGame() {

document.getElementById('overlayRestartBtn').addEventListener('click', () => {
document.getElementById('game-over-overlay').classList.add('hidden');
if (selector) selector.disabled = false;
direction = { x: 0, y: 0 };
snakeArr = [{ x: 13, y: 10 }];
score = 0;
document.getElementById('score').innerHTML = score;
});

window.addEventListener('keydown', e => {
// Change difficulty selection dynamic evaluations if arrow key registers
if (["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(e.key)) {
if (selector && !selector.disabled) {
selector.disabled = true;
}
}

switch (e.key) {
case "ArrowUp": if (direction.y !== 1) { direction.x = 0; direction.y = -1; } break;
case "ArrowDown": if (direction.y !== -1) { direction.x = 0; direction.y = 1; } break;
Expand All @@ -228,3 +336,7 @@ function initSnakeGame() {
}
});
}

// Global scope assignments
window.getSnakeGameHTML = getSnakeGameHTML;
window.initSnakeGame = initSnakeGame;
Loading