anycoder-b520a23b / index.html
mhpalestine's picture
Upload folder using huggingface_hub
2058d5f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game with Admin Panel</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #6c5ce7;
--secondary: #a29bfe;
--accent: #00cec9;
--dark: #2d3436;
--light: #dfe6e9;
--success: #00b894;
--danger: #d63031;
--warning: #fdcb6e;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
min-height: 100vh;
color: #fff;
}
header {
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.logo {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.5rem;
font-weight: bold;
color: var(--accent);
}
.logo i {
font-size: 2rem;
}
.built-with {
color: var(--secondary);
text-decoration: none;
font-size: 0.9rem;
transition: color 0.3s;
}
.built-with:hover {
color: var(--accent);
}
.nav-buttons {
display: flex;
gap: 1rem;
}
.nav-btn {
padding: 0.5rem 1.5rem;
border: none;
border-radius: 25px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.nav-btn.game-btn {
background: var(--accent);
color: var(--dark);
}
.nav-btn.admin-btn {
background: var(--primary);
color: #fff;
}
.nav-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3);
}
main {
padding: 2rem;
max-width: 1400px;
margin: 0 auto;
}
.game-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 2rem;
}
.game-info {
display: flex;
gap: 3rem;
flex-wrap: wrap;
justify-content: center;
}
.info-card {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
padding: 1rem 2rem;
border-radius: 15px;
text-align: center;
min-width: 150px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.info-card h3 {
font-size: 0.9rem;
color: var(--secondary);
margin-bottom: 0.5rem;
}
.info-card .value {
font-size: 2rem;
font-weight: bold;
color: var(--accent);
}
.game-board-wrapper {
position: relative;
}
#gameCanvas {
background: linear-gradient(145deg, #1a1a2e, #0f0f1a);
border-radius: 15px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5),
inset 0 0 60px rgba(108, 92, 231, 0.1);
border: 3px solid var(--primary);
}
.game-controls {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
}
.control-btn {
padding: 1rem 2rem;
border: none;
border-radius: 30px;
cursor: pointer;
font-weight: 600;
font-size: 1rem;
transition: all 0.3s;
display: flex;
align-items: center;
gap: 0.5rem;
}
.control-btn.start {
background: linear-gradient(135deg, var(--success), #00a884);
color: #fff;
}
.control-btn.pause {
background: linear-gradient(135deg, var(--warning), #e5b85c);
color: var(--dark);
}
.control-btn.restart {
background: linear-gradient(135deg, var(--danger), #b52828);
color: #fff;
}
.control-btn:hover {
transform: scale(1.05);
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.3);
}
.mobile-controls {
display: none;
grid-template-columns: repeat(3, 60px);
grid-template-rows: repeat(3, 60px);
gap: 5px;
margin-top: 1rem;
}
.mobile-btn {
background: rgba(255, 255, 255, 0.1);
border: 2px solid var(--primary);
border-radius: 10px;
color: #fff;
font-size: 1.5rem;
cursor: pointer;
transition: all 0.2s;
}
.mobile-btn:active {
background: var(--primary);
transform: scale(0.95);
}
.mobile-btn.up { grid-column: 2; grid-row: 1; }
.mobile-btn.left { grid-column: 1; grid-row: 2; }
.mobile-btn.right { grid-column: 3; grid-row: 2; }
.mobile-btn.down { grid-column: 2; grid-row: 3; }
/* Admin Panel Styles */
.admin-container {
display: none;
}
.admin-header {
text-align: center;
margin-bottom: 2rem;
}
.admin-header h1 {
font-size: 2.5rem;
color: var(--accent);
margin-bottom: 0.5rem;
}
.admin-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2rem;
}
.admin-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border-radius: 20px;
padding: 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.admin-card h2 {
color: var(--secondary);
margin-bottom: 1.5rem;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.3rem;
}
.setting-group {
margin-bottom: 1.5rem;
}
.setting-group label {
display: block;
margin-bottom: 0.5rem;
color: var(--light);
font-weight: 500;
}
.setting-group input[type="range"] {
width: 100%;
height: 8px;
border-radius: 4px;
background: rgba(255, 255, 255, 0.1);
outline: none;
-webkit-appearance: none;
}
.setting-group input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--accent);
cursor: pointer;
box-shadow: 0 2px 10px rgba(0, 206, 201, 0.5);
}
.setting-group input[type="number"],
.setting-group input[type="text"],
.setting-group select {
width: 100%;
padding: 0.75rem;
border: 2px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
font-size: 1rem;
transition: border-color 0.3s;
}
.setting-group input:focus,
.setting-group select:focus {
border-color: var(--accent);
outline: none;
}
.color-picker-group {
display: flex;
align-items: center;
gap: 1rem;
}
.color-picker-group input[type="color"] {
width: 50px;
height: 50px;
border: none;
border-radius: 10px;
cursor: pointer;
background: transparent;
}
.toggle-switch {
display: flex;
align-items: center;
gap: 1rem;
}
.toggle-switch input {
display: none;
}
.toggle-slider {
width: 60px;
height: 30px;
background: rgba(255, 255, 255, 0.1);
border-radius: 15px;
position: relative;
cursor: pointer;
transition: background 0.3s;
}
.toggle-slider::before {
content: '';
position: absolute;
width: 24px;
height: 24px;
background: #fff;
border-radius: 50%;
top: 3px;
left: 3px;
transition: transform 0.3s;
}
.toggle-switch input:checked + .toggle-slider {
background: var(--accent);
}
.toggle-switch input:checked + .toggle-slider::before {
transform: translateX(30px);
}
.save-btn {
width: 100%;
padding: 1rem;
background: linear-gradient(135deg, var(--primary), var(--secondary));
border: none;
border-radius: 10px;
color: #fff;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
margin-top: 1rem;
}
.save-btn:hover {
transform: translateY(-2px);
box-shadow: 0 10px 30px rgba(108, 92, 231, 0.4);
}
.leaderboard {
max-height: 300px;
overflow-y: auto;
}
.leaderboard-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
margin-bottom: 0.5rem;
transition: background 0.3s;
}
.leaderboard-item:hover {
background: rgba(255, 255, 255, 0.1);
}
.leaderboard-item .rank {
width: 30px;
height: 30px;
background: var(--primary);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.leaderboard-item .rank.gold { background: #ffd700; color: #000; }
.leaderboard-item .rank.silver { background: #c0c0c0; color: #000; }
.leaderboard-item .rank.bronze { background: #cd7f32; color: #000; }
.leaderboard-item .name {
flex: 1;
margin-left: 1rem;
}
.leaderboard-item .score {
font-weight: bold;
color: var(--accent);
}
.clear-btn {
background: var(--danger);
padding: 0.5rem 1rem;
border: none;
border-radius: 5px;
color: #fff;
cursor: pointer;
margin-top: 1rem;
transition: all 0.3s;
}
.clear-btn:hover {
background: #b52828;
}
/* Game Over Modal */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(5px);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: linear-gradient(145deg, #1a1a2e, #16213e);
padding: 3rem;
border-radius: 20px;
text-align: center;
border: 2px solid var(--primary);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
animation: modalPop 0.3s ease;
}
@keyframes modalPop {
from {
transform: scale(0.8);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.modal-content h2 {
font-size: 2.5rem;
color: var(--danger);
margin-bottom: 1rem;
}
.modal-content .final-score {
font-size: 4rem;
color: var(--accent);
font-weight: bold;
margin: 1rem 0;
}
.modal-content input {
padding: 0.75rem 1.5rem;
border: 2px solid var(--primary);
border-radius: 10px;
background: rgba(0, 0, 0, 0.3);
color: #fff;
font-size: 1rem;
margin: 1rem 0;
width: 100%;
max-width: 250px;
}
.modal-buttons {
display: flex;
gap: 1rem;
justify-content: center;
margin-top: 1.5rem;
}
.instructions {
background: rgba(255, 255, 255, 0.05);
padding: 1.5rem;
border-radius: 15px;
margin-top: 1rem;
text-align: left;
}
.instructions h3 {
color: var(--accent);
margin-bottom: 1rem;
}
.instructions ul {
list-style: none;
}
.instructions li {
padding: 0.5rem 0;
display: flex;
align-items: center;
gap: 0.5rem;
}
.instructions li i {
color: var(--primary);
}
@media (max-width: 768px) {
header {
flex-direction: column;
gap: 1rem;
padding: 1rem;
}
.game-info {
gap: 1rem;
}
.info-card {
padding: 0.75rem 1.5rem;
min-width: 100px;
}
.info-card .value {
font-size: 1.5rem;
}
.mobile-controls {
display: grid;
}
.admin-grid {
grid-template-columns: 1fr;
}
#gameCanvas {
max-width: 100%;
height: auto;
}
}
@media (max-width: 480px) {
.nav-buttons {
flex-direction: column;
width: 100%;
}
.nav-btn {
justify-content: center;
}
.game-controls {
flex-direction: column;
width: 100%;
}
.control-btn {
justify-content: center;
}
}
</style>
</head>
<body>
<header>
<div class="logo">
<i class="fas fa-dragon"></i>
<span>Snake Game</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="built-with">
Built with anycoder
</a>
<div class="nav-buttons">
<button class="nav-btn game-btn" onclick="showGame()">
<i class="fas fa-gamepad"></i> Play Game
</button>
<button class="nav-btn admin-btn" onclick="showAdmin()">
<i class="fas fa-cog"></i> Admin Panel
</button>
</div>
</header>
<main>
<!-- Game Container -->
<div class="game-container" id="gameSection">
<div class="game-info">
<div class="info-card">
<h3><i class="fas fa-star"></i> Score</h3>
<div class="value" id="currentScore">0</div>
</div>
<div class="info-card">
<h3><i class="fas fa-trophy"></i> High Score</h3>
<div class="value" id="highScore">0</div>
</div>
<div class="info-card">
<h3><i class="fas fa-ruler"></i> Length</h3>
<div class="value" id="snakeLength">3</div>
</div>
<div class="info-card">
<h3><i class="fas fa-tachometer-alt"></i> Speed</h3>
<div class="value" id="currentSpeed">5</div>
</div>
</div>
<div class="game-board-wrapper">
<canvas id="gameCanvas" width="400" height="400"></canvas>
</div>
<div class="game-controls">
<button class="control-btn start" id="startBtn" onclick="startGame()">
<i class="fas fa-play"></i> Start
</button>
<button class="control-btn pause" id="pauseBtn" onclick="togglePause()">
<i class="fas fa-pause"></i> Pause
</button>
<button class="control-btn restart" onclick="restartGame()">
<i class="fas fa-redo"></i> Restart
</button>
</div>
<div class="mobile-controls">
<button class="mobile-btn up" onclick="changeDirection('up')"><i class="fas fa-arrow-up"></i></button>
<button class="mobile-btn left" onclick="changeDirection('left')"><i class="fas fa-arrow-left"></i></button>
<button class="mobile-btn right" onclick="changeDirection('right')"><i class="fas fa-arrow-right"></i></button>
<button class="mobile-btn down" onclick="changeDirection('down')"><i class="fas fa-arrow-down"></i></button>
</div>
<div class="instructions">
<h3><i class="fas fa-info-circle"></i> How to Play</h3>
<ul>
<li><i class="fas fa-arrow-up"></i><i class="fas fa-arrow-down"></i><i class="fas fa-arrow-left"></i><i class="fas fa-arrow-right"></i> Use Arrow Keys or WASD to move</li>
<li><i class="fas fa-apple-alt"></i> Eat food to grow and score points</li>
<li><i class="fas fa-skull"></i> Don't hit the walls or yourself!</li>
<li><i class="fas fa-bolt"></i> Speed increases as you grow</li>
</ul>
</div>
</div>
<!-- Admin Container -->
<div class="admin-container" id="adminSection">
<div class="admin-header">
<h1><i class="fas fa-cog"></i> Admin Panel</h1>
<p>Customize your Snake Game experience</p>
</div>
<div class="admin-grid">
<!-- Game Settings -->
<div class="admin-card">
<h2><i class="fas fa-sliders-h"></i> Game Settings</h2>
<div class="setting-group">
<label>Initial Speed (1-10): <span id="speedValue">5</span></label>
<input type="range" id="gameSpeed" min="1" max="10" value="5" oninput="updateSpeedValue()">
</div>
<div class="setting-group">
<label>Grid Size</label>
<select id="gridSize">
<option value="10">Small (10x10)</option>
<option value="20" selected>Medium (20x20)</option>
<option value="30">Large (30x30)</option>
</select>
</div>
<div class="setting-group">
<label>Points per Food</label>
<input type="number" id="pointsPerFood" value="10" min="1" max="100">
</div>
<div class="setting-group">
<label>Speed Increase Rate</label>
<input type="range" id="speedIncrease" min="0" max="10" value="5" oninput="updateSpeedIncreaseValue()">
<span id="speedIncreaseValue">5</span>
</div>
<div class="setting-group toggle-switch">
<label>Wall Collision</label>
<input type="checkbox" id="wallCollision" checked>
<span class="toggle-slider" onclick="toggleWallCollision()"></span>
</div>
<button class="save-btn" onclick="saveGameSettings()">
<i class="fas fa-save"></i> Save Settings
</button>
</div>
<!-- Appearance Settings -->
<div class="admin-card">
<h2><i class="fas fa-palette"></i> Appearance</h2>
<div class="setting-group">
<label>Snake Color</label>
<div class="color-picker-group">
<input type="color" id="snakeColor" value="#00cec9">
<span>Primary snake color</span>
</div>
</div>
<div class="setting-group">
<label>Snake Head Color</label>
<div class="color-picker-group">
<input type="color" id="snakeHeadColor" value="#00b894">
<span>Head highlight color</span>
</div>
</div>
<div class="setting-group">
<label>Food Color</label>
<div class="color-picker-group">
<input type="color" id="foodColor" value="#d63031">
<span>Food item color</span>
</div>
</div>
<div class="setting-group">
<label>Background Color</label>
<div class="color-picker-group">
<input type="color" id="bgColor" value="#1a1a2e">
<span>Game board background</span>
</div>
</div>
<div class="setting-group">
<label>Grid Lines Color</label>
<div class="color-picker-group">
<input type="color" id="gridColor" value="#2d3436">
<span>Grid line color</span>
</div>
</div>
<div class="setting-group toggle-switch">
<label>Show Grid Lines</label>
<input type="checkbox" id="showGrid" checked>
<span class="toggle-slider" onclick="toggleGrid()"></span>
</div>
<button class="save-btn" onclick="saveAppearanceSettings()">
<i class="fas fa-save"></i> Save Appearance
</button>
</div>
<!-- Leaderboard -->
<div class="admin-card">
<h2><i class="fas fa-trophy"></i> Leaderboard</h2>
<div class="leaderboard" id="leaderboard">
<!-- Leaderboard items will be inserted here -->
</div>
<button class="clear-btn" onclick="clearLeaderboard()">
<i class="fas fa-trash"></i> Clear Leaderboard
</button>
</div>
<!-- Statistics -->
<div class="admin-card">
<h2><i class="fas fa-chart-bar"></i> Statistics</h2>
<div class="setting-group">
<label>Total Games Played</label>
<input type="text" id="totalGames" value="0" readonly>
</div>
<div class="setting-group">
<label>Highest Score Ever</label>
<input type="text" id="highestScore" value="0" readonly>
</div>
<div class="setting-group">
<label>Total Food Eaten</label>
<input type="text" id="totalFood" value="0" readonly>
</div>
<div class="setting-group">
<label>Average Score</label>
<input type="text" id="avgScore" value="0" readonly>
</div>
<button class="clear-btn" onclick="resetStatistics()">
<i class="fas fa-undo"></i> Reset Statistics
</button>
</div>
</div>
</div>
</main>
<!-- Game Over Modal -->
<div class="modal" id="gameOverModal">
<div class="modal-content">
<h2><i class="fas fa-skull-crossbones"></i> Game Over!</h2>
<p>Your Score</p>
<div class="final-score" id="finalScore">0</div>
<input type="text" id="playerName" placeholder="Enter your name" maxlength="20">
<div class="modal-buttons">
<button class="control-btn start" onclick="saveScore()">
<i class="fas fa-save"></i> Save Score
</button>
<button class="control-btn restart" onclick="playAgain()">
<i class="fas fa-redo"></i> Play Again
</button>
</div>
</div>
</div>
<script>
// Game Variables
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
let gridSize = 20;
let tileCount = canvas.width / gridSize;
let snake = [];
let food = { x: 0, y: 0 };
let direction = { x: 0, y: 0 };
let nextDirection = { x: 0, y: 0 };
let score = 0;
let gameLoop = null;
let isPaused = false;
let isGameRunning = false;
// Settings
let settings = {
speed: 5,
gridSize: 20,
pointsPerFood: 10,
speedIncrease: 5,
wallCollision: true,
snakeColor: '#00cec9',
snakeHeadColor: '#00b894',
foodColor: '#d63031',
bgColor: '#1a1a2e',
gridColor: '#2d3436',
showGrid: true
};
// Statistics
let stats = {
totalGames: 0,
highestScore: 0,
totalFood: 0,
scores: []
};
// Leaderboard
let leaderboard = [];
// Load saved data
function loadSavedData() {
const savedSettings = localStorage.getItem('snakeSettings');
const savedStats = localStorage.getItem('snakeStats');
const savedLeaderboard = localStorage.getItem('snakeLeaderboard');
if (savedSettings) settings = JSON.parse(savedSettings);
if (savedStats) stats = JSON.parse(savedStats);
if (savedLeaderboard) leaderboard = JSON.parse(savedLeaderboard);
applySettings();
updateLeaderboard();
updateStatistics();
}
// Initialize game
function initGame() {
tileCount = Math.floor(canvas.width / settings.gridSize);
snake = [
{ x: Math.floor(tileCount / 2), y: Math.floor(tileCount / 2) },
{ x: Math.floor(tileCount / 2) - 1, y: Math.floor(tileCount / 2) },
{ x: Math.floor(tileCount / 2) - 2, y: Math.floor(tileCount / 2) }
];
direction = { x: 0, y: 0 };
nextDirection = { x: 0, y: 0 };
score = 0;
spawnFood();
updateDisplay();
draw();
}
// Spawn food
function spawnFood() {
do {
food.x = Math.floor(Math.random() * tileCount);
food.y = Math.floor(Math.random() * tileCount);
} while (snake.some(segment => segment.x === food.x && segment.y === food.y));
}
// Draw game
function draw() {
// Clear canvas
ctx.fillStyle = settings.bgColor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw grid
if (settings.showGrid) {
ctx.strokeStyle = settings.gridColor;
ctx.lineWidth = 0.5;
for (let i = 0; i <= tileCount; i++) {
ctx.beginPath();
ctx.moveTo(i * settings.gridSize, 0);
ctx.lineTo(i * settings.gridSize, canvas.height);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, i * settings.gridSize);
ctx.lineTo(canvas.width, i * settings.gridSize);
ctx.stroke();
}
}
// Draw food
ctx.fillStyle = settings.foodColor;
ctx.beginPath();
const foodCenterX = food.x * settings.gridSize + settings.gridSize / 2;
const foodCenterY = food.y * settings.gridSize + settings.gridSize / 2;
ctx.arc(foodCenterX, foodCenterY, settings.gridSize / 2 - 2, 0, Math.PI * 2);
ctx.fill();
// Draw food glow
ctx.shadowColor = settings.foodColor;
ctx.shadowBlur = 10;
ctx.fill();
ctx.shadowBlur = 0;
// Draw snake
snake.forEach((segment, index) => {
const isHead = index === 0;
ctx.fillStyle = isHead ? settings.snakeHeadColor : settings.snakeColor;
const x = segment.x * settings.gridSize;
const y = segment.y * settings.gridSize;
const size = settings.gridSize - 2;
const radius = isHead ? 8 : 5;
// Rounded rectangle
ctx.beginPath();
ctx.roundRect(x + 1, y + 1, size, size, radius);
ctx.fill();
// Draw eyes on head
if (isHead) {
ctx.fillStyle = '#fff';
const eyeSize = 4;
const eyeOffset = 5;
if (direction.x === 1) {
ctx.beginPath();
ctx.arc(x + size - eyeOffset, y + eyeOffset + 2, eyeSize, 0, Math.PI * 2);
ctx.arc(x + size - eyeOffset, y + size - eyeOffset - 2, eyeSize, 0, Math.PI * 2);
ctx.fill();
} else if (direction.x === -1) {
ctx.beginPath();
ctx.arc(x + eyeOffset + 2, y + eyeOffset + 2, eyeSize, 0, Math.PI * 2);
ctx.arc(x + eyeOffset + 2, y + size - eyeOffset - 2, eyeSize, 0, Math.PI * 2);
ctx.fill();
} else if (direction.y === -1) {
ctx.beginPath();
ctx.arc(x + eyeOffset + 2, y + eyeOffset + 2, eyeSize, 0, Math.PI * 2);
ctx.arc(x + size - eyeOffset - 2, y + eyeOffset + 2, eyeSize, 0, Math.PI * 2);
ctx.fill();
} else {
ctx.beginPath();
ctx.arc(x + eyeOffset + 2, y + size - eyeOffset - 2, eyeSize, 0, Math.PI * 2);
ctx.arc(x + size - eyeOffset - 2, y + size - eyeOffset - 2, eyeSize, 0, Math.PI * 2);
ctx.fill();
}
}
});
}
// Update game
function update() {
if (isPaused) return;
direction = { ...nextDirection };
// Move snake
const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };
// Wall collision
if (settings.wallCollision) {
if (head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount) {
gameOver();
return;
}
} else {
// Wrap around
if (head.x < 0) head.x = tileCount - 1;
if (head.x >= tileCount) head.x = 0;
if (head.y < 0) head.y = tileCount - 1;
if (head.y >= tileCount) head.y = 0;
}
// Self collision
if (snake.some(segment => segment.x === head.x && segment.y === head.y)) {
gameOver();
return;
}
snake.unshift(head);
// Check food collision
if (head.x === food.x && head.y === food.y) {
score += settings.pointsPerFood;
stats.totalFood++;
spawnFood();
// Increase speed
if (settings.speedIncrease > 0 && snake.length % 5 === 0) {
const newSpeed = Math.min(settings.speed + (settings.speedIncrease / 10), 15);
clearInterval(gameLoop);
gameLoop = setInterval(gameStep, 1000 / (newSpeed * 2));
}
} else {
snake.pop();
}
updateDisplay();
draw();
}
// Game step
function gameStep() {
if (direction.x !== 0 || direction.y !== 0) {
update();
} else {
draw();
}
}
// Start game
function startGame() {
if (isGameRunning) return;
isGameRunning = true;
isPaused = false;
stats.totalGames++;
if (direction.x === 0 && direction.y === 0) {
nextDirection = { x: 1, y: 0 };
}
document.getElementById('startBtn').innerHTML = '<i class="fas fa-play"></i> Playing...';
document.getElementById('startBtn').disabled = true;
gameLoop = setInterval(gameStep, 1000 / (settings.speed * 2));
}
// Toggle pause
function togglePause() {
if (!isGameRunning) return;
isPaused = !isPaused;
const pauseBtn = document.getElementById('pauseBtn');
if (isPaused) {
pauseBtn.innerHTML = '<i class="fas fa-play"></i> Resume';
} else {
pauseBtn.innerHTML = '<i class="fas fa-pause"></i> Pause';
}
}
// Restart game
function restartGame() {
clearInterval(gameLoop);
isGameRunning = false;
isPaused = false;
document.getElementById('startBtn').innerHTML = '<i class="fas fa-play"></i> Start';
document.getElementById('startBtn').disabled = false;
document.getElementById('pauseBtn').innerHTML = '<i class="fas fa-pause"></i> Pause