File size: 9,697 Bytes
a91cf94 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
document.addEventListener('DOMContentLoaded', () => {
// --- Get Elements ---
const gridContainer = document.getElementById('grid-container');
const targetCoordsDisplay = document.getElementById('target-coords');
const feedbackDisplay = document.getElementById('feedback');
const itemNameDisplay = document.getElementById('item-name');
const yAxisLabelsContainer = document.getElementById('y-axis-labels');
const xAxisLabelsContainer = document.getElementById('x-axis-labels');
const xAxisContainer = document.getElementById('x-axis-container');
const scoreDisplay = document.getElementById('score-display');
// --- Game Settings ---
const gridSize = 8;
const cellSize = 40; // Pixels
// --- Items to Find ---
const itemsToFind = [
{ name: "a sparkling diamond", emoji: "π" }, { name: "a red apple", emoji: "π" },
{ name: "a yummy pizza slice", emoji: "π" }, { name: "a fast rocket", emoji: "π" },
{ name: "a cute puppy", emoji: "πΆ" }, { name: "a bright star", emoji: "β" },
{ name: "a cool robot", emoji: "π€" }, { name: "a friendly ghost", emoji: "π»" },
{ name: "a birthday cake", emoji: "π" }, { name: "a magical unicorn", emoji: "π¦" }
];
const totalItems = itemsToFind.length;
// --- Game State ---
let targetX = -1;
let targetY = -1;
let currentItemIndex = 0;
let foundCurrent = false;
let score = 0;
// --- Initialize Grid and Axes ---
function initializeGameArea() {
gridContainer.innerHTML = '';
xAxisLabelsContainer.innerHTML = '';
yAxisLabelsContainer.innerHTML = '';
score = 0;
currentItemIndex = 0;
updateScoreDisplay();
// CSS variable for reference if needed, though direct style is used now
document.documentElement.style.setProperty('--cell-size', `${cellSize}px`);
const gridTotalSize = gridSize * cellSize;
const yAxisWidth = 20; // Must match CSS .y-axis-label width
const yAxisMargin = 5; // Must match CSS #y-axis-labels margin-right
// --- Configure Grid Container Styles Explicitly ---
gridContainer.style.width = `${gridTotalSize}px`;
gridContainer.style.height = `${gridTotalSize}px`;
gridContainer.style.display = 'grid'; // **Ensure grid layout**
gridContainer.style.gridTemplateColumns = `repeat(${gridSize}, ${cellSize}px)`; // **Ensure columns**
gridContainer.style.gridTemplateRows = `repeat(${gridSize}, ${cellSize}px)`; // **Ensure rows**
// ---
// Configure Axis Containers
yAxisLabelsContainer.style.height = `${gridTotalSize}px`; // Match grid height
xAxisLabelsContainer.style.width = `${gridTotalSize}px`; // Inner label container matches grid width
xAxisContainer.style.width = `${yAxisWidth + yAxisMargin + gridTotalSize}px`; // Outer width includes Y-axis space
xAxisLabelsContainer.style.marginLeft = `${yAxisWidth + yAxisMargin}px`; // Align labels under grid
// Create Y-axis labels (1 to N, bottom-up visually)
for (let y = 1; y <= gridSize; y++) {
const label = document.createElement('div');
label.classList.add('axis-label', 'y-axis-label');
label.textContent = y;
label.style.height = `${cellSize}px`;
yAxisLabelsContainer.appendChild(label);
}
// Create X-axis labels (1 to N, left-to-right)
for (let x = 1; x <= gridSize; x++) {
const label = document.createElement('div');
label.classList.add('axis-label', 'x-axis-label');
label.textContent = x;
label.style.width = `${cellSize}px`;
xAxisLabelsContainer.appendChild(label);
}
// Create grid cells
// Loop Y from gridSize down to 1 so that Y=1 is the bottom row visually
for (let y = gridSize; y >= 1; y--) {
// Loop X from 1 to gridSize as usual (left-to-right)
for (let x = 1; x <= gridSize; x++) {
const cell = document.createElement('div');
cell.classList.add('grid-cell');
cell.dataset.x = x; // Store correct X coordinate
cell.dataset.y = y; // Store correct Y coordinate
cell.style.width = `${cellSize}px`; // Explicit size
cell.style.height = `${cellSize}px`; // Explicit size
cell.addEventListener('click', handleCellClick);
gridContainer.appendChild(cell);
}
}
console.log("Grid, Axes, and Score Initialized.");
}
// --- Update Score Display ---
function updateScoreDisplay() {
scoreDisplay.textContent = `Score: ${score} / ${totalItems}`;
}
// --- Set a New Target Item and Location ---
function setNewTarget() {
foundCurrent = false;
// --- Game Over Check ---
if (currentItemIndex >= totalItems) {
let finalMessage = `All done! Your final score: ${score} / ${totalItems}! π`;
if (score === totalItems) {
finalMessage += " Perfect score! π₯³";
} else if (score >= totalItems / 2) {
finalMessage += " Great job! π";
}
feedbackDisplay.textContent = finalMessage;
feedbackDisplay.className = 'correct-feedback';
targetCoordsDisplay.textContent = "(β,β)";
itemNameDisplay.textContent = 'all the items';
// Optional: Add a visible reset button here instead of forcing refresh
return;
}
const currentItem = itemsToFind[currentItemIndex];
// --- Find Empty Cell for New Target ---
let newTargetFound = false;
let attempts = 0; // Prevent infinite loop
const maxAttempts = gridSize * gridSize * 2; // Generous limit
while (!newTargetFound && attempts < maxAttempts) {
targetX = Math.floor(Math.random() * gridSize) + 1;
targetY = Math.floor(Math.random() * gridSize) + 1;
const potentialCell = gridContainer.querySelector(`.grid-cell[data-x="${targetX}"][data-y="${targetY}"]`);
// Check if the cell exists AND is visually empty (no emoji)
if (potentialCell && potentialCell.textContent.trim() === '') {
newTargetFound = true;
}
attempts++;
}
// Handle unlikely case where no empty cell is found
if (!newTargetFound) {
console.error("Could not find an empty cell for the next target!");
feedbackDisplay.textContent = "Uh oh, the map is full! Please refresh.";
return;
}
// --- Update Display ---
itemNameDisplay.textContent = currentItem.name;
targetCoordsDisplay.textContent = `(${targetX}, ${targetY})`;
feedbackDisplay.textContent = `Where is ${currentItem.name}? (${currentItemIndex + 1}/${totalItems})`;
feedbackDisplay.className = '';
// Reset temporary styles from previous round
document.querySelectorAll('.grid-cell').forEach(cell => {
cell.classList.remove('just-found', 'incorrect');
});
console.log(`Round ${currentItemIndex + 1}: Find ${currentItem.name} at (${targetX}, ${targetY})`);
}
// --- Handle Cell Click ---
function handleCellClick(event) {
// Prevent action if round/game is over or cell already found
if (foundCurrent || currentItemIndex >= totalItems) return;
const clickedCell = event.target;
if (clickedCell.classList.contains('found-item')) return;
const clickedX = parseInt(clickedCell.dataset.x);
const clickedY = parseInt(clickedCell.dataset.y);
// Clear any lingering incorrect styles
document.querySelectorAll('.grid-cell.incorrect').forEach(cell => {
cell.classList.remove('incorrect');
});
// --- Check if Correct ---
if (clickedX === targetX && clickedY === targetY) {
foundCurrent = true;
score++;
updateScoreDisplay();
const currentItem = itemsToFind[currentItemIndex];
feedbackDisplay.textContent = `You found ${currentItem.name}! π`;
feedbackDisplay.className = 'correct-feedback';
clickedCell.textContent = currentItem.emoji; // Add emoji
clickedCell.classList.add('just-found'); // Temporary highlight
// After highlight animation, switch to permanent 'found' style
setTimeout(() => {
clickedCell.classList.remove('just-found');
clickedCell.classList.add('found-item');
}, 600); // Duration should be >= pulse animation time
currentItemIndex++; // Move to next item
setTimeout(setNewTarget, 1800); // Delay before next target
} else {
// --- Incorrect Guess ---
feedbackDisplay.textContent = "Not quite! Try again. π€";
feedbackDisplay.className = 'incorrect-feedback';
clickedCell.classList.add('incorrect');
// Remove incorrect style after shake animation
setTimeout(() => {
// Check if still marked incorrect (user might click fast)
if (clickedCell.classList.contains('incorrect')) {
clickedCell.classList.remove('incorrect');
}
}, 500); // Match shake animation duration
}
}
// --- Start the Game ---
initializeGameArea();
setNewTarget();
}); // End DOMContentLoaded |