Pp commited on
Commit
dbdfa02
·
verified ·
1 Parent(s): 1029d6c

Upload 3 files

Browse files
Files changed (3) hide show
  1. index.html +51 -19
  2. script.js +213 -0
  3. style.css +139 -17
index.html CHANGED
@@ -1,19 +1,51 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Multiplication Farm! 🧑‍🌾</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <link href="https://fonts.googleapis.com/css2?family=Lilita+One&display=swap" rel="stylesheet">
9
+ </head>
10
+ <body>
11
+
12
+ <div id="game-wrapper">
13
+
14
+ <h1>Multiplication Farm!</h1>
15
+
16
+ <div id="score-area">
17
+ Score: <span id="score">0</span> / <span id="total-questions">10</span>
18
+ </div>
19
+
20
+ <div id="problem-area">
21
+ <h2>Time to Plant/Gather!</h2>
22
+ <p>Show me this multiplication:</p>
23
+ <div id="multiplication-problem">
24
+ <span id="num1">?</span> x <span id="num2">?</span> = ?
25
+ </div>
26
+ </div>
27
+
28
+ <div id="feedback-area">
29
+ Click the farm plot that matches the problem!
30
+ </div>
31
+
32
+ <div id="farm-options-area">
33
+ <h2>Choose the Correct Farm Plot:</h2>
34
+ <div id="field-choices">
35
+ <!-- Farm plot options will be dynamically added here by JS -->
36
+ <!-- Example of one plot option structure (repeated by JS) -->
37
+ <!--
38
+ <div class="field-option" data-rows="3" data-cols="4">
39
+ <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div>
40
+ <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div>
41
+ <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div> <div class="item">🍎</div>
42
+ </div>
43
+ -->
44
+ </div>
45
+ </div>
46
+
47
+ </div> <!-- End of game-wrapper -->
48
+
49
+ <script src="script.js"></script>
50
+ </body>
51
+ </html>
script.js ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const scoreDisplay = document.getElementById('score');
3
+ const totalQuestionsDisplay = document.getElementById('total-questions');
4
+ const num1Display = document.getElementById('num1');
5
+ const num2Display = document.getElementById('num2');
6
+ const feedbackArea = document.getElementById('feedback-area');
7
+ const fieldChoicesContainer = document.getElementById('field-choices');
8
+
9
+ const OPTIONS_COUNT = 3; // Number of plot choices (1 correct, 2 incorrect)
10
+ const MAX_FACTOR = 6; // Maximum number for factors (e.g., up to 6x6)
11
+ const TOTAL_ROUNDS = 10; // Number of questions in a game
12
+
13
+ // --- Items for the Farm ---
14
+ const farmItems = ['🍎', '🥕', '🐔', '🐑', '🌻', '🌽'];
15
+
16
+ // --- Generate Multiplication Problems ---
17
+ let possibleProblems = [];
18
+ function generateProblems() {
19
+ possibleProblems = [];
20
+ for (let i = 1; i <= MAX_FACTOR; i++) {
21
+ // Start j from 1 to include squares and both orders (e.g., 2x3 and 3x2 are distinct visual arrays)
22
+ for (let j = 1; j <= MAX_FACTOR; j++) {
23
+ possibleProblems.push({ num1: i, num2: j, answer: i * j });
24
+ }
25
+ }
26
+ // Remove duplicates might be needed if we consider A*B same as B*A later
27
+ }
28
+
29
+ // --- Game State ---
30
+ let score = 0;
31
+ let currentProblem = null;
32
+ let currentRound = 0;
33
+ let waitingForNext = false;
34
+
35
+ // --- Utility: Get Random Int ---
36
+ function getRandomInt(max) {
37
+ return Math.floor(Math.random() * max);
38
+ }
39
+
40
+ // --- Utility: Shuffle Array ---
41
+ function shuffleArray(array) {
42
+ for (let i = array.length - 1; i > 0; i--) {
43
+ const j = getRandomInt(i + 1);
44
+ [array[i], array[j]] = [array[j], array[i]];
45
+ }
46
+ }
47
+
48
+ // --- Setup a New Round ---
49
+ function setupNewRound() {
50
+ if (currentRound >= TOTAL_ROUNDS) {
51
+ endGame();
52
+ return;
53
+ }
54
+
55
+ waitingForNext = false;
56
+ fieldChoicesContainer.innerHTML = '';
57
+ feedbackArea.textContent = "Click the farm plot that matches the problem!";
58
+ feedbackArea.className = '';
59
+
60
+ currentRound++;
61
+
62
+ // 1. Choose a target problem
63
+ if (!possibleProblems || possibleProblems.length === 0) generateProblems(); // Regenerate if empty
64
+ const problemIndex = getRandomInt(possibleProblems.length);
65
+ currentProblem = possibleProblems.splice(problemIndex, 1)[0]; // Pick and remove
66
+
67
+ num1Display.textContent = currentProblem.num1;
68
+ num2Display.textContent = currentProblem.num2;
69
+
70
+ // 2. Create options array (as {rows, cols})
71
+ // Allow commutative property visually (3x4 can be 3 rows of 4 OR 4 rows of 3)
72
+ const correctOption = { rows: currentProblem.num1, cols: currentProblem.num2 };
73
+ const options = [correctOption];
74
+
75
+ // 3. Generate incorrect options
76
+ while (options.length < OPTIONS_COUNT) {
77
+ let wrongRows, wrongCols;
78
+ let isDuplicate = true;
79
+ let attempts = 0; // Prevent infinite loop
80
+
81
+ while(isDuplicate && attempts < 20) {
82
+ // Generate wrong dimensions, make sure at least one is different
83
+ const changeRows = Math.random() > 0.5;
84
+ wrongRows = changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.rows;
85
+ wrongCols = !changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.cols;
86
+
87
+ // Ensure it's actually wrong AND not zero product AND different from target
88
+ if((wrongRows !== correctOption.rows || wrongCols !== correctOption.cols) &&
89
+ (wrongRows * wrongCols > 0) ) {
90
+
91
+ // Check if this combination (or its commutative pair) is already in options
92
+ isDuplicate = options.some(opt =>
93
+ (opt.rows === wrongRows && opt.cols === wrongCols) ||
94
+ (opt.rows === wrongCols && opt.cols === wrongRows)
95
+ );
96
+ } else {
97
+ isDuplicate = true; // Force retry if generated same as correct or zero product
98
+ }
99
+ attempts++;
100
+ }
101
+ // If stuck finding unique, just create a simple wrong one
102
+ if (attempts >= 20) {
103
+ wrongRows = correctOption.rows === 1 ? 2 : correctOption.rows -1;
104
+ wrongCols = correctOption.cols;
105
+ isDuplicate = options.some(opt =>
106
+ (opt.rows === wrongRows && opt.cols === wrongCols) ||
107
+ (opt.rows === wrongCols && opt.cols === wrongRows)
108
+ ); // Final check
109
+ }
110
+
111
+
112
+ if (!isDuplicate) {
113
+ options.push({ rows: wrongRows, cols: wrongCols });
114
+ }
115
+ }
116
+
117
+ // 4. Shuffle options
118
+ shuffleArray(options);
119
+
120
+ // 5. Create and display field elements
121
+ options.forEach(plot => {
122
+ const fieldDiv = document.createElement('div');
123
+ fieldDiv.classList.add('field-option');
124
+ fieldDiv.dataset.rows = plot.rows;
125
+ fieldDiv.dataset.cols = plot.cols;
126
+
127
+ // Style the grid layout for items *inside* this field
128
+ fieldDiv.style.gridTemplateColumns = `repeat(${plot.cols}, auto)`; // auto size columns
129
+ fieldDiv.style.gridTemplateRows = `repeat(${plot.rows}, auto)`; // auto size rows
130
+ // Set a max-width to prevent huge single rows/columns
131
+ fieldDiv.style.maxWidth = `${plot.cols * 35}px`; // Approx item size + gap
132
+
133
+
134
+ // Add items (emoji)
135
+ const itemEmoji = farmItems[getRandomInt(farmItems.length)];
136
+ for (let i = 0; i < plot.rows * plot.cols; i++) {
137
+ const itemSpan = document.createElement('span');
138
+ itemSpan.classList.add('item');
139
+ itemSpan.textContent = itemEmoji;
140
+ fieldDiv.appendChild(itemSpan);
141
+ }
142
+
143
+ fieldDiv.addEventListener('click', handleChoiceClick);
144
+ fieldChoicesContainer.appendChild(fieldDiv);
145
+ });
146
+
147
+ console.log("New round setup. Target:", currentProblem);
148
+ }
149
+
150
+ // --- Handle Field Choice Click ---
151
+ function handleChoiceClick(event) {
152
+ if (waitingForNext) return;
153
+
154
+ const clickedField = event.currentTarget;
155
+ const clickedRows = parseInt(clickedField.dataset.rows);
156
+ const clickedCols = parseInt(clickedField.dataset.cols);
157
+
158
+ waitingForNext = true;
159
+
160
+ // Remove listeners
161
+ document.querySelectorAll('.field-option').forEach(opt => {
162
+ const clone = opt.cloneNode(true);
163
+ opt.parentNode.replaceChild(clone, opt);
164
+ });
165
+
166
+ // Check if correct (allow commutative: A x B or B x A)
167
+ const isCorrect = (clickedRows === currentProblem.num1 && clickedCols === currentProblem.num2) ||
168
+ (clickedRows === currentProblem.num2 && clickedCols === currentProblem.num1);
169
+
170
+ if (isCorrect) {
171
+ score++;
172
+ scoreDisplay.textContent = score;
173
+ feedbackArea.textContent = `Yes! ${currentProblem.num1} x ${currentProblem.num2} = ${currentProblem.answer}! 🎉`;
174
+ feedbackArea.className = 'correct-feedback';
175
+
176
+ const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`);
177
+ if (newClickedElement) newClickedElement.classList.add('correct-choice');
178
+
179
+ } else {
180
+ feedbackArea.textContent = `Oops! That shows ${clickedRows} x ${clickedCols}. The answer was ${currentProblem.answer}. 🤔`;
181
+ feedbackArea.className = 'incorrect-feedback';
182
+
183
+ const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`);
184
+ if (newClickedElement) newClickedElement.classList.add('incorrect-choice');
185
+
186
+ // Highlight the correct answer(s)
187
+ setTimeout(() => {
188
+ const correctElement1 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num1}"][data-cols="${currentProblem.num2}"]`);
189
+ if (correctElement1) correctElement1.classList.add('correct-choice');
190
+ // Also highlight commutative pair if it exists and is different
191
+ const correctElement2 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num2}"][data-cols="${currentProblem.num1}"]`);
192
+ if (correctElement2 && correctElement1 !== correctElement2) correctElement2.classList.add('correct-choice');
193
+ }, 300);
194
+ }
195
+
196
+ // Load next round
197
+ setTimeout(setupNewRound, 2500); // Longer delay to see feedback/answer
198
+ }
199
+
200
+ // --- End Game ---
201
+ function endGame() {
202
+ feedbackArea.textContent = `Game Over! Your final score: ${score} / ${TOTAL_ROUNDS}! Great work! 🥳`;
203
+ feedbackArea.className = 'correct-feedback'; // Use correct style for positive end
204
+ fieldChoicesContainer.innerHTML = '<p style="font-size:1.2em; color: #795548;">Refresh the page to play again!</p>'; // Clear options
205
+ // Optionally disable further interaction if needed
206
+ }
207
+
208
+ // --- Initial Game Start ---
209
+ totalQuestionsDisplay.textContent = TOTAL_ROUNDS; // Set total rounds display
210
+ generateProblems(); // Create the initial list of problems
211
+ setupNewRound();
212
+
213
+ }); // End DOMContentLoaded
style.css CHANGED
@@ -1,28 +1,150 @@
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
  h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
 
28
  }
 
 
 
 
 
 
1
  body {
2
+ font-family: 'Lilita One', cursive;
3
+ display: flex;
4
+ justify-content: center;
5
+ align-items: flex-start;
6
+ background-color: #c8e6c9; /* Light green background */
7
+ color: #388e3c; /* Darker green */
8
+ padding: 20px;
9
+ margin: 0;
10
+ min-height: 100vh;
11
+ }
12
+
13
+ #game-wrapper {
14
+ background-color: #fffde7; /* Light yellow */
15
+ padding: 20px 30px;
16
+ border-radius: 20px;
17
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
18
+ border: 5px solid #795548; /* Brown border */
19
+ max-width: 700px;
20
+ width: 95%;
21
+ text-align: center;
22
  }
23
 
24
  h1 {
25
+ color: #fb8c00; /* Orange */
26
+ text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.1);
27
+ margin-bottom: 15px;
28
+ }
29
+
30
+ #score-area {
31
+ font-size: 1.2em;
32
+ font-weight: bold;
33
+ color: #1e88e5; /* Blue */
34
+ background-color: #e3f2fd; /* Light blue */
35
+ padding: 5px 15px;
36
+ border-radius: 10px;
37
+ display: inline-block;
38
+ margin-bottom: 20px;
39
+ border: 2px solid #90caf9; /* Lighter blue border */
40
+ }
41
+
42
+ #problem-area {
43
+ background-color: #ffecb3; /* Light amber */
44
+ border: 3px dashed #ff8f00; /* Amber dashed border */
45
+ padding: 15px;
46
+ border-radius: 15px;
47
+ margin-bottom: 20px;
48
+ }
49
+
50
+ #problem-area h2 {
51
+ margin-top: 0;
52
+ margin-bottom: 5px;
53
+ color: #795548; /* Brown */
54
+ }
55
+ #problem-area p {
56
+ margin-top: 0;
57
+ margin-bottom: 10px;
58
+ font-size: 1.1em;
59
+ }
60
+
61
+
62
+ #multiplication-problem {
63
+ font-size: 2.8em; /* Large problem display */
64
+ font-weight: bold;
65
+ color: #e53935; /* Red */
66
+ }
67
+
68
+ #feedback-area {
69
+ margin-bottom: 25px;
70
+ font-size: 1.1em;
71
+ font-weight: bold;
72
+ color: #5d4037; /* Brown */
73
+ min-height: 30px;
74
+ padding: 10px;
75
+ border-radius: 8px;
76
+ background-color: #efebe9; /* Light brown/grey */
77
+ }
78
+
79
+ #feedback-area.correct-feedback {
80
+ color: #2e7d32; /* Dark Green */
81
+ background-color: #c8e6c9; /* Light Green */
82
+ }
83
+
84
+ #feedback-area.incorrect-feedback {
85
+ color: #c62828; /* Dark Red */
86
+ background-color: #ffcdd2; /* Light Red */
87
+ }
88
+
89
+ #farm-options-area h2 {
90
+ color: #795548; /* Brown */
91
+ margin-bottom: 15px;
92
+ }
93
+
94
+ #field-choices {
95
+ display: flex;
96
+ justify-content: space-around;
97
+ align-items: flex-start; /* Align tops of potentially diff height grids */
98
+ flex-wrap: wrap;
99
+ gap: 25px; /* Space between plot options */
100
+ }
101
+
102
+ .field-option {
103
+ cursor: pointer;
104
+ border: 4px solid #a1887f; /* Brownish border */
105
+ background-color: #d7ccc8; /* Light background for field */
106
+ padding: 10px;
107
+ border-radius: 8px;
108
+ transition: border-color 0.2s ease, transform 0.2s ease;
109
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
110
+
111
+ /* CSS Grid for items inside */
112
+ display: grid;
113
+ gap: 4px; /* Space between items */
114
+ /* grid-template-columns/rows set by JS */
115
+ }
116
+
117
+ .field-option:hover {
118
+ border-color: #fb8c00; /* Orange hover border */
119
+ transform: translateY(-3px);
120
+ }
121
+
122
+ .field-option .item {
123
+ font-size: 1.8em; /* Size of the emoji/item */
124
+ line-height: 1; /* Prevent extra vertical space */
125
+ display: flex;
126
+ justify-content: center;
127
+ align-items: center;
128
  }
129
 
130
+ /* Feedback Animations */
131
+ .field-option.correct-choice {
132
+ border-color: #4caf50 !important; /* Green border */
133
+ animation: pulse 0.6s;
 
134
  }
135
 
136
+ .field-option.incorrect-choice {
137
+ border-color: #f44336 !important; /* Red border */
138
+ animation: shake 0.5s;
 
 
 
139
  }
140
 
141
+ @keyframes shake {
142
+ 0%, 100% { transform: translateX(0); }
143
+ 25% { transform: translateX(-6px); }
144
+ 75% { transform: translateX(6px); }
145
  }
146
+ @keyframes pulse {
147
+ 0% { transform: scale(1); }
148
+ 50% { transform: scale(1.05); }
149
+ 100% { transform: scale(1); }
150
+ }