console
document.addEventListener('DOMContentLoaded', () => {
const gridElement = document.getElementById('game-grid');
const victoryRibbon = document.getElementById('victory-ribbon');
const GRID_SIZE = 10;
const CANDY_TYPES = ['��', '��', '��', '��', '��', '��', '��', '��'];
const MIN_MATCH_LENGTH = 3;
let grid = [];
let isAnimating = false;
function initGame() {
gridElement.innerHTML = '';
grid = [];
isAnimating = false;
victoryRibbon.classList.add('hidden');
victoryRibbon.classList.remove('visible');
for (let r = 0; r < GRID_SIZE; r++) {
grid[r] = [];
for (let c = 0; c < GRID_SIZE; c++) {
createCandyCell(r, c);
}
}
updateGridDOM();
}
function getRandomCandy() {
return CANDY_TYPES[Math.floor(Math.random() * CANDY_TYPES.length)];
}
function createCandyCell(r, c) {
const cell = document.createElement('div');
cell.classList.add('candy');
cell.dataset.row = r;
cell.dataset.col = c;
grid[r][c] = getRandomCandy();
cell.addEventListener('click', handleCandyClick);
gridElement.appendChild(cell);
}
function handleCandyClick(event) {
if (isAnimating) return;
const row = parseInt(event.target.dataset.row);
const col = parseInt(event.target.dataset.col);
const candyType = grid[row][col];
if (!candyType) return;
const connectedCandies = findConnectedCandies(row, col, candyType);
if (connectedCandies.length >= MIN_MATCH_LENGTH) {
isAnimating = true;
eliminateCandies(connectedCandies);
setTimeout(() => {
applyGravity();
refillGrid();
updateGridDOM();
if (checkVictory()) {
triggerVictory();
} else {
isAnimating = false;
}
}, 300);
}
}
function findConnectedCandies(startRow, startCol, candyType) {
const connected = [];
const queue = [{ r: startRow, c: startCol }];
const visited = new Set([`${startRow}-${startCol}`]);
while (queue.length > 0) {
const { r, c } = queue.shift();
connected.push({ r, c });
const neighbors = [
{ r: r - 1, c: c }, { r: r + 1, c: c },
{ r: r, c: c - 1 }, { r: r, c: c + 1 }
];
for (const neighbor of neighbors) {
const { r: nr, c: nc } = neighbor;
const key = `${nr}-${nc}`;
if (nr >= 0 && nr < GRID_SIZE && nc >= 0 && nc < GRID_SIZE &&
!visited.has(key) && grid[nr][nc] === candyType) {
visited.add(key);
queue.push({ r: nr, c: nc });
}
}
}
return connected;
}
function eliminateCandies(candiesToEliminate) {
candiesToEliminate.forEach(({ r, c }) => {
const cellElement = getCellElement(r, c);
if (cellElement) {
cellElement.classList.add('eliminating');
}
grid[r][c] = null;
});
}
function applyGravity() {
for (let c = 0; c < GRID_SIZE; c++) {
let emptyRow = GRID_SIZE - 1;
for (let r = GRID_SIZE - 1; r >= 0; r--) {
if (grid[r][c] !== null) {
if (r !== emptyRow) {
grid[emptyRow][c] = grid[r][c];
grid[r][c] = null;
}
emptyRow--;
}
}
}
}
function refillGrid() {
for (let r = 0; r < GRID_SIZE; r++) {
for (let c = 0; c < GRID_SIZE; c++) {
if (grid[r][c] === null) {
grid[r][c] = getRandomCandy();
}
}
}
}
function updateGridDOM() {
for (let r = 0; r < GRID_SIZE; r++) {
for (let c = 0; c < GRID_SIZE; c++) {
const cellElement = getCellElement(r, c);
if (cellElement) {
const candyType = grid[r][c];
if (candyType) {
cellElement.textContent = candyType;
cellElement.classList.remove('eliminating');
cellElement.style.opacity = 1;
} else {
cellElement.textContent = '';
cellElement.style.opacity = 0;
}
}
}
}
}
function getCellElement(r, c) {
return gridElement.querySelector(`[data-row="${r}"][data-col="${c}"]`);
}
function checkVictory() {
const lastRow = GRID_SIZE - 1;
for (let c = 0; c < GRID_SIZE; c++) {
if (grid[lastRow][c] !== null) {
return false;
}
}
return true;
}
function triggerVictory() {
console.log("Victory!");
isAnimating = true;
victoryRibbon.classList.remove('hidden');
void victoryRibbon.offsetWidth;
victoryRibbon.classList.add('visible');
setTimeout(() => {
victoryRibbon.classList.remove('visible');
setTimeout(() => {
victoryRibbon.classList.add('hidden');
}, 500);
}, 3000);
}
initGame();
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Candy Elimination Fun</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Simple Candy Elimination Fun</h1>
<div id="game-container">
<div id="game-grid">
</div>
<div id="victory-ribbon" class="hidden">
�� Victory! ��
</div>
</div>
<div id="instructions">
Click on 3 or more connected candies of the same type to eliminate them! Clear the bottom row to win!
</div>
<script src="script.js"></script>
</body>
</html>
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #ffdde1, #ee9ca7);
font-family: 'Arial Rounded MT Bold', 'Helvetica Rounded', Arial, sans-serif;
overflow: hidden;
}
h1 {
color: #d13a5a;
text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
margin-bottom: 15px;
}
#game-container {
position: relative;
border: 5px solid #fff;
border-radius: 15px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
background-color: rgba(255, 255, 255, 0.7);
padding: 10px;
}
#game-grid {
display: grid;
grid-template-columns: repeat(10, 40px);
grid-template-rows: repeat(10, 40px);
gap: 3px;
width: 430px;
height: 430px;
}
.candy {
display: flex;
justify-content: center;
align-items: center;
font-size: 28px;
border-radius: 8px;
background-color: rgba(255, 255, 255, 0.5);
cursor: pointer;
transition: transform 0.1s ease-out, background-color 0.2s;
user-select: none;
box-shadow: inset 0 0 5px rgba(0,0,0,0.05);
}
.candy:hover {
transform: scale(1.1);
background-color: rgba(255, 255, 255, 0.8);
}
.eliminating {
transform: scale(0);
transition: transform 0.3s ease-in;
background-color: transparent !important;
}
#instructions {
margin-top: 20px;
color: #555;
font-size: 0.9em;
text-align: center;
}
#victory-ribbon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.8);
background: linear-gradient(45deg, #ffd700, #ffa500);
color: white;
padding: 25px 50px;
border-radius: 10px;
font-size: 2.5em;
font-weight: bold;
text-align: center;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
opacity: 0;
transition: opacity 0.5s ease-in-out, transform 0.5s ease-in-out;
pointer-events: none;
z-index: 10;
}
#victory-ribbon.visible {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
.hidden {
display: none;
}
#victory-ribbon:not(.hidden) {
display: block;
}