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 3c5c8a9..6d851a7 100644 --- a/app/luca/Luca.tsx +++ b/app/luca/Luca.tsx @@ -1,33 +1,205 @@ -// Luca.tsx "use client"; -import React, { useState } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import './Luca.css'; // Import specific styles for Luca +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); - // Function to handle button click - const handleClick = () => { - setClickCount(clickCount + 1); + // 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 [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; + + let newSnake = [...snake]; + let head = { ...newSnake[0] }; + + // 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; + default: break; + } + + // Check if the new head position is the food + const hasEatenFood = head.x === food.x && head.y === food.y; + + newSnake = [head, ...newSnake]; + + if (hasEatenFood) { + setFood(generateRandomFood()); + setScore(prevScore => prevScore + 1); + } else { + newSnake.pop(); + } + + // Check for collisions + if ( + 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); + return; + } + + setSnake(newSnake); + }, [direction, snake, food, gameOver]); + + // Set up interval to move the snake if the game is started + useEffect(() => { + 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) => { + if (['KeyW', 'KeyA', 'KeyS', 'KeyD'].includes(e.code)) { + 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; + default: break; + } + }; + + useEffect(() => { + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [direction]); + return (
Welcome, Luca! This is your programming space.
{/* Button to count clicks */} -