Pp commited on
Commit
a91cf94
Β·
verified Β·
1 Parent(s): 84a2817

Create script.js

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