jeromegenevray commited on
Commit
65b4d4f
·
verified ·
1 Parent(s): 1a9762d

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +726 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Jerome
3
- emoji: 📊
4
- colorFrom: indigo
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: jerome
3
+ emoji: 🐳
4
+ colorFrom: red
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,726 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Pacman Game</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <style>
9
+ @keyframes pacman-mouth {
10
+ 0% { clip-path: polygon(50% 50%, 100% 0%, 100% 100%); }
11
+ 50% { clip-path: polygon(50% 50%, 100% 25%, 100% 75%); }
12
+ 100% { clip-path: polygon(50% 50%, 100% 0%, 100% 100%); }
13
+ }
14
+
15
+ @keyframes ghost-movement {
16
+ 0% { transform: translateY(0); }
17
+ 50% { transform: translateY(-5px); }
18
+ 100% { transform: translateY(0); }
19
+ }
20
+
21
+ .pacman {
22
+ animation: pacman-mouth 0.7s infinite;
23
+ clip-path: polygon(50% 50%, 100% 0%, 100% 100%);
24
+ }
25
+
26
+ .ghost {
27
+ animation: ghost-movement 2s infinite;
28
+ }
29
+
30
+ .maze {
31
+ background-color: #000033;
32
+ position: relative;
33
+ overflow: hidden;
34
+ }
35
+
36
+ .wall {
37
+ background-color: #0000AA;
38
+ }
39
+
40
+ .pellet {
41
+ width: 8px;
42
+ height: 8px;
43
+ background-color: #FFD700;
44
+ border-radius: 50%;
45
+ position: absolute;
46
+ }
47
+
48
+ .power-pellet {
49
+ width: 16px;
50
+ height: 16px;
51
+ background-color: #FFD700;
52
+ border-radius: 50%;
53
+ position: absolute;
54
+ animation: pulse 1s infinite;
55
+ }
56
+
57
+ @keyframes pulse {
58
+ 0% { transform: scale(1); opacity: 1; }
59
+ 50% { transform: scale(1.2); opacity: 0.7; }
60
+ 100% { transform: scale(1); opacity: 1; }
61
+ }
62
+
63
+ .game-over {
64
+ display: none;
65
+ position: absolute;
66
+ top: 0;
67
+ left: 0;
68
+ width: 100%;
69
+ height: 100%;
70
+ background-color: rgba(0, 0, 0, 0.8);
71
+ z-index: 100;
72
+ flex-direction: column;
73
+ justify-content: center;
74
+ align-items: center;
75
+ }
76
+
77
+ .controls {
78
+ touch-action: none;
79
+ }
80
+ </style>
81
+ </head>
82
+ <body class="bg-gray-900 text-white font-sans">
83
+ <div class="container mx-auto px-4 py-8 max-w-md">
84
+ <div class="flex justify-between items-center mb-4">
85
+ <div class="text-2xl font-bold text-yellow-400">PACMAN</div>
86
+ <div class="flex items-center space-x-4">
87
+ <div class="bg-gray-800 px-4 py-2 rounded-lg">
88
+ <span class="text-yellow-400">Score: </span>
89
+ <span id="score" class="font-bold">0</span>
90
+ </div>
91
+ <div class="bg-gray-800 px-4 py-2 rounded-lg">
92
+ <span class="text-red-400">Lives: </span>
93
+ <span id="lives" class="font-bold">3</span>
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <div class="relative maze w-full aspect-square rounded-lg overflow-hidden mb-4" id="maze">
99
+ <div id="pacman" class="pacman absolute w-8 h-8 bg-yellow-400 rounded-full z-10"></div>
100
+
101
+ <!-- Ghosts -->
102
+ <div id="blinky" class="ghost absolute w-8 h-8 rounded-t-full z-10" style="background-color: #FF0000;"></div>
103
+ <div id="pinky" class="ghost absolute w-8 h-8 rounded-t-full z-10" style="background-color: #FFB8FF;"></div>
104
+ <div id="inky" class="ghost absolute w-8 h-8 rounded-t-full z-10" style="background-color: #00FFFF;"></div>
105
+ <div id="clyde" class="ghost absolute w-8 h-8 rounded-t-full z-10" style="background-color: #FFB852;"></div>
106
+
107
+ <!-- Game over overlay -->
108
+ <div id="game-over" class="game-over">
109
+ <div class="text-4xl font-bold text-red-500 mb-4">GAME OVER</div>
110
+ <div class="text-2xl mb-6">Final Score: <span id="final-score" class="text-yellow-400">0</span></div>
111
+ <button id="restart-btn" class="bg-yellow-500 hover:bg-yellow-600 text-black font-bold py-2 px-6 rounded-full">
112
+ PLAY AGAIN
113
+ </button>
114
+ </div>
115
+ </div>
116
+
117
+ <div class="controls bg-gray-800 p-4 rounded-lg">
118
+ <div class="flex justify-center mb-2">
119
+ <button id="up-btn" class="bg-gray-700 hover:bg-gray-600 w-12 h-12 rounded-full flex items-center justify-center">
120
+
121
+ </button>
122
+ </div>
123
+ <div class="flex justify-center space-x-12">
124
+ <button id="left-btn" class="bg-gray-700 hover:bg-gray-600 w-12 h-12 rounded-full flex items-center justify-center">
125
+
126
+ </button>
127
+ <button id="right-btn" class="bg-gray-700 hover:bg-gray-600 w-12 h-12 rounded-full flex items-center justify-center">
128
+
129
+ </button>
130
+ </div>
131
+ <div class="flex justify-center mt-2">
132
+ <button id="down-btn" class="bg-gray-700 hover:bg-gray-600 w-12 h-12 rounded-full flex items-center justify-center">
133
+
134
+ </button>
135
+ </div>
136
+ </div>
137
+ </div>
138
+
139
+ <script>
140
+ document.addEventListener('DOMContentLoaded', () => {
141
+ // Game variables
142
+ let score = 0;
143
+ let lives = 3;
144
+ let gameRunning = true;
145
+ let direction = 'right';
146
+ let nextDirection = 'right';
147
+ let pacmanSpeed = 5;
148
+ let ghostSpeed = 3;
149
+ let scaredGhosts = false;
150
+ let scaredTimer = null;
151
+ let pelletsEaten = 0;
152
+ const totalPellets = 240; // Approximate number of pellets
153
+
154
+ // DOM elements
155
+ const maze = document.getElementById('maze');
156
+ const pacman = document.getElementById('pacman');
157
+ const blinky = document.getElementById('blinky');
158
+ const pinky = document.getElementById('pinky');
159
+ const inky = document.getElementById('inky');
160
+ const clyde = document.getElementById('clyde');
161
+ const scoreDisplay = document.getElementById('score');
162
+ const livesDisplay = document.getElementById('lives');
163
+ const gameOverDisplay = document.getElementById('game-over');
164
+ const finalScoreDisplay = document.getElementById('final-score');
165
+ const restartBtn = document.getElementById('restart-btn');
166
+
167
+ // Control buttons
168
+ const upBtn = document.getElementById('up-btn');
169
+ const downBtn = document.getElementById('down-btn');
170
+ const leftBtn = document.getElementById('left-btn');
171
+ const rightBtn = document.getElementById('right-btn');
172
+
173
+ // Maze dimensions
174
+ const mazeWidth = maze.offsetWidth;
175
+ const mazeHeight = maze.offsetHeight;
176
+ const cellSize = 20;
177
+ const cols = Math.floor(mazeWidth / cellSize);
178
+ const rows = Math.floor(mazeHeight / cellSize);
179
+
180
+ // Initialize positions
181
+ let pacmanPos = {
182
+ x: Math.floor(cols / 2) * cellSize,
183
+ y: Math.floor(rows / 2) * cellSize
184
+ };
185
+
186
+ let ghosts = [
187
+ { element: blinky, x: 3 * cellSize, y: 3 * cellSize, color: '#FF0000', speed: ghostSpeed, direction: 'right', scared: false },
188
+ { element: pinky, x: (cols - 4) * cellSize, y: 3 * cellSize, color: '#FFB8FF', speed: ghostSpeed, direction: 'left', scared: false },
189
+ { element: inky, x: 3 * cellSize, y: (rows - 4) * cellSize, color: '#00FFFF', speed: ghostSpeed, direction: 'right', scared: false },
190
+ { element: clyde, x: (cols - 4) * cellSize, y: (rows - 4) * cellSize, color: '#FFB852', speed: ghostSpeed, direction: 'left', scared: false }
191
+ ];
192
+
193
+ // Maze layout (1 = wall, 0 = path)
194
+ const mazeLayout = [
195
+ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
196
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
197
+ [1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1],
198
+ [1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1],
199
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
200
+ [1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,0,1],
201
+ [1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1],
202
+ [1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,1],
203
+ [0,0,0,1,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0],
204
+ [1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,0,1,1,1,1],
205
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
206
+ [1,0,1,1,0,1,1,0,1,1,1,1,0,1,1,0,1,1,0,1],
207
+ [1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1],
208
+ [1,1,0,1,0,1,0,1,1,1,1,1,1,0,1,0,1,0,1,1],
209
+ [1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1],
210
+ [1,0,1,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,1],
211
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
212
+ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
213
+ ];
214
+
215
+ // Create maze walls
216
+ function createMaze() {
217
+ maze.innerHTML = '';
218
+
219
+ // Add Pacman back to the maze
220
+ maze.appendChild(pacman);
221
+
222
+ // Add ghosts back to the maze
223
+ ghosts.forEach(ghost => {
224
+ maze.appendChild(ghost.element);
225
+ });
226
+
227
+ // Create walls
228
+ for (let y = 0; y < rows; y++) {
229
+ for (let x = 0; x < cols; x++) {
230
+ if (mazeLayout[y] && mazeLayout[y][x] === 1) {
231
+ const wall = document.createElement('div');
232
+ wall.className = 'wall absolute';
233
+ wall.style.width = `${cellSize}px`;
234
+ wall.style.height = `${cellSize}px`;
235
+ wall.style.left = `${x * cellSize}px`;
236
+ wall.style.top = `${y * cellSize}px`;
237
+ maze.appendChild(wall);
238
+ }
239
+ }
240
+ }
241
+
242
+ // Create pellets
243
+ for (let y = 0; y < rows; y++) {
244
+ for (let x = 0; x < cols; x++) {
245
+ if (mazeLayout[y] && mazeLayout[y][x] === 0) {
246
+ // Skip positions near ghosts' starting points
247
+ const isNearGhostStart = ghosts.some(ghost =>
248
+ Math.abs(ghost.x - x * cellSize) < 2 * cellSize &&
249
+ Math.abs(ghost.y - y * cellSize) < 2 * cellSize
250
+ );
251
+
252
+ if (!isNearGhostStart) {
253
+ const pellet = document.createElement('div');
254
+ pellet.className = 'pellet';
255
+ pellet.style.left = `${x * cellSize + cellSize / 2 - 4}px`;
256
+ pellet.style.top = `${y * cellSize + cellSize / 2 - 4}px`;
257
+ pellet.dataset.x = x;
258
+ pellet.dataset.y = y;
259
+ maze.appendChild(pellet);
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ // Add power pellets
266
+ addPowerPellet(1, 1);
267
+ addPowerPellet(cols - 2, 1);
268
+ addPowerPellet(1, rows - 2);
269
+ addPowerPellet(cols - 2, rows - 2);
270
+ }
271
+
272
+ function addPowerPellet(x, y) {
273
+ const pellet = document.createElement('div');
274
+ pellet.className = 'power-pellet';
275
+ pellet.style.left = `${x * cellSize + cellSize / 2 - 8}px`;
276
+ pellet.style.top = `${y * cellSize + cellSize / 2 - 8}px`;
277
+ pellet.dataset.x = x;
278
+ pellet.dataset.y = y;
279
+ pellet.dataset.power = 'true';
280
+ maze.appendChild(pellet);
281
+ }
282
+
283
+ // Initialize game
284
+ function initGame() {
285
+ score = 0;
286
+ lives = 3;
287
+ gameRunning = true;
288
+ direction = 'right';
289
+ nextDirection = 'right';
290
+ scaredGhosts = false;
291
+ pelletsEaten = 0;
292
+
293
+ scoreDisplay.textContent = score;
294
+ livesDisplay.textContent = lives;
295
+ gameOverDisplay.style.display = 'none';
296
+
297
+ // Reset positions
298
+ pacmanPos = {
299
+ x: Math.floor(cols / 2) * cellSize,
300
+ y: Math.floor(rows / 2) * cellSize
301
+ };
302
+
303
+ ghosts = [
304
+ { element: blinky, x: 3 * cellSize, y: 3 * cellSize, color: '#FF0000', speed: ghostSpeed, direction: 'right', scared: false },
305
+ { element: pinky, x: (cols - 4) * cellSize, y: 3 * cellSize, color: '#FFB8FF', speed: ghostSpeed, direction: 'left', scared: false },
306
+ { element: inky, x: 3 * cellSize, y: (rows - 4) * cellSize, color: '#00FFFF', speed: ghostSpeed, direction: 'right', scared: false },
307
+ { element: clyde, x: (cols - 4) * cellSize, y: (rows - 4) * cellSize, color: '#FFB852', speed: ghostSpeed, direction: 'left', scared: false }
308
+ ];
309
+
310
+ createMaze();
311
+ updatePositions();
312
+ gameLoop();
313
+ }
314
+
315
+ // Update positions on screen
316
+ function updatePositions() {
317
+ // Pacman
318
+ pacman.style.left = `${pacmanPos.x}px`;
319
+ pacman.style.top = `${pacmanPos.y}px`;
320
+
321
+ // Rotate Pacman based on direction
322
+ let rotation = 0;
323
+ switch (direction) {
324
+ case 'up': rotation = -90; break;
325
+ case 'down': rotation = 90; break;
326
+ case 'left': rotation = 180; break;
327
+ case 'right': rotation = 0; break;
328
+ }
329
+ pacman.style.transform = `rotate(${rotation}deg)`;
330
+
331
+ // Ghosts
332
+ ghosts.forEach(ghost => {
333
+ ghost.element.style.left = `${ghost.x}px`;
334
+ ghost.element.style.top = `${ghost.y}px`;
335
+
336
+ if (ghost.scared) {
337
+ ghost.element.style.backgroundColor = '#0000FF';
338
+ } else {
339
+ ghost.element.style.backgroundColor = ghost.color;
340
+ }
341
+ });
342
+ }
343
+
344
+ // Check if position is valid (not a wall)
345
+ function isValidPosition(x, y) {
346
+ const col = Math.floor(x / cellSize);
347
+ const row = Math.floor(y / cellSize);
348
+
349
+ // Check boundaries
350
+ if (col < 0 || col >= cols || row < 0 || row >= rows) {
351
+ return false;
352
+ }
353
+
354
+ // Check if it's a wall
355
+ return !(mazeLayout[row] && mazeLayout[row][col] === 1);
356
+ }
357
+
358
+ // Move Pacman
359
+ function movePacman() {
360
+ let newX = pacmanPos.x;
361
+ let newY = pacmanPos.y;
362
+
363
+ // Try next direction first
364
+ if (nextDirection !== direction) {
365
+ let canChange = false;
366
+
367
+ switch (nextDirection) {
368
+ case 'up':
369
+ canChange = isValidPosition(pacmanPos.x, pacmanPos.y - pacmanSpeed) &&
370
+ isValidPosition(pacmanPos.x + cellSize - 1, pacmanPos.y - pacmanSpeed);
371
+ break;
372
+ case 'down':
373
+ canChange = isValidPosition(pacmanPos.x, pacmanPos.y + cellSize + pacmanSpeed - 1) &&
374
+ isValidPosition(pacmanPos.x + cellSize - 1, pacmanPos.y + cellSize + pacmanSpeed - 1);
375
+ break;
376
+ case 'left':
377
+ canChange = isValidPosition(pacmanPos.x - pacmanSpeed, pacmanPos.y) &&
378
+ isValidPosition(pacmanPos.x - pacmanSpeed, pacmanPos.y + cellSize - 1);
379
+ break;
380
+ case 'right':
381
+ canChange = isValidPosition(pacmanPos.x + cellSize + pacmanSpeed - 1, pacmanPos.y) &&
382
+ isValidPosition(pacmanPos.x + cellSize + pacmanSpeed - 1, pacmanPos.y + cellSize - 1);
383
+ break;
384
+ }
385
+
386
+ if (canChange) {
387
+ direction = nextDirection;
388
+ }
389
+ }
390
+
391
+ // Move in current direction
392
+ switch (direction) {
393
+ case 'up':
394
+ newY -= pacmanSpeed;
395
+ if (isValidPosition(pacmanPos.x, newY) &&
396
+ isValidPosition(pacmanPos.x + cellSize - 1, newY)) {
397
+ pacmanPos.y = newY;
398
+ }
399
+ break;
400
+ case 'down':
401
+ newY += pacmanSpeed;
402
+ if (isValidPosition(pacmanPos.x, newY + cellSize - 1) &&
403
+ isValidPosition(pacmanPos.x + cellSize - 1, newY + cellSize - 1)) {
404
+ pacmanPos.y = newY;
405
+ }
406
+ break;
407
+ case 'left':
408
+ newX -= pacmanSpeed;
409
+ if (isValidPosition(newX, pacmanPos.y) &&
410
+ isValidPosition(newX, pacmanPos.y + cellSize - 1)) {
411
+ pacmanPos.x = newX;
412
+ }
413
+ break;
414
+ case 'right':
415
+ newX += pacmanSpeed;
416
+ if (isValidPosition(newX + cellSize - 1, pacmanPos.y) &&
417
+ isValidPosition(newX + cellSize - 1, pacmanPos.y + cellSize - 1)) {
418
+ pacmanPos.x = newX;
419
+ }
420
+ break;
421
+ }
422
+
423
+ // Wrap around (tunnel effect)
424
+ if (pacmanPos.x < -cellSize) {
425
+ pacmanPos.x = mazeWidth;
426
+ } else if (pacmanPos.x > mazeWidth) {
427
+ pacmanPos.x = -cellSize;
428
+ }
429
+
430
+ // Check for pellet collision
431
+ checkPelletCollision();
432
+
433
+ // Check for ghost collision
434
+ checkGhostCollision();
435
+ }
436
+
437
+ // Move ghosts
438
+ function moveGhosts() {
439
+ ghosts.forEach(ghost => {
440
+ // Simple AI: move randomly but prefer current direction
441
+ const directions = ['up', 'down', 'left', 'right'];
442
+ let possibleDirections = [];
443
+
444
+ // Check which directions are valid
445
+ directions.forEach(dir => {
446
+ let newX = ghost.x;
447
+ let newY = ghost.y;
448
+
449
+ switch (dir) {
450
+ case 'up':
451
+ newY -= ghost.speed;
452
+ break;
453
+ case 'down':
454
+ newY += ghost.speed;
455
+ break;
456
+ case 'left':
457
+ newX -= ghost.speed;
458
+ break;
459
+ case 'right':
460
+ newX += ghost.speed;
461
+ break;
462
+ }
463
+
464
+ // Check if new position is valid
465
+ if (isValidPosition(newX, newY) &&
466
+ isValidPosition(newX + cellSize - 1, newY + cellSize - 1)) {
467
+ possibleDirections.push(dir);
468
+ }
469
+ });
470
+
471
+ // If no possible directions, reverse
472
+ if (possibleDirections.length === 0) {
473
+ switch (ghost.direction) {
474
+ case 'up': ghost.direction = 'down'; break;
475
+ case 'down': ghost.direction = 'up'; break;
476
+ case 'left': ghost.direction = 'right'; break;
477
+ case 'right': ghost.direction = 'left'; break;
478
+ }
479
+ return;
480
+ }
481
+
482
+ // If current direction is still possible, keep it
483
+ if (possibleDirections.includes(ghost.direction)) {
484
+ // 70% chance to keep same direction
485
+ if (Math.random() < 0.7) {
486
+ // Keep same direction
487
+ } else {
488
+ // Choose random direction
489
+ ghost.direction = possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
490
+ }
491
+ } else {
492
+ // Choose random direction from possible
493
+ ghost.direction = possibleDirections[Math.floor(Math.random() * possibleDirections.length)];
494
+ }
495
+
496
+ // Move ghost
497
+ switch (ghost.direction) {
498
+ case 'up':
499
+ ghost.y -= ghost.speed;
500
+ break;
501
+ case 'down':
502
+ ghost.y += ghost.speed;
503
+ break;
504
+ case 'left':
505
+ ghost.x -= ghost.speed;
506
+ break;
507
+ case 'right':
508
+ ghost.x += ghost.speed;
509
+ break;
510
+ }
511
+
512
+ // Wrap around (tunnel effect)
513
+ if (ghost.x < -cellSize) {
514
+ ghost.x = mazeWidth;
515
+ } else if (ghost.x > mazeWidth) {
516
+ ghost.x = -cellSize;
517
+ }
518
+ });
519
+ }
520
+
521
+ // Check for pellet collision
522
+ function checkPelletCollision() {
523
+ const pacmanCenterX = pacmanPos.x + cellSize / 2;
524
+ const pacmanCenterY = pacmanPos.y + cellSize / 2;
525
+
526
+ document.querySelectorAll('.pellet, .power-pellet').forEach(pellet => {
527
+ const pelletX = parseInt(pellet.style.left) + parseInt(pellet.offsetWidth) / 2;
528
+ const pelletY = parseInt(pellet.style.top) + parseInt(pellet.offsetHeight) / 2;
529
+
530
+ const distance = Math.sqrt(
531
+ Math.pow(pacmanCenterX - pelletX, 2) +
532
+ Math.pow(pacmanCenterY - pelletY, 2)
533
+ );
534
+
535
+ if (distance < cellSize / 2) {
536
+ // Remove pellet
537
+ pellet.remove();
538
+
539
+ // Update score
540
+ if (pellet.classList.contains('power-pellet')) {
541
+ score += 50;
542
+ scareGhosts();
543
+ } else {
544
+ score += 10;
545
+ }
546
+
547
+ scoreDisplay.textContent = score;
548
+ pelletsEaten++;
549
+
550
+ // Check if all pellets are eaten
551
+ if (pelletsEaten >= totalPellets) {
552
+ gameWin();
553
+ }
554
+ }
555
+ });
556
+ }
557
+
558
+ // Scare ghosts (make them vulnerable)
559
+ function scareGhosts() {
560
+ scaredGhosts = true;
561
+ ghosts.forEach(ghost => {
562
+ ghost.scared = true;
563
+ ghost.speed = ghostSpeed * 0.7; // Slow down when scared
564
+ });
565
+
566
+ // Reset scared timer if already active
567
+ if (scaredTimer) {
568
+ clearTimeout(scaredTimer);
569
+ }
570
+
571
+ // Ghosts return to normal after 10 seconds
572
+ scaredTimer = setTimeout(() => {
573
+ scaredGhosts = false;
574
+ ghosts.forEach(ghost => {
575
+ ghost.scared = false;
576
+ ghost.speed = ghostSpeed;
577
+ });
578
+ }, 10000);
579
+ }
580
+
581
+ // Check for ghost collision
582
+ function checkGhostCollision() {
583
+ const pacmanCenterX = pacmanPos.x + cellSize / 2;
584
+ const pacmanCenterY = pacmanPos.y + cellSize / 2;
585
+
586
+ ghosts.forEach(ghost => {
587
+ const ghostCenterX = ghost.x + cellSize / 2;
588
+ const ghostCenterY = ghost.y + cellSize / 2;
589
+
590
+ const distance = Math.sqrt(
591
+ Math.pow(pacmanCenterX - ghostCenterX, 2) +
592
+ Math.pow(pacmanCenterY - ghostCenterY, 2)
593
+ );
594
+
595
+ if (distance < cellSize) {
596
+ if (ghost.scared) {
597
+ // Eat ghost
598
+ ghost.x = Math.floor(cols / 2) * cellSize;
599
+ ghost.y = Math.floor(rows / 2) * cellSize;
600
+ ghost.scared = false;
601
+ ghost.speed = ghostSpeed;
602
+ score += 200;
603
+ scoreDisplay.textContent = score;
604
+ } else {
605
+ // Lose life
606
+ loseLife();
607
+ }
608
+ }
609
+ });
610
+ }
611
+
612
+ // Lose a life
613
+ function loseLife() {
614
+ lives--;
615
+ livesDisplay.textContent = lives;
616
+
617
+ if (lives <= 0) {
618
+ gameOver();
619
+ } else {
620
+ // Reset positions
621
+ pacmanPos = {
622
+ x: Math.floor(cols / 2) * cellSize,
623
+ y: Math.floor(rows / 2) * cellSize
624
+ };
625
+
626
+ direction = 'right';
627
+ nextDirection = 'right';
628
+
629
+ // Reset ghosts
630
+ ghosts = [
631
+ { element: blinky, x: 3 * cellSize, y: 3 * cellSize, color: '#FF0000', speed: ghostSpeed, direction: 'right', scared: false },
632
+ { element: pinky, x: (cols - 4) * cellSize, y: 3 * cellSize, color: '#FFB8FF', speed: ghostSpeed, direction: 'left', scared: false },
633
+ { element: inky, x: 3 * cellSize, y: (rows - 4) * cellSize, color: '#00FFFF', speed: ghostSpeed, direction: 'right', scared: false },
634
+ { element: clyde, x: (cols - 4) * cellSize, y: (rows - 4) * cellSize, color: '#FFB852', speed: ghostSpeed, direction: 'left', scared: false }
635
+ ];
636
+
637
+ updatePositions();
638
+ }
639
+ }
640
+
641
+ // Game over
642
+ function gameOver() {
643
+ gameRunning = false;
644
+ finalScoreDisplay.textContent = score;
645
+ gameOverDisplay.style.display = 'flex';
646
+ }
647
+
648
+ // Game win
649
+ function gameWin() {
650
+ gameRunning = false;
651
+ finalScoreDisplay.textContent = score;
652
+ gameOverDisplay.querySelector('div').textContent = 'YOU WIN!';
653
+ gameOverDisplay.querySelector('div').className = 'text-4xl font-bold text-green-500 mb-4';
654
+ gameOverDisplay.style.display = 'flex';
655
+ }
656
+
657
+ // Game loop
658
+ function gameLoop() {
659
+ if (!gameRunning) return;
660
+
661
+ movePacman();
662
+ moveGhosts();
663
+ updatePositions();
664
+
665
+ requestAnimationFrame(gameLoop);
666
+ }
667
+
668
+ // Event listeners for controls
669
+ upBtn.addEventListener('click', () => nextDirection = 'up');
670
+ downBtn.addEventListener('click', () => nextDirection = 'down');
671
+ leftBtn.addEventListener('click', () => nextDirection = 'left');
672
+ rightBtn.addEventListener('click', () => nextDirection = 'right');
673
+
674
+ // Keyboard controls
675
+ document.addEventListener('keydown', (e) => {
676
+ switch (e.key) {
677
+ case 'ArrowUp': nextDirection = 'up'; break;
678
+ case 'ArrowDown': nextDirection = 'down'; break;
679
+ case 'ArrowLeft': nextDirection = 'left'; break;
680
+ case 'ArrowRight': nextDirection = 'right'; break;
681
+ }
682
+ });
683
+
684
+ // Touch controls for mobile
685
+ let touchStartX = 0;
686
+ let touchStartY = 0;
687
+
688
+ maze.addEventListener('touchstart', (e) => {
689
+ touchStartX = e.touches[0].clientX;
690
+ touchStartY = e.touches[0].clientY;
691
+ });
692
+
693
+ maze.addEventListener('touchmove', (e) => {
694
+ e.preventDefault();
695
+ const touchEndX = e.touches[0].clientX;
696
+ const touchEndY = e.touches[0].clientY;
697
+
698
+ const diffX = touchEndX - touchStartX;
699
+ const diffY = touchEndY - touchStartY;
700
+
701
+ if (Math.abs(diffX) > Math.abs(diffY)) {
702
+ // Horizontal swipe
703
+ if (diffX > 0) {
704
+ nextDirection = 'right';
705
+ } else {
706
+ nextDirection = 'left';
707
+ }
708
+ } else {
709
+ // Vertical swipe
710
+ if (diffY > 0) {
711
+ nextDirection = 'down';
712
+ } else {
713
+ nextDirection = 'up';
714
+ }
715
+ }
716
+ });
717
+
718
+ // Restart game
719
+ restartBtn.addEventListener('click', initGame);
720
+
721
+ // Start the game
722
+ initGame();
723
+ });
724
+ </script>
725
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=jeromegenevray/jerome" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
726
+ </html>