create-template-html-css 1.8.1 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +7 -1
- package/demo-games/guess-number/index.html +71 -0
- package/demo-games/guess-number/script.js +216 -0
- package/demo-games/guess-number/style.css +337 -0
- package/demo-games/memory-game/index.html +50 -0
- package/demo-games/memory-game/script.js +216 -0
- package/demo-games/memory-game/style.css +288 -0
- package/demo-games/snake-game/index.html +61 -0
- package/demo-games/snake-game/script.js +360 -0
- package/demo-games/snake-game/style.css +246 -0
- package/demo-games/tic-tac-toe/index.html +57 -0
- package/demo-games/tic-tac-toe/script.js +156 -0
- package/demo-games/tic-tac-toe/style.css +244 -0
- package/package.json +1 -1
- package/templates/guess-number/index.html +71 -0
- package/templates/guess-number/script.js +216 -0
- package/templates/guess-number/style.css +337 -0
- package/templates/memory-game/index.html +50 -0
- package/templates/memory-game/script.js +216 -0
- package/templates/memory-game/style.css +288 -0
- package/templates/snake-game/index.html +61 -0
- package/templates/snake-game/script.js +360 -0
- package/templates/snake-game/style.css +246 -0
- package/templates/tic-tac-toe/index.html +57 -0
- package/templates/tic-tac-toe/script.js +156 -0
- package/templates/tic-tac-toe/style.css +244 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
// Snake Game Logic
|
|
2
|
+
|
|
3
|
+
const canvas = document.getElementById('gameCanvas');
|
|
4
|
+
const ctx = canvas.getContext('2d');
|
|
5
|
+
const scoreDisplay = document.getElementById('score');
|
|
6
|
+
const highScoreDisplay = document.getElementById('highScore');
|
|
7
|
+
const speedDisplay = document.getElementById('speed');
|
|
8
|
+
const messageDisplay = document.getElementById('message');
|
|
9
|
+
const startBtn = document.getElementById('startBtn');
|
|
10
|
+
const pauseBtn = document.getElementById('pauseBtn');
|
|
11
|
+
const resetBtn = document.getElementById('resetBtn');
|
|
12
|
+
const upBtn = document.getElementById('upBtn');
|
|
13
|
+
const downBtn = document.getElementById('downBtn');
|
|
14
|
+
const leftBtn = document.getElementById('leftBtn');
|
|
15
|
+
const rightBtn = document.getElementById('rightBtn');
|
|
16
|
+
|
|
17
|
+
// Game constants
|
|
18
|
+
const GRID_SIZE = 20;
|
|
19
|
+
const CELL_SIZE = canvas.width / GRID_SIZE;
|
|
20
|
+
|
|
21
|
+
// Game state
|
|
22
|
+
let snake = [];
|
|
23
|
+
let food = {};
|
|
24
|
+
let direction = 'right';
|
|
25
|
+
let nextDirection = 'right';
|
|
26
|
+
let score = 0;
|
|
27
|
+
let highScore = localStorage.getItem('snakeHighScore') || 0;
|
|
28
|
+
let gameLoop = null;
|
|
29
|
+
let gameSpeed = 150;
|
|
30
|
+
let isPaused = false;
|
|
31
|
+
let isGameOver = false;
|
|
32
|
+
|
|
33
|
+
// Initialize game
|
|
34
|
+
function initGame() {
|
|
35
|
+
snake = [
|
|
36
|
+
{ x: 10, y: 10 },
|
|
37
|
+
{ x: 9, y: 10 },
|
|
38
|
+
{ x: 8, y: 10 }
|
|
39
|
+
];
|
|
40
|
+
direction = 'right';
|
|
41
|
+
nextDirection = 'right';
|
|
42
|
+
score = 0;
|
|
43
|
+
gameSpeed = 150;
|
|
44
|
+
isPaused = false;
|
|
45
|
+
isGameOver = false;
|
|
46
|
+
|
|
47
|
+
updateScore();
|
|
48
|
+
updateSpeed();
|
|
49
|
+
spawnFood();
|
|
50
|
+
draw();
|
|
51
|
+
|
|
52
|
+
messageDisplay.textContent = 'Press SPACE or tap Start to begin';
|
|
53
|
+
messageDisplay.className = 'message';
|
|
54
|
+
startBtn.disabled = false;
|
|
55
|
+
pauseBtn.disabled = true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Start game
|
|
59
|
+
function startGame() {
|
|
60
|
+
if (gameLoop || isPaused) return;
|
|
61
|
+
|
|
62
|
+
messageDisplay.textContent = '';
|
|
63
|
+
startBtn.disabled = true;
|
|
64
|
+
pauseBtn.disabled = false;
|
|
65
|
+
|
|
66
|
+
gameLoop = setInterval(() => {
|
|
67
|
+
update();
|
|
68
|
+
draw();
|
|
69
|
+
}, gameSpeed);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Pause game
|
|
73
|
+
function pauseGame() {
|
|
74
|
+
if (isGameOver) return;
|
|
75
|
+
|
|
76
|
+
isPaused = !isPaused;
|
|
77
|
+
|
|
78
|
+
if (isPaused) {
|
|
79
|
+
clearInterval(gameLoop);
|
|
80
|
+
gameLoop = null;
|
|
81
|
+
messageDisplay.textContent = 'PAUSED - Press SPACE or Resume';
|
|
82
|
+
messageDisplay.className = 'message show';
|
|
83
|
+
pauseBtn.textContent = 'Resume';
|
|
84
|
+
startBtn.disabled = false;
|
|
85
|
+
} else {
|
|
86
|
+
startGame();
|
|
87
|
+
messageDisplay.textContent = '';
|
|
88
|
+
pauseBtn.textContent = 'Pause';
|
|
89
|
+
startBtn.disabled = true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Reset game
|
|
94
|
+
function resetGame() {
|
|
95
|
+
clearInterval(gameLoop);
|
|
96
|
+
gameLoop = null;
|
|
97
|
+
initGame();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Update game state
|
|
101
|
+
function update() {
|
|
102
|
+
direction = nextDirection;
|
|
103
|
+
|
|
104
|
+
// Calculate new head position
|
|
105
|
+
const head = { ...snake[0] };
|
|
106
|
+
|
|
107
|
+
switch (direction) {
|
|
108
|
+
case 'up':
|
|
109
|
+
head.y--;
|
|
110
|
+
break;
|
|
111
|
+
case 'down':
|
|
112
|
+
head.y++;
|
|
113
|
+
break;
|
|
114
|
+
case 'left':
|
|
115
|
+
head.x--;
|
|
116
|
+
break;
|
|
117
|
+
case 'right':
|
|
118
|
+
head.x++;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Check collision with walls
|
|
123
|
+
if (head.x < 0 || head.x >= GRID_SIZE || head.y < 0 || head.y >= GRID_SIZE) {
|
|
124
|
+
gameOver();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Check collision with self
|
|
129
|
+
if (snake.some(segment => segment.x === head.x && segment.y === head.y)) {
|
|
130
|
+
gameOver();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Add new head
|
|
135
|
+
snake.unshift(head);
|
|
136
|
+
|
|
137
|
+
// Check if food eaten
|
|
138
|
+
if (head.x === food.x && head.y === food.y) {
|
|
139
|
+
score += 10;
|
|
140
|
+
updateScore();
|
|
141
|
+
spawnFood();
|
|
142
|
+
increaseSpeed();
|
|
143
|
+
} else {
|
|
144
|
+
snake.pop();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Draw everything
|
|
149
|
+
function draw() {
|
|
150
|
+
// Clear canvas
|
|
151
|
+
ctx.fillStyle = '#1f2937';
|
|
152
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
153
|
+
|
|
154
|
+
// Draw grid
|
|
155
|
+
ctx.strokeStyle = '#374151';
|
|
156
|
+
ctx.lineWidth = 1;
|
|
157
|
+
for (let i = 0; i <= GRID_SIZE; i++) {
|
|
158
|
+
ctx.beginPath();
|
|
159
|
+
ctx.moveTo(i * CELL_SIZE, 0);
|
|
160
|
+
ctx.lineTo(i * CELL_SIZE, canvas.height);
|
|
161
|
+
ctx.stroke();
|
|
162
|
+
|
|
163
|
+
ctx.beginPath();
|
|
164
|
+
ctx.moveTo(0, i * CELL_SIZE);
|
|
165
|
+
ctx.lineTo(canvas.width, i * CELL_SIZE);
|
|
166
|
+
ctx.stroke();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Draw snake
|
|
170
|
+
snake.forEach((segment, index) => {
|
|
171
|
+
if (index === 0) {
|
|
172
|
+
// Head
|
|
173
|
+
ctx.fillStyle = '#10b981';
|
|
174
|
+
} else {
|
|
175
|
+
// Body
|
|
176
|
+
ctx.fillStyle = '#34d399';
|
|
177
|
+
}
|
|
178
|
+
ctx.fillRect(
|
|
179
|
+
segment.x * CELL_SIZE + 1,
|
|
180
|
+
segment.y * CELL_SIZE + 1,
|
|
181
|
+
CELL_SIZE - 2,
|
|
182
|
+
CELL_SIZE - 2
|
|
183
|
+
);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Draw food
|
|
187
|
+
ctx.fillStyle = '#ef4444';
|
|
188
|
+
ctx.beginPath();
|
|
189
|
+
ctx.arc(
|
|
190
|
+
food.x * CELL_SIZE + CELL_SIZE / 2,
|
|
191
|
+
food.y * CELL_SIZE + CELL_SIZE / 2,
|
|
192
|
+
CELL_SIZE / 2 - 2,
|
|
193
|
+
0,
|
|
194
|
+
Math.PI * 2
|
|
195
|
+
);
|
|
196
|
+
ctx.fill();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Spawn food
|
|
200
|
+
function spawnFood() {
|
|
201
|
+
do {
|
|
202
|
+
food = {
|
|
203
|
+
x: Math.floor(Math.random() * GRID_SIZE),
|
|
204
|
+
y: Math.floor(Math.random() * GRID_SIZE)
|
|
205
|
+
};
|
|
206
|
+
} while (snake.some(segment => segment.x === food.x && segment.y === food.y));
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Change direction
|
|
210
|
+
function changeDirection(newDirection) {
|
|
211
|
+
// Prevent 180 degree turns
|
|
212
|
+
if (
|
|
213
|
+
(newDirection === 'up' && direction !== 'down') ||
|
|
214
|
+
(newDirection === 'down' && direction !== 'up') ||
|
|
215
|
+
(newDirection === 'left' && direction !== 'right') ||
|
|
216
|
+
(newDirection === 'right' && direction !== 'left')
|
|
217
|
+
) {
|
|
218
|
+
nextDirection = newDirection;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Increase speed
|
|
223
|
+
function increaseSpeed() {
|
|
224
|
+
if (gameSpeed > 50) {
|
|
225
|
+
gameSpeed -= 5;
|
|
226
|
+
clearInterval(gameLoop);
|
|
227
|
+
if (!isPaused) {
|
|
228
|
+
gameLoop = setInterval(() => {
|
|
229
|
+
update();
|
|
230
|
+
draw();
|
|
231
|
+
}, gameSpeed);
|
|
232
|
+
}
|
|
233
|
+
updateSpeed();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Update score
|
|
238
|
+
function updateScore() {
|
|
239
|
+
scoreDisplay.textContent = score;
|
|
240
|
+
|
|
241
|
+
if (score > highScore) {
|
|
242
|
+
highScore = score;
|
|
243
|
+
localStorage.setItem('snakeHighScore', highScore);
|
|
244
|
+
highScoreDisplay.textContent = highScore;
|
|
245
|
+
} else {
|
|
246
|
+
highScoreDisplay.textContent = highScore;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Update speed display
|
|
251
|
+
function updateSpeed() {
|
|
252
|
+
if (gameSpeed > 100) {
|
|
253
|
+
speedDisplay.textContent = 'Normal';
|
|
254
|
+
} else if (gameSpeed > 60) {
|
|
255
|
+
speedDisplay.textContent = 'Fast';
|
|
256
|
+
} else {
|
|
257
|
+
speedDisplay.textContent = 'Very Fast';
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Game over
|
|
262
|
+
function gameOver() {
|
|
263
|
+
clearInterval(gameLoop);
|
|
264
|
+
gameLoop = null;
|
|
265
|
+
isGameOver = true;
|
|
266
|
+
|
|
267
|
+
messageDisplay.textContent = `Game Over! Final Score: ${score}`;
|
|
268
|
+
messageDisplay.className = 'message show game-over';
|
|
269
|
+
|
|
270
|
+
startBtn.disabled = false;
|
|
271
|
+
pauseBtn.disabled = true;
|
|
272
|
+
pauseBtn.textContent = 'Pause';
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Keyboard controls
|
|
276
|
+
document.addEventListener('keydown', (e) => {
|
|
277
|
+
switch (e.key) {
|
|
278
|
+
case 'ArrowUp':
|
|
279
|
+
case 'w':
|
|
280
|
+
case 'W':
|
|
281
|
+
e.preventDefault();
|
|
282
|
+
changeDirection('up');
|
|
283
|
+
break;
|
|
284
|
+
case 'ArrowDown':
|
|
285
|
+
case 's':
|
|
286
|
+
case 'S':
|
|
287
|
+
e.preventDefault();
|
|
288
|
+
changeDirection('down');
|
|
289
|
+
break;
|
|
290
|
+
case 'ArrowLeft':
|
|
291
|
+
case 'a':
|
|
292
|
+
case 'A':
|
|
293
|
+
e.preventDefault();
|
|
294
|
+
changeDirection('left');
|
|
295
|
+
break;
|
|
296
|
+
case 'ArrowRight':
|
|
297
|
+
case 'd':
|
|
298
|
+
case 'D':
|
|
299
|
+
e.preventDefault();
|
|
300
|
+
changeDirection('right');
|
|
301
|
+
break;
|
|
302
|
+
case ' ':
|
|
303
|
+
e.preventDefault();
|
|
304
|
+
if (!gameLoop && !isPaused) {
|
|
305
|
+
startGame();
|
|
306
|
+
} else if (!isGameOver) {
|
|
307
|
+
pauseGame();
|
|
308
|
+
}
|
|
309
|
+
break;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Button controls
|
|
314
|
+
upBtn.addEventListener('click', () => changeDirection('up'));
|
|
315
|
+
downBtn.addEventListener('click', () => changeDirection('down'));
|
|
316
|
+
leftBtn.addEventListener('click', () => changeDirection('left'));
|
|
317
|
+
rightBtn.addEventListener('click', () => changeDirection('right'));
|
|
318
|
+
|
|
319
|
+
startBtn.addEventListener('click', () => {
|
|
320
|
+
if (isGameOver) {
|
|
321
|
+
resetGame();
|
|
322
|
+
}
|
|
323
|
+
startGame();
|
|
324
|
+
});
|
|
325
|
+
pauseBtn.addEventListener('click', pauseGame);
|
|
326
|
+
resetBtn.addEventListener('click', resetGame);
|
|
327
|
+
|
|
328
|
+
// Touch swipe controls
|
|
329
|
+
let touchStartX = 0;
|
|
330
|
+
let touchStartY = 0;
|
|
331
|
+
|
|
332
|
+
canvas.addEventListener('touchstart', (e) => {
|
|
333
|
+
touchStartX = e.touches[0].clientX;
|
|
334
|
+
touchStartY = e.touches[0].clientY;
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
canvas.addEventListener('touchend', (e) => {
|
|
338
|
+
const touchEndX = e.changedTouches[0].clientX;
|
|
339
|
+
const touchEndY = e.changedTouches[0].clientY;
|
|
340
|
+
|
|
341
|
+
const deltaX = touchEndX - touchStartX;
|
|
342
|
+
const deltaY = touchEndY - touchStartY;
|
|
343
|
+
|
|
344
|
+
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
|
345
|
+
if (deltaX > 0) {
|
|
346
|
+
changeDirection('right');
|
|
347
|
+
} else {
|
|
348
|
+
changeDirection('left');
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
if (deltaY > 0) {
|
|
352
|
+
changeDirection('down');
|
|
353
|
+
} else {
|
|
354
|
+
changeDirection('up');
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// Initialize on load
|
|
360
|
+
initGame();
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
body {
|
|
8
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
9
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
10
|
+
min-height: 100vh;
|
|
11
|
+
display: flex;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
align-items: center;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.container {
|
|
18
|
+
width: 100%;
|
|
19
|
+
max-width: 500px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.game-card {
|
|
23
|
+
background: white;
|
|
24
|
+
border-radius: 16px;
|
|
25
|
+
padding: 30px;
|
|
26
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.game-card h1 {
|
|
30
|
+
text-align: center;
|
|
31
|
+
color: #333;
|
|
32
|
+
margin-bottom: 20px;
|
|
33
|
+
font-size: 2.5rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.game-info {
|
|
37
|
+
display: flex;
|
|
38
|
+
justify-content: space-between;
|
|
39
|
+
padding: 15px;
|
|
40
|
+
background: #f3f4f6;
|
|
41
|
+
border-radius: 12px;
|
|
42
|
+
margin-bottom: 20px;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.info-item {
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-direction: column;
|
|
48
|
+
align-items: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.label {
|
|
52
|
+
font-size: 0.9rem;
|
|
53
|
+
color: #6b7280;
|
|
54
|
+
margin-bottom: 5px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.value {
|
|
58
|
+
font-size: 1.3rem;
|
|
59
|
+
font-weight: bold;
|
|
60
|
+
color: #333;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#gameCanvas {
|
|
64
|
+
width: 100%;
|
|
65
|
+
max-width: 400px;
|
|
66
|
+
height: auto;
|
|
67
|
+
display: block;
|
|
68
|
+
margin: 0 auto 20px;
|
|
69
|
+
border-radius: 8px;
|
|
70
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.message {
|
|
74
|
+
text-align: center;
|
|
75
|
+
font-size: 1.1rem;
|
|
76
|
+
font-weight: 600;
|
|
77
|
+
height: 35px;
|
|
78
|
+
display: flex;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
align-items: center;
|
|
81
|
+
margin-bottom: 20px;
|
|
82
|
+
color: #6b7280;
|
|
83
|
+
opacity: 0;
|
|
84
|
+
transition: opacity 0.3s ease;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.message.show {
|
|
88
|
+
opacity: 1;
|
|
89
|
+
animation: pulse 1.5s ease-in-out infinite;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.message.game-over {
|
|
93
|
+
color: #ef4444;
|
|
94
|
+
font-size: 1.2rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@keyframes pulse {
|
|
98
|
+
0%, 100% {
|
|
99
|
+
opacity: 1;
|
|
100
|
+
}
|
|
101
|
+
50% {
|
|
102
|
+
opacity: 0.6;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.controls {
|
|
107
|
+
margin-bottom: 20px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.arrow-buttons {
|
|
111
|
+
display: flex;
|
|
112
|
+
flex-direction: column;
|
|
113
|
+
align-items: center;
|
|
114
|
+
gap: 5px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.arrow-row {
|
|
118
|
+
display: flex;
|
|
119
|
+
gap: 5px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.arrow-btn {
|
|
123
|
+
width: 60px;
|
|
124
|
+
height: 60px;
|
|
125
|
+
border: 2px solid #e5e7eb;
|
|
126
|
+
border-radius: 8px;
|
|
127
|
+
background: white;
|
|
128
|
+
font-size: 1.5rem;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: all 0.2s ease;
|
|
131
|
+
color: #333;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.arrow-btn:hover {
|
|
135
|
+
background: #f3f4f6;
|
|
136
|
+
border-color: #9ca3af;
|
|
137
|
+
transform: scale(1.05);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.arrow-btn:active {
|
|
141
|
+
transform: scale(0.95);
|
|
142
|
+
background: #e5e7eb;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.button-group {
|
|
146
|
+
display: flex;
|
|
147
|
+
gap: 10px;
|
|
148
|
+
margin-bottom: 20px;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.btn {
|
|
152
|
+
flex: 1;
|
|
153
|
+
padding: 12px 20px;
|
|
154
|
+
border: none;
|
|
155
|
+
border-radius: 8px;
|
|
156
|
+
font-size: 1rem;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
cursor: pointer;
|
|
159
|
+
transition: all 0.3s ease;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.btn:disabled {
|
|
163
|
+
opacity: 0.5;
|
|
164
|
+
cursor: not-allowed;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.btn-success {
|
|
168
|
+
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
|
169
|
+
color: white;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.btn-success:hover:not(:disabled) {
|
|
173
|
+
transform: translateY(-2px);
|
|
174
|
+
box-shadow: 0 5px 15px rgba(16, 185, 129, 0.4);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.btn-warning {
|
|
178
|
+
background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
|
|
179
|
+
color: white;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.btn-warning:hover:not(:disabled) {
|
|
183
|
+
transform: translateY(-2px);
|
|
184
|
+
box-shadow: 0 5px 15px rgba(245, 158, 11, 0.4);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.btn-danger {
|
|
188
|
+
background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
|
|
189
|
+
color: white;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.btn-danger:hover:not(:disabled) {
|
|
193
|
+
transform: translateY(-2px);
|
|
194
|
+
box-shadow: 0 5px 15px rgba(239, 68, 68, 0.4);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.instructions {
|
|
198
|
+
background: #f9fafb;
|
|
199
|
+
border-radius: 8px;
|
|
200
|
+
padding: 15px;
|
|
201
|
+
font-size: 0.9rem;
|
|
202
|
+
color: #6b7280;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.instructions p {
|
|
206
|
+
margin-bottom: 8px;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.instructions p:last-child {
|
|
210
|
+
margin-bottom: 0;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
@media (max-width: 480px) {
|
|
214
|
+
.game-card {
|
|
215
|
+
padding: 20px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.game-card h1 {
|
|
219
|
+
font-size: 2rem;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.game-info {
|
|
223
|
+
flex-direction: column;
|
|
224
|
+
gap: 10px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.info-item {
|
|
228
|
+
flex-direction: row;
|
|
229
|
+
justify-content: space-between;
|
|
230
|
+
width: 100%;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.arrow-btn {
|
|
234
|
+
width: 50px;
|
|
235
|
+
height: 50px;
|
|
236
|
+
font-size: 1.2rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.button-group {
|
|
240
|
+
flex-direction: column;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.instructions {
|
|
244
|
+
font-size: 0.85rem;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
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>{{name}} - Tic Tac Toe</title>
|
|
7
|
+
<link rel="stylesheet" href="style.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<div class="game-card">
|
|
12
|
+
<h1>Tic Tac Toe</h1>
|
|
13
|
+
|
|
14
|
+
<div class="game-info">
|
|
15
|
+
<div class="current-player">
|
|
16
|
+
<span>Current Player: </span>
|
|
17
|
+
<span id="currentPlayer" class="player-x">X</span>
|
|
18
|
+
</div>
|
|
19
|
+
<div class="score-board">
|
|
20
|
+
<div class="score-item">
|
|
21
|
+
<span class="player-x">X:</span>
|
|
22
|
+
<span id="scoreX">0</span>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="score-item">
|
|
25
|
+
<span>Draws:</span>
|
|
26
|
+
<span id="scoreDraw">0</span>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="score-item">
|
|
29
|
+
<span class="player-o">O:</span>
|
|
30
|
+
<span id="scoreO">0</span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="board" id="board">
|
|
36
|
+
<div class="cell" data-cell="0"></div>
|
|
37
|
+
<div class="cell" data-cell="1"></div>
|
|
38
|
+
<div class="cell" data-cell="2"></div>
|
|
39
|
+
<div class="cell" data-cell="3"></div>
|
|
40
|
+
<div class="cell" data-cell="4"></div>
|
|
41
|
+
<div class="cell" data-cell="5"></div>
|
|
42
|
+
<div class="cell" data-cell="6"></div>
|
|
43
|
+
<div class="cell" data-cell="7"></div>
|
|
44
|
+
<div class="cell" data-cell="8"></div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<div class="message" id="message"></div>
|
|
48
|
+
|
|
49
|
+
<div class="button-group">
|
|
50
|
+
<button id="resetBtn" class="btn btn-primary">New Game</button>
|
|
51
|
+
<button id="resetScoreBtn" class="btn btn-secondary">Reset Score</button>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<script src="script.js"></script>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|