kimhyunwoo commited on
Commit
37913c3
·
verified ·
1 Parent(s): 13dfc7c

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +97 -90
index.html CHANGED
@@ -195,27 +195,34 @@
195
  let selectedApples = [];
196
  let score = 0;
197
  let isMouseDown = false;
198
- let lastTouchEnd = 0;
199
 
 
200
  function getRelativeCoordinates(event, element) {
201
  const rect = element.getBoundingClientRect();
202
  const clientX = event.clientX || (event.touches && event.touches[0].clientX);
203
  const clientY = event.clientY || (event.touches && event.touches[0].clientY);
204
- if (clientX === undefined || clientY === undefined) { return null; }
 
 
 
205
  return { x: clientX - rect.left, y: clientY - rect.top };
206
  }
207
 
 
208
  function getCellFromCoordinates(coords) {
209
  if (!coords) return null;
210
  const cellSize = gameContainer.offsetWidth / gridSize;
211
  const col = Math.floor(coords.x / cellSize);
212
  const row = Math.floor(coords.y / cellSize);
 
213
  if (row >= 0 && row < gridSize && col >= 0 && col < gridSize) {
214
  return { row, col };
215
  }
216
  return null;
217
  }
218
 
 
219
  function createApple(row, col) {
220
  const apple = document.createElement('div');
221
  apple.classList.add('apple');
@@ -227,6 +234,7 @@
227
  return apple;
228
  }
229
 
 
230
  function populateGrid() {
231
  for (let row = 0; row < gridSize; row++) {
232
  for (let col = 0; col < gridSize; col++) {
@@ -234,7 +242,7 @@
234
  cell.classList.add('grid-cell');
235
  cell.dataset.row = row;
236
  cell.dataset.col = col;
237
- cell.addEventListener('touchstart', preventZoom, { passive: false });
238
  const apple = createApple(row, col);
239
  cell.appendChild(apple);
240
  gameContainer.appendChild(cell);
@@ -242,14 +250,16 @@
242
  }
243
  updateCombinablePairs();
244
  }
245
-
246
- function preventZoom(e) {
247
  if (e.touches && e.touches.length > 1) {
248
  e.preventDefault(); return;
249
  }
250
  if (e.timeStamp - lastTouchEnd < 300) { e.preventDefault(); }
251
  }
252
 
 
 
253
  function handleSelectionStart(event) {
254
  if (event.type === 'touchend') { lastTouchEnd = event.timeStamp; }
255
 
@@ -257,28 +267,34 @@
257
  const cell = getCellFromCoordinates(coords);
258
  if (!cell) return;
259
 
 
260
  const elementAtPoint = document.elementFromPoint(
261
  event.clientX || (event.touches && event.touches[0].clientX),
262
  event.clientY || (event.touches && event.touches[0].clientY)
263
  );
264
- if (!elementAtPoint || !elementAtPoint.classList.contains('apple')) { return; }
 
 
 
 
265
 
266
  isMouseDown = true;
267
  startCell = cell;
268
  isSelecting = true;
269
  deselectAllApples();
270
 
 
271
  const cellSize = gameContainer.offsetWidth / gridSize;
272
  selectionBox.style.left = `${startCell.col * cellSize}px`;
273
  selectionBox.style.top = `${startCell.row * cellSize}px`;
274
  selectionBox.style.width = `${cellSize}px`;
275
  selectionBox.style.height = `${cellSize}px`;
276
  selectionBox.style.display = 'block';
277
-
278
  selectApplesInBox();
279
- event.preventDefault();
280
  }
281
 
 
282
  function handleSelectionMove(event) {
283
  if (!isSelecting || !isMouseDown) return;
284
 
@@ -289,84 +305,58 @@
289
  if (!currentCell) return;
290
 
291
  const cellSize = gameContainer.offsetWidth / gridSize;
 
 
292
  const top = Math.min(startCell.row, currentCell.row);
293
  const left = Math.min(startCell.col, currentCell.col);
294
  const bottom = Math.max(startCell.row, currentCell.row);
295
  const right = Math.max(startCell.col, currentCell.col);
296
 
297
- // 선택 영역 축소
298
- const shrinkFactor = 0.9; // 바깥쪽 축소
299
- const offsetX = cellSize * (1 - shrinkFactor) / 2;
300
- const offsetY = cellSize * (1 - shrinkFactor) / 2;
301
-
302
- selectionBox.style.top = `${top * cellSize + offsetY}px`;
303
- selectionBox.style.left = `${left * cellSize + offsetX}px`;
304
- selectionBox.style.width = `${(right - left + 1) * cellSize * shrinkFactor}px`;
305
- selectionBox.style.height = `${(bottom - top + 1) * cellSize * shrinkFactor}px`;
306
 
307
  selectApplesInBox();
308
  event.preventDefault();
309
  }
310
 
 
311
  function handleSelectionEnd(event) {
312
  if (event.type === 'touchend') { lastTouchEnd = event.timeStamp; }
313
  if (!isSelecting) return;
314
 
315
  isMouseDown = false;
316
  isSelecting = false;
317
- selectionBox.style.display = 'none';
318
- checkSum();
319
- startCell = null;
320
  event.preventDefault();
321
  }
322
- function selectApplesInBox() {
323
- const boxRect = selectionBox.getBoundingClientRect();
324
- const containerRect = gameContainer.getBoundingClientRect();
325
- const apples = document.querySelectorAll('.apple');
326
 
327
- // 선택 상자의 "안쪽" 경계 계산 (margin 적용) - 중심점 검사용
328
- const selectionMargin = boxRect.width * 0.2; // margin은 유지
329
- const innerBoxLeft = boxRect.left - containerRect.left + selectionMargin;
330
- const innerBoxTop = boxRect.top - containerRect.top + selectionMargin;
331
- const innerBoxRight = boxRect.right - containerRect.left - selectionMargin;
332
- const innerBoxBottom = boxRect.bottom - containerRect.top - selectionMargin;
333
 
334
  apples.forEach(apple => {
335
  const appleRect = apple.getBoundingClientRect();
336
 
337
- // 사과 중심 좌표 계산
338
- const appleCenterX = appleRect.left + appleRect.width / 2 - containerRect.left;
339
- const appleCenterY = appleRect.top + appleRect.height / 2 - containerRect.top;
340
-
341
- // 1. 중심점 기반 검사 (엄격)
342
- const isInside = appleCenterX >= innerBoxLeft && appleCenterX <= innerBoxRight &&
343
- appleCenterY >= innerBoxTop && appleCenterY <= innerBoxBottom;
344
-
345
- // 2. 경계 겹침 검사 (완화) - containerRect 기준 상대 좌표 사용
346
- const adjustedBoxRect = {
347
- left: boxRect.left - containerRect.left,
348
- top: boxRect.top - containerRect.top,
349
- right: boxRect.right - containerRect.left,
350
- bottom: boxRect.bottom - containerRect.top
351
- };
352
- const adjustedAppleRect = {
353
- left: appleRect.left - containerRect.left,
354
- top: appleRect.top - containerRect.top,
355
- right: appleRect.right - containerRect.left,
356
- bottom: appleRect.bottom - containerRect.top
357
- };
358
-
359
- const isOverlapping = !(adjustedBoxRect.right < adjustedAppleRect.left ||
360
- adjustedBoxRect.left > adjustedAppleRect.right ||
361
- adjustedBoxRect.bottom < adjustedAppleRect.top ||
362
- adjustedBoxRect.top > adjustedAppleRect.bottom);
363
-
364
-
365
- // 두 조건 중 하나라도 만족하면 선택
366
- if (isInside || isOverlapping) {
367
  if (!selectedApples.includes(apple)) {
368
- apple.classList.add('selected');
369
- selectedApples.push(apple);
370
  }
371
  } else {
372
  apple.classList.remove('selected');
@@ -374,41 +364,49 @@
374
  }
375
  });
376
  }
 
 
 
377
  function deselectAllApples() {
378
  selectedApples.forEach(apple => apple.classList.remove('selected'));
379
  selectedApples = [];
380
  }
381
 
382
- function checkSum() {
383
- let sum = 0;
384
- selectedApples.forEach(apple => sum += parseInt(apple.dataset.value));
385
-
386
- if (sum === 10) {
387
- score += selectedApples.length;
388
- scoreDisplay.textContent = `Score: ${score}`;
389
-
390
- selectedApples.forEach(apple => {
391
- apple.classList.add('removing');
392
- apple.style.setProperty('--random-x', Math.random() * 2 - 1);
393
- apple.style.setProperty('--random-y', Math.random() * 2 - 1);
394
- apple.style.setProperty('--random-rotate', Math.random() * 2 - 1);
395
- apple.style.setProperty('--random-scale', Math.random() * 1 + 0.5);
396
-
397
- apple.addEventListener('animationend', () => {
398
- const parentCell = apple.parentElement;
399
- if (parentCell && parentCell.classList.contains('grid-cell')) {
400
- parentCell.removeChild(apple);
401
- updateCombinablePairs();
402
- }
 
 
 
 
403
  });
404
- });
405
 
406
- selectedApples = [];
407
- } else {
408
- deselectAllApples();
 
409
  }
410
- }
411
 
 
 
412
  function hasCombinablePairs() {
413
  const apples = document.querySelectorAll('.apple');
414
  const values = Array.from(apples).map(apple => parseInt(apple.dataset.value));
@@ -416,13 +414,14 @@
416
  for (let i = 0; i < values.length; i++) {
417
  for (let j = i + 1; j < values.length; j++) {
418
  if (values[i] + values[j] === 10) {
419
- return true;
420
  }
421
  }
422
  }
423
- return false;
424
  }
425
 
 
426
  function updateCombinablePairs() {
427
  const apples = document.querySelectorAll('.apple');
428
  const values = Array.from(apples).map(apple => parseInt(apple.dataset.value));
@@ -438,18 +437,23 @@
438
 
439
  combinablePairsDisplay.textContent = `Pairs: ${count}`;
440
 
 
441
  if (count === 0 && apples.length > 0) {
442
  gameOverScreen.style.display = "flex";
443
  }
444
  }
445
 
 
 
446
  function startGame() {
447
  populateGrid();
448
  }
449
 
 
450
  function restartGame() {
451
  score = 0;
452
  scoreDisplay.textContent = "Score: 0";
 
453
  while (gameContainer.firstChild) {
454
  gameContainer.removeChild(gameContainer.firstChild);
455
  }
@@ -457,6 +461,7 @@
457
  startGame();
458
  }
459
 
 
460
  gameContainer.addEventListener('mousedown', handleSelectionStart);
461
  gameContainer.addEventListener('mousemove', handleSelectionMove);
462
  gameContainer.addEventListener('mouseup', handleSelectionEnd);
@@ -464,6 +469,8 @@
464
  gameContainer.addEventListener('touchmove', handleSelectionMove);
465
  gameContainer.addEventListener('touchend', handleSelectionEnd);
466
 
 
 
467
  startGame();
468
  </script>
469
  </body>
 
195
  let selectedApples = [];
196
  let score = 0;
197
  let isMouseDown = false;
198
+ let lastTouchEnd = 0;
199
 
200
+ // Helper function to get relative coordinates, handling both mouse and touch events.
201
  function getRelativeCoordinates(event, element) {
202
  const rect = element.getBoundingClientRect();
203
  const clientX = event.clientX || (event.touches && event.touches[0].clientX);
204
  const clientY = event.clientY || (event.touches && event.touches[0].clientY);
205
+
206
+ if (clientX === undefined || clientY === undefined) {
207
+ return null;
208
+ }
209
  return { x: clientX - rect.left, y: clientY - rect.top };
210
  }
211
 
212
+ // Helper function to get the row and column of a cell from coordinates.
213
  function getCellFromCoordinates(coords) {
214
  if (!coords) return null;
215
  const cellSize = gameContainer.offsetWidth / gridSize;
216
  const col = Math.floor(coords.x / cellSize);
217
  const row = Math.floor(coords.y / cellSize);
218
+
219
  if (row >= 0 && row < gridSize && col >= 0 && col < gridSize) {
220
  return { row, col };
221
  }
222
  return null;
223
  }
224
 
225
+ // Creates an apple with a random number (1-9).
226
  function createApple(row, col) {
227
  const apple = document.createElement('div');
228
  apple.classList.add('apple');
 
234
  return apple;
235
  }
236
 
237
+ // Populates the grid with apples.
238
  function populateGrid() {
239
  for (let row = 0; row < gridSize; row++) {
240
  for (let col = 0; col < gridSize; col++) {
 
242
  cell.classList.add('grid-cell');
243
  cell.dataset.row = row;
244
  cell.dataset.col = col;
245
+ cell.addEventListener('touchstart', preventZoom, { passive: false }); // Prevent zoom on double-tap
246
  const apple = createApple(row, col);
247
  cell.appendChild(apple);
248
  gameContainer.appendChild(cell);
 
250
  }
251
  updateCombinablePairs();
252
  }
253
+ // Prevent page zoom on touch devices
254
+ function preventZoom(e) {
255
  if (e.touches && e.touches.length > 1) {
256
  e.preventDefault(); return;
257
  }
258
  if (e.timeStamp - lastTouchEnd < 300) { e.preventDefault(); }
259
  }
260
 
261
+
262
+ // Handles the start of a selection (mousedown or touchstart).
263
  function handleSelectionStart(event) {
264
  if (event.type === 'touchend') { lastTouchEnd = event.timeStamp; }
265
 
 
267
  const cell = getCellFromCoordinates(coords);
268
  if (!cell) return;
269
 
270
+ // Ensure we're starting on an apple.
271
  const elementAtPoint = document.elementFromPoint(
272
  event.clientX || (event.touches && event.touches[0].clientX),
273
  event.clientY || (event.touches && event.touches[0].clientY)
274
  );
275
+
276
+ if (!elementAtPoint || !elementAtPoint.classList.contains('apple')) {
277
+ return;
278
+ }
279
+
280
 
281
  isMouseDown = true;
282
  startCell = cell;
283
  isSelecting = true;
284
  deselectAllApples();
285
 
286
+ // Set initial size and position of the selection box.
287
  const cellSize = gameContainer.offsetWidth / gridSize;
288
  selectionBox.style.left = `${startCell.col * cellSize}px`;
289
  selectionBox.style.top = `${startCell.row * cellSize}px`;
290
  selectionBox.style.width = `${cellSize}px`;
291
  selectionBox.style.height = `${cellSize}px`;
292
  selectionBox.style.display = 'block';
 
293
  selectApplesInBox();
294
+ event.preventDefault(); // Prevent other events like scrolling.
295
  }
296
 
297
+ // Handles mouse/touch movement during selection.
298
  function handleSelectionMove(event) {
299
  if (!isSelecting || !isMouseDown) return;
300
 
 
305
  if (!currentCell) return;
306
 
307
  const cellSize = gameContainer.offsetWidth / gridSize;
308
+
309
+ // Calculate top-left and bottom-right corners of the selection box.
310
  const top = Math.min(startCell.row, currentCell.row);
311
  const left = Math.min(startCell.col, currentCell.col);
312
  const bottom = Math.max(startCell.row, currentCell.row);
313
  const right = Math.max(startCell.col, currentCell.col);
314
 
315
+ // Update selection box size and position.
316
+ selectionBox.style.top = `${top * cellSize}px`;
317
+ selectionBox.style.left = `${left * cellSize}px`;
318
+ selectionBox.style.width = `${(right - left + 1) * cellSize}px`;
319
+ selectionBox.style.height = `${(bottom - top + 1) * cellSize}px`;
 
 
 
 
320
 
321
  selectApplesInBox();
322
  event.preventDefault();
323
  }
324
 
325
+ // Handles the end of a selection (mouseup or touchend).
326
  function handleSelectionEnd(event) {
327
  if (event.type === 'touchend') { lastTouchEnd = event.timeStamp; }
328
  if (!isSelecting) return;
329
 
330
  isMouseDown = false;
331
  isSelecting = false;
332
+ selectionBox.style.display = 'none'; // Hide selection box.
333
+ checkSum(); // Check the sum of selected apples.
334
+ startCell = null; // Reset startCell.
335
  event.preventDefault();
336
  }
 
 
 
 
337
 
338
+
339
+ function selectApplesInBox() {
340
+ const apples = document.querySelectorAll('.apple');
341
+ const selectionRect = selectionBox.getBoundingClientRect(); // Selection box rect
 
 
342
 
343
  apples.forEach(apple => {
344
  const appleRect = apple.getBoundingClientRect();
345
 
346
+ // Calculate the center of the apple.
347
+ const appleCenterX = appleRect.left + appleRect.width / 2;
348
+ const appleCenterY = appleRect.top + appleRect.height / 2;
349
+
350
+ // Check if the apple's center is within the selection box.
351
+ const isInside = appleCenterX >= selectionRect.left &&
352
+ appleCenterX <= selectionRect.right &&
353
+ appleCenterY >= selectionRect.top &&
354
+ appleCenterY <= selectionRect.bottom;
355
+
356
+ if (isInside) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  if (!selectedApples.includes(apple)) {
358
+ apple.classList.add('selected');
359
+ selectedApples.push(apple);
360
  }
361
  } else {
362
  apple.classList.remove('selected');
 
364
  }
365
  });
366
  }
367
+
368
+
369
+ // Deselects all apples.
370
  function deselectAllApples() {
371
  selectedApples.forEach(apple => apple.classList.remove('selected'));
372
  selectedApples = [];
373
  }
374
 
375
+ // Checks if the sum of selected apples is 10. If so, removes them and updates the score.
376
+ function checkSum() {
377
+ let sum = 0;
378
+ selectedApples.forEach(apple => sum += parseInt(apple.dataset.value));
379
+
380
+ if (sum === 10) {
381
+ score += selectedApples.length;
382
+ scoreDisplay.textContent = `Score: ${score}`;
383
+
384
+ selectedApples.forEach(apple => {
385
+ apple.classList.add('removing');
386
+ // Add random animation properties
387
+ apple.style.setProperty('--random-x', Math.random() * 2 - 1); // -1 to 1
388
+ apple.style.setProperty('--random-y', Math.random() * 2 - 1);
389
+ apple.style.setProperty('--random-rotate', Math.random() * 2 - 1);
390
+ apple.style.setProperty('--random-scale', Math.random() * 1 + 0.5); // 0.5 to 1.5
391
+
392
+ // Remove the apple after the animation finishes.
393
+ apple.addEventListener('animationend', () => {
394
+ const parentCell = apple.parentElement;
395
+ if (parentCell && parentCell.classList.contains('grid-cell')) {
396
+ parentCell.removeChild(apple);
397
+ updateCombinablePairs(); // Check for game over after removing apples.
398
+ }
399
+ });
400
  });
 
401
 
402
+ selectedApples = []; // Clear the selection.
403
+ } else {
404
+ deselectAllApples(); // Deselect if the sum is not 10.
405
+ }
406
  }
 
407
 
408
+
409
+ // Checks if there are any combinable pairs left on the board.
410
  function hasCombinablePairs() {
411
  const apples = document.querySelectorAll('.apple');
412
  const values = Array.from(apples).map(apple => parseInt(apple.dataset.value));
 
414
  for (let i = 0; i < values.length; i++) {
415
  for (let j = i + 1; j < values.length; j++) {
416
  if (values[i] + values[j] === 10) {
417
+ return true; // Found a pair that sums to 10.
418
  }
419
  }
420
  }
421
+ return false; // No pairs found.
422
  }
423
 
424
+ // Updates the display of combinable pairs and checks for game over.
425
  function updateCombinablePairs() {
426
  const apples = document.querySelectorAll('.apple');
427
  const values = Array.from(apples).map(apple => parseInt(apple.dataset.value));
 
437
 
438
  combinablePairsDisplay.textContent = `Pairs: ${count}`;
439
 
440
+ // Check for game over (no apples left or no combinable pairs).
441
  if (count === 0 && apples.length > 0) {
442
  gameOverScreen.style.display = "flex";
443
  }
444
  }
445
 
446
+
447
+ // Starts a new game.
448
  function startGame() {
449
  populateGrid();
450
  }
451
 
452
+ // Restarts the game.
453
  function restartGame() {
454
  score = 0;
455
  scoreDisplay.textContent = "Score: 0";
456
+ // Clear existing apples.
457
  while (gameContainer.firstChild) {
458
  gameContainer.removeChild(gameContainer.firstChild);
459
  }
 
461
  startGame();
462
  }
463
 
464
+ // Event listeners for mouse and touch events.
465
  gameContainer.addEventListener('mousedown', handleSelectionStart);
466
  gameContainer.addEventListener('mousemove', handleSelectionMove);
467
  gameContainer.addEventListener('mouseup', handleSelectionEnd);
 
469
  gameContainer.addEventListener('touchmove', handleSelectionMove);
470
  gameContainer.addEventListener('touchend', handleSelectionEnd);
471
 
472
+
473
+ // Start the game when the page loads.
474
  startGame();
475
  </script>
476
  </body>