SG_P2_Math_Volume_2 / index.html
saurabh2086's picture
First Commit
47b8f7f verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Volume Champions</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;
}
.difficulty-btn.active {
background-color: #3b82f6; /* blue-500 */
color: white;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
}
.jug-container {
transition: transform 0.2s ease-in-out;
}
.jug-container:hover {
transform: scale(1.05);
}
</style>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen">
<div class="container mx-auto p-4 sm:p-6 lg:p-8 max-w-5xl bg-white rounded-2xl shadow-lg">
<!-- Header -->
<header class="text-center mb-6">
<h1 class="text-4xl sm:text-5xl font-bold text-blue-600">Volume Champions</h1>
<p class="text-gray-500 mt-2">Select a level and solve the puzzle!</p>
</header>
<!-- Difficulty Controls -->
<div id="difficulty-controls" class="flex justify-center space-x-2 sm:space-x-4 mb-8">
<button data-level="easy" class="difficulty-btn w-24 sm:w-32 py-2 px-4 bg-gray-200 text-gray-700 font-bold rounded-full hover:bg-blue-500 hover:text-white transition-all duration-300">Easy</button>
<button data-level="medium" class="difficulty-btn w-24 sm:w-32 py-2 px-4 bg-gray-200 text-gray-700 font-bold rounded-full hover:bg-blue-500 hover:text-white transition-all duration-300">Medium</button>
<button data-level="hard" class="difficulty-btn w-24 sm:w-32 py-2 px-4 bg-gray-200 text-gray-700 font-bold rounded-full hover:bg-blue-500 hover:text-white transition-all duration-300">Hard</button>
</div>
<!-- Main Content Area -->
<main class="space-y-8">
<!-- Problem Visualization -->
<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">
<!-- Jugs and glasses will be rendered here -->
</div>
<!-- Questions and Actions -->
<div id="questions-container" class="bg-green-50 p-6 rounded-xl border border-green-200">
<div id="questions-area" class="space-y-4 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>
<!-- Feedback Area -->
<div id="feedback-area" class="h-16 flex items-center justify-center text-2xl font-bold transition-all duration-300"></div>
</main>
</div>
<script>
// --- DOM Elements ---
const difficultyControls = document.getElementById('difficulty-controls');
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');
// --- Game State ---
let gameState = {
level: 'easy',
problemData: [],
questions: []
};
// --- Image URLs & SVG Templates ---
// Using local file references as requested.
const jugImageURLs = [
'jug.webp',
'carafe.avif',
'roundpot.jpg'
];
const glassSVG = `<svg viewBox="0 0 20 30" class="w-6 h-9" fill="#FBBF24"><path d="M1,0 H19 L17,30 H3 L1,0 Z"></path></svg>`;
// --- Difficulty Settings ---
const difficultySettings = {
easy: { numContainers: 2, maxUnits: 5 },
medium: { numContainers: 3, maxUnits: 10 },
hard: { numContainers: 4, maxUnits: 12 }
};
// --- Utility Functions ---
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// --- Core Game Logic ---
function generateProblem(level) {
gameState.level = level;
const settings = difficultySettings[level];
const containerNames = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
const usedValues = new Set();
gameState.problemData = [];
for (let i = 0; i < settings.numContainers; i++) {
let value;
do {
value = getRandomInt(1, settings.maxUnits);
} while (usedValues.has(value));
usedValues.add(value);
gameState.problemData.push({ name: containerNames[i], value: value });
}
renderProblem();
generateQuestions();
updateActiveButton();
feedbackArea.innerHTML = '';
}
function renderProblem() {
problemDisplay.innerHTML = '';
// Shuffle images for variety
const shuffledImages = [...jugImageURLs].sort(() => 0.5 - Math.random());
gameState.problemData.forEach((container, index) => {
let glassesHTML = '';
for(let i = 0; i < container.value; i++) {
glassesHTML += glassSVG;
}
// Pick a new jug image for each container, looping if needed
const currentImageURL = shuffledImages[index % shuffledImages.length];
const containerHTML = `
<div class="jug-container text-center p-4 bg-white rounded-lg shadow">
<img src="${currentImageURL}" alt="Jug" class="w-24 h-24 mx-auto object-contain">
<p class="text-3xl font-bold text-purple-700 mt-2">${container.name}</p>
<div class="flex flex-wrap justify-center gap-1 mt-4">
${glassesHTML}
</div>
<p class="text-sm text-gray-500 mt-2">(${container.value} glasses)</p>
</div>
`;
problemDisplay.innerHTML += containerHTML;
});
}
function generateQuestions() {
questionsArea.innerHTML = '';
gameState.questions = [];
const data = [...gameState.problemData];
const sortedData = [...data].sort((a, b) => a.value - b.value);
const smallest = sortedData[0];
const greatest = sortedData[sortedData.length - 1];
const questionTemplates = [
{
text: `Container <span class="font-bold text-green-700">__</span> has the smallest volume.`,
getAnswer: () => smallest.name
},
{
text: `Container <span class="font-bold text-green-700">__</span> has the greatest volume.`,
getAnswer: () => greatest.name
},
{
text: `Container ${greatest.name} has more volume than Container <span class="font-bold text-green-700">__</span>.`,
getAnswer: () => data.filter(c => c.value < greatest.value).map(c => c.name)
},
{
text: `Container ${smallest.name} has less volume than Container <span class="font-bold text-green-700">__</span>.`,
getAnswer: () => data.filter(c => c.value > smallest.value).map(c => c.name)
}
];
// Select questions based on level
let selectedQuestions = [];
if (gameState.level === 'easy') {
selectedQuestions = [questionTemplates[0], questionTemplates[1]];
} else {
// Shuffle and pick for medium/hard
questionTemplates.sort(() => 0.5 - Math.random());
selectedQuestions = questionTemplates.slice(0, 3);
}
selectedQuestions.forEach((q, index) => {
const answer = q.getAnswer();
gameState.questions.push({
id: `q${index}`,
correctAnswer: answer
});
const optionsHTML = gameState.problemData.map(c => `<option value="${c.name}">${c.name}</option>`).join('');
const questionHTML = `
<div class="flex items-center justify-center text-lg sm:text-xl">
<label for="q${index}" class="text-gray-700">${q.text.replace('__', `
<select id="q${index}" class="mx-2 p-1 border-2 border-green-400 rounded-md focus:outline-none focus:ring-2 focus:ring-green-500">
<option value="">?</option>
${optionsHTML}
</select>
`)}</label>
</div>
`;
questionsArea.innerHTML += questionHTML;
});
}
function checkAnswers() {
let allCorrect = true;
gameState.questions.forEach(q => {
const selectElement = document.getElementById(q.id);
const userAnswer = selectElement.value;
let isCorrect = false;
if (Array.isArray(q.correctAnswer)) {
isCorrect = q.correctAnswer.includes(userAnswer);
} else {
isCorrect = userAnswer === q.correctAnswer;
}
if (isCorrect) {
selectElement.classList.remove('border-red-400');
selectElement.classList.add('border-green-400');
} else {
selectElement.classList.remove('border-green-400');
selectElement.classList.add('border-red-400');
allCorrect = false;
}
});
if(allCorrect) {
feedbackArea.innerHTML = `<span class="text-green-500">๐ŸŽ‰ Well Done! All Correct! ๐ŸŽ‰</span>`;
} else {
feedbackArea.innerHTML = `<span class="text-red-500">Some answers are incorrect. Try again!</span>`;
}
}
function updateActiveButton() {
document.querySelectorAll('.difficulty-btn').forEach(btn => {
if(btn.dataset.level === gameState.level) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
});
}
// --- Event Listeners ---
difficultyControls.addEventListener('click', (e) => {
if (e.target.tagName === 'BUTTON') {
generateProblem(e.target.dataset.level);
}
});
checkBtn.addEventListener('click', checkAnswers);
newQuestionBtn.addEventListener('click', () => {
generateProblem(gameState.level);
});
// --- Initial Load ---
generateProblem('easy');
</script>
</body>
</html>