Pp commited on
Commit
28a75da
·
verified ·
1 Parent(s): 6862916

Upload 3 files

Browse files
Files changed (3) hide show
  1. index.html +45 -19
  2. script.js +221 -0
  3. style.css +142 -17
index.html CHANGED
@@ -1,19 +1,45 @@
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>Fraction Pizza Party! 🍕</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>Fraction Pizza Party!</h1>
15
+
16
+ <div id="score-area">
17
+ Score: <span id="score">0</span>
18
+ </div>
19
+
20
+ <div id="order-area">
21
+ <h2>Order Up!</h2>
22
+ <p>A customer wants:</p>
23
+ <div id="fraction-order" class="fraction-display">
24
+ <span class="numerator">?</span>
25
+ <span class="denominator">?</span>
26
+ </div>
27
+ </div>
28
+
29
+ <div id="feedback-area">
30
+ <!-- Feedback messages appear here -->
31
+ Click the pizza that matches the order!
32
+ </div>
33
+
34
+ <div id="pizza-options-area">
35
+ <h2>Choose the Pizza:</h2>
36
+ <div id="pizza-choices">
37
+ <!-- Pizza options will be dynamically added here by JS -->
38
+ </div>
39
+ </div>
40
+
41
+ </div> <!-- End of game-wrapper -->
42
+
43
+ <script src="script.js"></script>
44
+ </body>
45
+ </html>
script.js ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const scoreDisplay = document.getElementById('score');
3
+ const numeratorDisplay = document.querySelector('#fraction-order .numerator');
4
+ const denominatorDisplay = document.querySelector('#fraction-order .denominator');
5
+ const feedbackArea = document.getElementById('feedback-area');
6
+ const pizzaChoicesContainer = document.getElementById('pizza-choices');
7
+
8
+ const PIZZA_SIZE = 140; // Diameter of the pizza canvas
9
+ const OPTIONS_COUNT = 3; // Number of pizza choices to show (1 correct, 2 incorrect)
10
+
11
+ // --- Define Possible Fractions ---
12
+ // Start simple, can add more complex ones later
13
+ const possibleFractions = [
14
+ // Denominator 2
15
+ { num: 1, den: 2 },
16
+ // Denominator 3
17
+ { num: 1, den: 3 }, { num: 2, den: 3 },
18
+ // Denominator 4
19
+ { num: 1, den: 4 }, { num: 2, den: 4 }, { num: 3, den: 4 },
20
+ // Denominator 6
21
+ { num: 1, den: 6 }, { num: 2, den: 6 }, { num: 3, den: 6 }, { num: 4, den: 6 }, { num: 5, den: 6 },
22
+ // Denominator 8
23
+ { num: 1, den: 8 }, { num: 2, den: 8 }, { num: 3, den: 8 }, { num: 4, den: 8 },
24
+ { num: 5, den: 8 }, { num: 6, den: 8 }, { num: 7, den: 8 },
25
+ ];
26
+
27
+ // --- Game State ---
28
+ let score = 0;
29
+ let currentOrder = null; // Will hold {num, den} of the target fraction
30
+ let waitingForNext = false; // Flag to prevent clicks during feedback/delay
31
+
32
+ // --- Utility: Get Random Int ---
33
+ function getRandomInt(max) {
34
+ return Math.floor(Math.random() * max);
35
+ }
36
+
37
+ // --- Utility: Shuffle Array ---
38
+ function shuffleArray(array) {
39
+ for (let i = array.length - 1; i > 0; i--) {
40
+ const j = getRandomInt(i + 1);
41
+ [array[i], array[j]] = [array[j], array[i]]; // Swap elements
42
+ }
43
+ }
44
+
45
+ // --- Canvas Drawing Function ---
46
+ function drawPizza(canvas, num, den) {
47
+ const ctx = canvas.getContext('2d');
48
+ const radius = canvas.width / 2;
49
+ const centerX = radius;
50
+ const centerY = radius;
51
+ const sliceAngle = (Math.PI * 2) / den;
52
+
53
+ // Colors
54
+ const crustColor = '#f4a460'; // Sandy brown
55
+ const sauceColor = '#ff6347'; // Tomato red
56
+ const cheeseColor = '#fffacd'; // Lemon chiffon (looks like cheese)
57
+
58
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
59
+
60
+ // Draw base crust slightly larger
61
+ ctx.fillStyle = crustColor;
62
+ ctx.beginPath();
63
+ ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
64
+ ctx.fill();
65
+
66
+ // Draw cheese base smaller than crust
67
+ ctx.fillStyle = cheeseColor;
68
+ ctx.beginPath();
69
+ ctx.arc(centerX, centerY, radius * 0.95, 0, Math.PI * 2);
70
+ ctx.fill();
71
+
72
+
73
+ // Draw highlighted slices (sauce/toppings)
74
+ ctx.fillStyle = sauceColor;
75
+ for (let i = 0; i < num; i++) {
76
+ const startAngle = i * sliceAngle - Math.PI / 2; // Start from top
77
+ const endAngle = (i + 1) * sliceAngle - Math.PI / 2;
78
+
79
+ ctx.beginPath();
80
+ ctx.moveTo(centerX, centerY);
81
+ ctx.arc(centerX, centerY, radius * 0.95, startAngle, endAngle); // Fill up to cheese edge
82
+ ctx.closePath();
83
+ ctx.fill();
84
+ }
85
+
86
+ // Draw slice lines on top
87
+ ctx.strokeStyle = crustColor; // Darker lines for contrast
88
+ ctx.lineWidth = 2;
89
+ for (let i = 0; i < den; i++) {
90
+ const angle = i * sliceAngle - Math.PI / 2;
91
+ ctx.beginPath();
92
+ ctx.moveTo(centerX, centerY);
93
+ ctx.lineTo(centerX + radius * 0.95 * Math.cos(angle), centerY + radius * 0.95 * Math.sin(angle));
94
+ ctx.stroke();
95
+ }
96
+ }
97
+
98
+
99
+ // --- Setup a New Round ---
100
+ function setupNewRound() {
101
+ waitingForNext = false;
102
+ pizzaChoicesContainer.innerHTML = ''; // Clear previous pizzas
103
+ feedbackArea.textContent = "Click the pizza that matches the order!";
104
+ feedbackArea.className = ''; // Reset feedback style
105
+
106
+ // 1. Choose a target fraction
107
+ currentOrder = possibleFractions[getRandomInt(possibleFractions.length)];
108
+ numeratorDisplay.textContent = currentOrder.num;
109
+ denominatorDisplay.textContent = currentOrder.den;
110
+
111
+ // 2. Create options array, starting with the correct one
112
+ const options = [{ num: currentOrder.num, den: currentOrder.den }];
113
+
114
+ // 3. Generate incorrect options
115
+ while (options.length < OPTIONS_COUNT) {
116
+ const randomFraction = possibleFractions[getRandomInt(possibleFractions.length)];
117
+ // Make sure it's not the same as the target OR already in the options
118
+ const isDuplicate = options.some(opt => opt.num === randomFraction.num && opt.den === randomFraction.den);
119
+ if (!isDuplicate) {
120
+ options.push(randomFraction);
121
+ }
122
+ // Basic protection against infinite loop if somehow options are very limited
123
+ if(options.length < OPTIONS_COUNT && possibleFractions.length <= options.length){
124
+ console.warn("Not enough unique fractions to generate distractors. Reusing.");
125
+ // Add a non-duplicate if possible, otherwise just add another random one
126
+ let foundNew = false;
127
+ for(let frac of possibleFractions){
128
+ if(!options.some(opt => opt.num === frac.num && opt.den === frac.den)){
129
+ options.push(frac);
130
+ foundNew = true;
131
+ break;
132
+ }
133
+ }
134
+ if(!foundNew && options.length < OPTIONS_COUNT) options.push(randomFraction); // Add duplicate if absolutely needed
135
+ }
136
+
137
+ }
138
+
139
+ // 4. Shuffle options
140
+ shuffleArray(options);
141
+
142
+ // 5. Create and display pizza elements
143
+ options.forEach(fraction => {
144
+ const optionDiv = document.createElement('div');
145
+ optionDiv.classList.add('pizza-option');
146
+ optionDiv.dataset.num = fraction.num;
147
+ optionDiv.dataset.den = fraction.den;
148
+
149
+ const canvas = document.createElement('canvas');
150
+ canvas.classList.add('pizza-canvas');
151
+ canvas.width = PIZZA_SIZE;
152
+ canvas.height = PIZZA_SIZE;
153
+
154
+ optionDiv.appendChild(canvas);
155
+ pizzaChoicesContainer.appendChild(optionDiv);
156
+
157
+ drawPizza(canvas, fraction.num, fraction.den);
158
+
159
+ optionDiv.addEventListener('click', handleChoiceClick);
160
+ });
161
+
162
+ console.log("New round setup. Target:", currentOrder);
163
+ }
164
+
165
+ // --- Handle Pizza Choice Click ---
166
+ function handleChoiceClick(event) {
167
+ if (waitingForNext) return; // Don't process clicks during delay
168
+
169
+ const clickedPizza = event.currentTarget; // The div element
170
+ const clickedNum = parseInt(clickedPizza.dataset.num);
171
+ const clickedDen = parseInt(clickedPizza.dataset.den);
172
+
173
+ waitingForNext = true; // Prevent further clicks until next round
174
+
175
+ // Remove event listeners from all options to prevent multiple clicks
176
+ document.querySelectorAll('.pizza-option').forEach(opt => {
177
+ // Clone and replace to remove listeners easily, or store listeners and remove them
178
+ const clone = opt.cloneNode(true);
179
+ opt.parentNode.replaceChild(clone, opt);
180
+ });
181
+
182
+
183
+ // Check if correct
184
+ if (clickedNum === currentOrder.num && clickedDen === currentOrder.den) {
185
+ // Correct!
186
+ score++;
187
+ scoreDisplay.textContent = score;
188
+ feedbackArea.textContent = `Yummy! That's ${currentOrder.num}/${currentOrder.den}! 🎉`;
189
+ feedbackArea.className = 'correct-feedback';
190
+ clickedPizza.classList.add('correct-choice'); // Add animation class to the actual clicked element
191
+
192
+ // Find the *new* clone in the DOM to add the class (since we replaced it)
193
+ const newClickedElement = pizzaChoicesContainer.querySelector(`.pizza-option[data-num="${clickedNum}"][data-den="${clickedDen}"]`);
194
+ if (newClickedElement) newClickedElement.classList.add('correct-choice');
195
+
196
+
197
+ } else {
198
+ // Incorrect!
199
+ feedbackArea.textContent = `Oops! That shows ${clickedNum}/${clickedDen}. Try the next one! 🤔`;
200
+ feedbackArea.className = 'incorrect-feedback';
201
+
202
+ // Highlight the incorrect choice and the correct one (optional)
203
+ const newClickedElement = pizzaChoicesContainer.querySelector(`.pizza-option[data-num="${clickedNum}"][data-den="${clickedDen}"]`);
204
+ if (newClickedElement) newClickedElement.classList.add('incorrect-choice');
205
+
206
+ // Highlight the correct answer after a small delay
207
+ setTimeout(() => {
208
+ const correctElement = pizzaChoicesContainer.querySelector(`.pizza-option[data-num="${currentOrder.num}"][data-den="${currentOrder.den}"]`);
209
+ if (correctElement) correctElement.classList.add('correct-choice'); // Use correct style to show answer
210
+ }, 300);
211
+
212
+ }
213
+
214
+ // Load next round after a delay
215
+ setTimeout(setupNewRound, 2000); // Wait 2 seconds before next round
216
+ }
217
+
218
+ // --- Initial Game Start ---
219
+ setupNewRound();
220
+
221
+ }); // End DOMContentLoaded
style.css CHANGED
@@ -1,28 +1,153 @@
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; /* Align to top */
6
+ background-color: #f0e4d7; /* Light beige like dough */
7
+ color: #6b4f4f; /* Brownish text */
8
+ padding: 20px;
9
+ margin: 0;
10
+ min-height: 100vh;
11
+ }
12
+
13
+ #game-wrapper {
14
+ background-color: #fffaf0; /* Floral white */
15
+ padding: 20px 30px;
16
+ border-radius: 20px;
17
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.15);
18
+ border: 5px solid #a0522d; /* Sienna border */
19
+ max-width: 650px;
20
+ width: 90%;
21
+ text-align: center;
22
  }
23
 
24
  h1 {
25
+ color: #d9534f; /* Tomato red */
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.3em;
32
+ font-weight: bold;
33
+ color: #4682b4; /* Steel blue */
34
+ background-color: #e6f7ff;
35
+ padding: 5px 15px;
36
+ border-radius: 10px;
37
+ display: inline-block; /* Fit content */
38
+ margin-bottom: 20px;
39
+ border: 2px solid #add8e6; /* Light blue border */
40
+ }
41
+
42
+ #order-area {
43
+ background-color: #fff8dc; /* Cornsilk */
44
+ border: 3px dashed #a0522d; /* Sienna dashed border */
45
+ padding: 15px;
46
+ border-radius: 15px;
47
+ margin-bottom: 20px;
48
+ }
49
+
50
+ #order-area h2 {
51
+ margin-top: 0;
52
+ margin-bottom: 5px;
53
+ color: #8b4513; /* Saddle brown */
54
+ }
55
+
56
+ /* Fraction Display Styling */
57
+ .fraction-display {
58
+ display: inline-flex; /* Allows vertical alignment */
59
+ flex-direction: column;
60
+ align-items: center;
61
+ font-size: 2.5em; /* Large fraction */
62
+ font-weight: bold;
63
+ color: #c62828; /* Dark red */
64
+ margin-top: 5px;
65
+ }
66
+
67
+ .fraction-display .numerator {
68
+ line-height: 1;
69
+ }
70
+
71
+ .fraction-display .denominator {
72
+ line-height: 1;
73
+ border-top: 3px solid #c62828; /* Fraction line */
74
+ padding-top: 3px;
75
+ margin-top: 3px;
76
+ align-self: stretch; /* Make line stretch */
77
+ }
78
+
79
+ #feedback-area {
80
+ margin-bottom: 25px;
81
+ font-size: 1.2em;
82
+ font-weight: bold;
83
+ color: #00695c; /* Dark teal */
84
+ min-height: 30px; /* Prevent layout jumps */
85
+ padding: 10px;
86
+ border-radius: 8px;
87
+ background-color: #e0f2f1; /* Very light teal */
88
+ }
89
+
90
+ #feedback-area.correct-feedback {
91
+ color: #2e7d32; /* Dark Green */
92
+ background-color: #c8e6c9; /* Light Green */
93
+ }
94
+
95
+ #feedback-area.incorrect-feedback {
96
+ color: #c62828; /* Dark Red */
97
+ background-color: #ffcdd2; /* Light Red */
98
+ }
99
+
100
+ #pizza-options-area h2 {
101
+ color: #8b4513;
102
+ margin-bottom: 15px;
103
+ }
104
+
105
+ #pizza-choices {
106
+ display: flex;
107
+ justify-content: space-around;
108
+ align-items: center;
109
+ flex-wrap: wrap; /* Allow wrapping on smaller screens */
110
+ gap: 20px; /* Space between pizza options */
111
+ }
112
+
113
+ .pizza-option {
114
+ cursor: pointer;
115
+ border: 3px solid transparent; /* Reserve space for border */
116
+ border-radius: 50%; /* Make border circular */
117
+ transition: border-color 0.2s ease, transform 0.2s ease;
118
+ padding: 3px; /* Padding around canvas */
119
+ background-color: #fff; /* White background behind canvas */
120
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
121
+ }
122
+
123
+ .pizza-option:hover {
124
+ border-color: #f5a623; /* Orange hover border */
125
+ transform: scale(1.05);
126
+ }
127
+
128
+ .pizza-canvas {
129
+ display: block; /* Prevent extra space below canvas */
130
+ border-radius: 50%; /* Clip canvas drawing to circle */
131
  }
132
 
133
+ /* Feedback Animations */
134
+ .pizza-option.correct-choice {
135
+ border-color: #4caf50 !important; /* Green border */
136
+ animation: pulse 0.6s;
 
137
  }
138
 
139
+ .pizza-option.incorrect-choice {
140
+ border-color: #f44336 !important; /* Red border */
141
+ animation: shake 0.5s;
 
 
 
142
  }
143
 
144
+ @keyframes shake {
145
+ 0%, 100% { transform: translateX(0); }
146
+ 25% { transform: translateX(-6px); }
147
+ 75% { transform: translateX(6px); }
148
  }
149
+ @keyframes pulse {
150
+ 0% { transform: scale(1); }
151
+ 50% { transform: scale(1.1); }
152
+ 100% { transform: scale(1); }
153
+ }