diff --git a/app/luca/Luca.css b/app/luca/Luca.css index 3e6bd4c..3ba4f37 100644 --- a/app/luca/Luca.css +++ b/app/luca/Luca.css @@ -1,4 +1,4 @@ -/* Luca.css */ +/* Don't mess with that styling please */ .programmer-space { padding: 20px; margin: 10px; @@ -10,22 +10,108 @@ background-color: #4a90e2; /* Blue */ } -.click-button { - padding: 10px 20px; - margin-top: 10px; +/* Snake game container */ +.snake-game-container { + display: flex; + flex-direction: column; /* Stack score and game area vertically */ + align-items: center; /* Center content horizontally */ + background-color: #f5f5f5; /* Light background for contrast */ + border-radius: 12px; /* Rounded corners for a modern touch */ + padding: 20px; +} + +/* Snake game area */ +.snake-game { + position: relative; + width: 400px; /* 20 cells * 20px */ + height: 400px; /* 20 cells * 20px */ + border: 3px solid #4a90e2; /* Accent color border */ + background-color: #222; /* Dark background for the game area */ + box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3); /* Enhanced shadow for better depth */ + border-radius: 8px; /* Rounded corners for the game board */ + margin-top: 20px; /* Space between score and game */ +} + +/* Snake segments */ +.snake-segment { + position: absolute; + width: 20px; + height: 20px; + background-color: #4caf50; /* Modern green */ + border-radius: 6px; /* Rounded corners for the snake segments */ +} + +/* Food */ +.food { + position: absolute; + width: 20px; + height: 20px; + background-color: #f44336; /* Modern red */ + border-radius: 6px; /* Rounded corners for the food */ +} + +/* Game Over message */ +.game-over { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: rgba(0, 0, 0, 0.8); /* Slightly darker overlay for better readability */ + color: #fff; + padding: 20px; + border-radius: 10px; + font-size: 22px; + text-align: center; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.4); /* Enhanced shadow for visibility */ +} + +/* Score display */ +.score { + font-size: 26px; + font-weight: bold; + color: #4a90e2; /* Accent color */ +} + +/* Reload Game Button */ +.button { + background-color: #4CAF50; /* Green background */ border: none; - border-radius: 4px; - background-color: #fff; - color: #4a90e2; - cursor: pointer; - font-size: 16px; -} - -.click-button:hover { - background-color: #e3e3e3; -} - -.lorem-ipsum { + color: white; + padding: 14px 28px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 18px; margin-top: 20px; - font-size: 14px; + cursor: pointer; + border-radius: 8px; + transition: background-color 0.3s ease; +} + +.button:hover { + background-color: #388E3C; /* Darker green for hover effect */ +} + +/* Game Explanation Section */ +.game-explanation { + margin-top: 30px; + padding: 20px; + background-color: #fff; /* Light background for readability */ + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */ + color: #333; +} + +.game-explanation h3 { + margin-bottom: 15px; + font-size: 1.5rem; + color: #4a90e2; /* Accent color */ +} + +.game-explanation p { + margin-bottom: 15px; +} + +.game-explanation ul { + margin-left: 20px; } diff --git a/app/luca/Luca.tsx b/app/luca/Luca.tsx index 170e930..6d851a7 100644 --- a/app/luca/Luca.tsx +++ b/app/luca/Luca.tsx @@ -1,24 +1,40 @@ -// Luca.tsx "use client"; import React, { useState, useEffect, useCallback } from 'react'; import './Luca.css'; // Import specific styles for Luca -const WIDTH = 20; -const HEIGHT = 20; +const GRID_WIDTH = 20; +const GRID_HEIGHT = 20; const CELL_SIZE = 20; const Luca = () => { - // State to keep track of the number of clicks + // State for tracking clicks const [clickCount, setClickCount] = useState(0); - // State and logic for the Snake game + // State for Snake game const [snake, setSnake] = useState([{ x: 5, y: 5 }]); const [food, setFood] = useState({ x: 10, y: 10 }); const [direction, setDirection] = useState('RIGHT'); - const [score, setScore] = useState(0); const [gameOver, setGameOver] = useState(false); + const [gameStarted, setGameStarted] = useState(false); + const [score, setScore] = useState(0); + // Resets the game to its initial state + const resetGame = () => { + setSnake([{ x: 5, y: 5 }]); + setFood(generateRandomFood()); + setDirection('RIGHT'); + setScore(0); + setGameOver(false); + }; + + // Generates a random position for the food + const generateRandomFood = () => ({ + x: Math.floor(Math.random() * GRID_WIDTH), + y: Math.floor(Math.random() * GRID_HEIGHT), + }); + + // Moves the snake based on the current direction const moveSnake = useCallback(() => { if (gameOver) return; @@ -27,44 +43,29 @@ const Luca = () => { // Update head position based on direction switch (direction) { - case 'UP': - head.y -= 1; - break; - case 'DOWN': - head.y += 1; - break; - case 'LEFT': - head.x -= 1; - break; - case 'RIGHT': - head.x += 1; - break; + case 'UP': head.y -= 1; break; + case 'DOWN': head.y += 1; break; + case 'LEFT': head.x -= 1; break; + case 'RIGHT': head.x += 1; break; + default: break; } // Check if the new head position is the food const hasEatenFood = head.x === food.x && head.y === food.y; - // Update the snake's body newSnake = [head, ...newSnake]; if (hasEatenFood) { - // Generate new food position - setFood({ - x: Math.floor(Math.random() * WIDTH), - y: Math.floor(Math.random() * HEIGHT), - }); - setScore(score + 1); // Increase the score + setFood(generateRandomFood()); + setScore(prevScore => prevScore + 1); } else { - // Remove the tail segment if not eating food newSnake.pop(); } // Check for collisions if ( - head.x < 0 || - head.x >= WIDTH || - head.y < 0 || - head.y >= HEIGHT || + head.x < 0 || head.x >= GRID_WIDTH || + head.y < 0 || head.y >= GRID_HEIGHT || newSnake.slice(1).some(seg => seg.x === head.x && seg.y === head.y) ) { setGameOver(true); @@ -72,32 +73,28 @@ const Luca = () => { } setSnake(newSnake); - }, [direction, snake, food, gameOver, score]); + }, [direction, snake, food, gameOver]); + // Set up interval to move the snake if the game is started useEffect(() => { - const interval = setInterval(moveSnake, 200); - return () => clearInterval(interval); - }, [moveSnake]); + if (gameStarted && !gameOver) { + const interval = setInterval(moveSnake, 200); + return () => clearInterval(interval); + } + }, [moveSnake, gameStarted, gameOver]); + // Handle key presses to change the snake's direction const handleKeyDown = (e: KeyboardEvent) => { - // Prevent default behavior for 'W', 'A', 'S', 'D' to avoid scrolling if (['KeyW', 'KeyA', 'KeyS', 'KeyD'].includes(e.code)) { - e.preventDefault(); + e.preventDefault(); // Prevent default behavior for movement keys } switch (e.code) { - case 'KeyW': - if (direction !== 'DOWN') setDirection('UP'); - break; - case 'KeyS': - if (direction !== 'UP') setDirection('DOWN'); - break; - case 'KeyA': - if (direction !== 'RIGHT') setDirection('LEFT'); - break; - case 'KeyD': - if (direction !== 'LEFT') setDirection('RIGHT'); - break; + case 'KeyW': if (direction !== 'DOWN') setDirection('UP'); break; + case 'KeyS': if (direction !== 'UP') setDirection('DOWN'); break; + case 'KeyA': if (direction !== 'RIGHT') setDirection('LEFT'); break; + case 'KeyD': if (direction !== 'LEFT') setDirection('RIGHT'); break; + default: break; } }; @@ -112,73 +109,98 @@ const Luca = () => {
Welcome, Luca! This is your programming space.
{/* Button to count clicks */} -