File size: 12,644 Bytes
b8edebc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47c1b72
b8edebc
47c1b72
 
 
b8edebc
 
47c1b72
 
 
 
 
b8edebc
 
 
47c1b72
 
b8edebc
 
47c1b72
 
 
b8edebc
 
47c1b72
b8edebc
 
 
 
 
 
 
 
 
 
 
 
076ed55
 
b8edebc
 
47c1b72
b8edebc
 
 
2659388
b8edebc
 
 
2659388
b8edebc
2659388
b8edebc
2659388
b8edebc
 
 
2659388
b8edebc
 
 
 
2659388
b8edebc
 
 
2659388
b8edebc
2659388
b8edebc
2659388
b8edebc
 
 
2659388
b8edebc
c72a153
b8edebc
2659388
b8edebc
2659388
b8edebc
2659388
b8edebc
 
 
 
 
2659388
b8edebc
2659388
b8edebc
2659388
b8edebc
2659388
b8edebc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2659388
 
b8edebc
47c1b72
 
 
 
 
 
b8edebc
 
 
 
 
 
 
 
 
076ed55
b8edebc
 
 
 
 
076ed55
 
b8edebc
 
 
 
076ed55
 
47c1b72
076ed55
 
 
b8edebc
 
47c1b72
 
076ed55
 
 
b8edebc
 
 
 
 
 
 
 
076ed55
 
 
 
b8edebc
076ed55
 
 
 
 
 
 
 
 
 
 
 
 
 
b8edebc
076ed55
b8edebc
 
 
 
 
 
 
 
 
076ed55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b8edebc
 
 
 
 
 
 
076ed55
 
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Volume Conservation Challenge</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;700&display=swap" rel="stylesheet">
    <style>
        body {
            font-family: 'Nunito', sans-serif;
        }
    </style>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen p-4">
    <div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-6xl bg-white rounded-2xl shadow-lg">

        <header class="text-center mb-6">
            <h1 class="text-4xl sm:text-5xl font-bold text-blue-600">Volume Voyagers</h1>
            <p class="text-gray-500 mt-2">The water amount might trick your eyes! Count the glasses.</p>
        </header>

        <!-- Difficulty controls removed -->

        <main class="space-y-8 mt-12">
            <!-- Aligned containers and set a consistent grid for 3 items -->
            <div id="problem-display" class="grid grid-cols-1 md:grid-cols-3 gap-6 bg-blue-50 p-6 rounded-xl border border-blue-200 min-h-[420px] items-end">
                <!-- Problem will be rendered here -->
            </div>

            <div id="questions-container" class="bg-green-50 p-6 rounded-xl border border-green-200">
                <div id="questions-area" class="space-y-6 mb-6">
                    <!-- Questions will be rendered here -->
                </div>
                <div class="flex flex-col sm:flex-row items-center justify-center space-y-4 sm:space-y-0 sm:space-x-4">
                    <button id="check-btn" class="w-full sm:w-auto bg-green-500 text-white font-bold py-3 px-8 rounded-lg shadow-md hover:bg-green-600 transition-transform transform hover:scale-105">Check Answers</button>
                    <button id="new-question-btn" class="w-full sm:w-auto bg-purple-500 text-white font-bold py-3 px-8 rounded-lg shadow-md hover:bg-purple-600 transition-transform transform hover:scale-105">New Question</button>
                </div>
            </div>
            <div id="feedback-area" class="h-16 flex items-center justify-center text-2xl font-bold transition-all duration-300"></div>
        </main>
    </div>

    <script>
        const problemDisplay = document.getElementById('problem-display');
        const questionsArea = document.getElementById('questions-area');
        const checkBtn = document.getElementById('check-btn');
        const newQuestionBtn = document.getElementById('new-question-btn');
        const feedbackArea = document.getElementById('feedback-area');

        let gameState = {
            problemData: [],
            questions: [],
            userAnswers: {}
        };
        
        const glassSVG = `<svg viewBox="0 0 20 30" class="w-6 h-9" fill="#a5f3fc"><path d="M1,0 H19 L17,30 H3 L1,0 Z"></path></svg>`;
        
        const containerSVGs = {
            beaker: {
                // Beaker: Made thinner for contrast
                svg: (fillHeight) => `
                    <svg viewBox="0 0 120 150">
                        <!-- Water -->
                        <rect x="33" y="${140 - fillHeight}" width="54" height="${fillHeight}" fill="#38bdf8" />
                        <!-- Glass outline -->
                        <path d="M30 10 H90 V140 H30 Z" stroke="#a0aec0" stroke-width="3" fill="rgba(237, 242, 247, 0.4)" />
                    </svg>`,
                factor: 22, // Increased factor because it's thinner
                maxFill: 130
            },
            flask: {
                // Flask: Made thinner for contrast
                svg: (fillHeight) => `
                    <svg viewBox="0 0 120 150">
                        <defs>
                            <clipPath id="flaskClip">
                                <path d="M45 10 H75 V50 L100 140 H20 L45 50 Z" />
                            </clipPath>
                        </defs>
                        <!-- Water -->
                        <rect x="20" y="${140 - fillHeight}" width="80" height="${fillHeight}" fill="#38bdf8" clip-path="url(#flaskClip)" />
                        <!-- Glass outline -->
                        <path d="M45 10 H75 V50 L100 140 H20 L45 50 Z" stroke="#a0aec0" stroke-width="3" fill="rgba(237, 242, 247, 0.4)" />
                    </svg>`,
                factor: 6, // Increased factor
                maxFill: 130
            },
            cylinder: {
                // Cylinder: Made thinner for contrast
                svg: (fillHeight) => `
                    <svg viewBox="0 0 120 150">
                         <!-- Water -->
                        <rect x="23" y="${140 - fillHeight}" width="74" height="${fillHeight}" rx="3" fill="#38bdf8" />
                        <!-- Glass outline -->
                        <rect x="20" y="40" width="80" height="100" rx="5" stroke="#a0aec0" stroke-width="3" fill="rgba(237, 242, 247, 0.4)" />
                    </svg>`,
                factor: 10, // Increased factor
                maxFill: 100
            },
            wideBowl: {
                // wideBowl: Very wide and shallow to make water level appear low
                svg: (fillHeight) => `
                    <svg viewBox="0 0 250 150">
                         <!-- Water -->
                        <rect x="8" y="${140 - fillHeight}" width="234" height="${fillHeight}" rx="5" fill="#38bdf8" />
                        <!-- Glass outline -->
                        <rect x="5" y="70" width="240" height="70" rx="8" stroke="#a0aec0" stroke-width="3" fill="rgba(237, 242, 247, 0.4)" />
                    </svg>`,
                factor: 1.8, // Very low factor means height increases slowly
                maxFill: 65 // Max fill height is low
            }
        };

        function getRandomInt(min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }

        function generateProblem() {
            const numContainers = 3;
            const maxUnits = 8;
            const containerNames = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
            const usedValues = new Set();
            const containerTypes = Object.keys(containerSVGs).sort(() => 0.5 - Math.random());
            
            gameState.problemData = [];
            for (let i = 0; i < numContainers; i++) {
                let value;
                do {
                    value = getRandomInt(1, maxUnits);
                } while (usedValues.has(value));
                usedValues.add(value);
                gameState.problemData.push({
                    name: containerNames[i],
                    value: value,
                    type: containerTypes[i % containerTypes.length]
                });
            }
            renderProblem();
            generateQuestions();
            feedbackArea.innerHTML = '';
        }

        function renderProblem() {
            problemDisplay.innerHTML = '';
            gameState.problemData.forEach(container => {
                let glassesHTML = Array(container.value).fill(glassSVG).join('');
                
                const containerInfo = containerSVGs[container.type];
                const fillHeight = Math.min(container.value * containerInfo.factor, containerInfo.maxFill);
                const containerHTML = containerInfo.svg(fillHeight);

                const widthClass = container.type === 'wideBowl' ? 'w-64' : 'w-32';

                const itemHTML = `
                    <div class="flex flex-col items-center text-center p-2">
                         <p class="text-xl font-bold text-gray-600 mb-2">${container.value} Glasses</p>
                        <div class="flex flex-wrap justify-center gap-1 min-h-[70px] mb-2">${glassesHTML}</div>
                        <div class="text-3xl text-blue-500 font-bold mb-2">&darr;</div>
                        <div class="${widthClass} h-32 mb-6 flex items-center justify-center">${containerHTML}</div>
                        <p class="text-2xl font-bold text-purple-700">Container ${container.name}</p>
                    </div>
                `;
                problemDisplay.innerHTML += itemHTML;
            });
        }
        
        function generateQuestions() {
            questionsArea.innerHTML = '';
            gameState.questions = [];
            gameState.userAnswers = {};
            const sortedData = [...gameState.problemData].sort((a, b) => a.value - b.value);
            const smallest = sortedData[0];
            const greatest = sortedData[sortedData.length - 1];

            const questionTemplates = [
                { text: `Which container has the <span class="font-bold text-red-500">smallest</span> volume?`, answer: smallest.name },
                { text: `Which container has the <span class="font-bold text-green-600">greatest</span> volume?`, answer: greatest.name },
            ];
            
            questionTemplates.forEach((q, index) => {
                gameState.questions.push({ id: `q${index}`, correctAnswer: q.answer });
                const optionsHTML = gameState.problemData.map(c => `
                    <button data-question-id="q${index}" data-value="${c.name}"
                            class="answer-btn bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-2 px-6 rounded-lg transition-colors">
                        ${c.name}
                    </button>
                `).join('');

                const questionHTML = `
                     <div class="flex flex-col sm:flex-row items-center justify-center text-lg sm:text-xl space-y-2 sm:space-y-0">
                        <p class="text-gray-700 mr-4 text-center">${q.text}</p>
                        <div class="flex space-x-2">
                            ${optionsHTML}
                        </div>
                    </div>
                `;
                questionsArea.innerHTML += questionHTML;
            });
        }

        function checkAnswers() {
            let allCorrect = true;
            if (Object.keys(gameState.userAnswers).length !== gameState.questions.length) {
                allCorrect = false;
            }

            gameState.questions.forEach(q => {
                const userAnswer = gameState.userAnswers[q.id];
                const buttonsForQuestion = questionsArea.querySelectorAll(`[data-question-id="${q.id}"]`);
                
                buttonsForQuestion.forEach(btn => btn.classList.remove('border-4', 'border-green-500', 'border-red-500'));

                if (!userAnswer) {
                     allCorrect = false;
                     return;
                }
                
                const selectedButton = questionsArea.querySelector(`[data-question-id="${q.id}"][data-value="${userAnswer}"]`);

                if (userAnswer === q.correctAnswer) {
                    selectedButton.classList.add('border-4', 'border-green-500');
                } else {
                    selectedButton.classList.add('border-4', 'border-red-500');
                    allCorrect = false;
                }
            });

            feedbackArea.innerHTML = allCorrect 
                ? `<span class="text-green-500">๐ŸŽ‰ Excellent! You didn't get tricked! ๐ŸŽ‰</span>`
                : `<span class="text-red-500">Not quite. Count the glasses carefully!</span>`;
        }
        
        questionsArea.addEventListener('click', (e) => {
            if (e.target.classList.contains('answer-btn')) {
                const questionId = e.target.dataset.questionId;
                const selectedValue = e.target.dataset.value;

                gameState.userAnswers[questionId] = selectedValue;

                const buttonsForQuestion = questionsArea.querySelectorAll(`[data-question-id="${questionId}"]`);
                buttonsForQuestion.forEach(btn => {
                    btn.classList.remove('bg-blue-500', 'text-white');
                    btn.classList.add('bg-gray-200', 'text-gray-700');
                });
                
                e.target.classList.add('bg-blue-500', 'text-white');
                e.target.classList.remove('bg-gray-200', 'text-gray-700');
            }
        });
        
        checkBtn.addEventListener('click', checkAnswers);
        newQuestionBtn.addEventListener('click', generateProblem);

        // Generate the initial problem
        generateProblem();
    </script>
</body>
</html>