SG_P2_Math_Volume_3 / index.html
saurabh2086's picture
revert changes
47c1b72 verified
<!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>