🎮ArcadeLab

🎧 Grain Rain - Listen & Interpret

by RocketGecko40
490 lines15.3 KB
▶ Play
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>🎧 Grain Rain - Listen & Interpret</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', 'Poppins', sans-serif;
            background: linear-gradient(135deg, #667eea, #764ba2);
            min-height: 100vh;
            padding: 20px;
        }

        .game-box {
            max-width: 700px;
            margin: 0 auto;
        }

        .header {
            background: white;
            border-radius: 30px;
            padding: 20px;
            margin-bottom: 25px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-wrap: wrap;
            gap: 15px;
            box-shadow: 0 10px 20px rgba(0,0,0,0.1);
        }

        .score {
            background: #764ba2;
            padding: 10px 25px;
            border-radius: 50px;
            color: white;
            font-weight: bold;
            font-size: 1.3rem;
        }

        .round {
            background: #667eea;
            padding: 10px 25px;
            border-radius: 50px;
            color: white;
            font-weight: bold;
        }

        .name-input {
            display: flex;
            gap: 8px;
        }

        .name-input input {
            padding: 8px 12px;
            border-radius: 50px;
            border: 1px solid #ddd;
        }

        .name-input button {
            background: #667eea;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 50px;
            cursor: pointer;
        }

        .main-card {
            background: white;
            border-radius: 30px;
            padding: 30px;
            margin-bottom: 20px;
            box-shadow: 0 15px 30px rgba(0,0,0,0.15);
        }

        .audio-section {
            background: #f0f4ff;
            border-radius: 20px;
            padding: 20px;
            text-align: center;
            margin-bottom: 25px;
        }

        .play-sim {
            background: #667eea;
            color: white;
            border: none;
            padding: 15px 30px;
            border-radius: 60px;
            font-size: 1.2rem;
            font-weight: bold;
            cursor: pointer;
            margin: 10px 0;
        }

        .play-sim:hover {
            background: #764ba2;
        }

        .script {
            background: #f8f9fa;
            padding: 15px;
            border-radius: 15px;
            font-size: 0.9rem;
            margin-top: 15px;
            display: none;
            text-align: left;
        }

        .script.show {
            display: block;
        }

        .toggle-script {
            background: none;
            border: none;
            color: #667eea;
            cursor: pointer;
            font-size: 0.85rem;
            margin-top: 10px;
        }

        .interpreting-area {
            margin-top: 20px;
        }

        textarea {
            width: 100%;
            padding: 15px;
            border: 2px solid #e0e0e0;
            border-radius: 20px;
            font-size: 1rem;
            font-family: inherit;
            min-height: 100px;
            resize: vertical;
        }

        .submit-btn {
            background: #4caf50;
            color: white;
            border: none;
            padding: 12px 25px;
            border-radius: 50px;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            margin-top: 15px;
            width: 100%;
        }

        .submit-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
        }

        .feedback {
            margin-top: 20px;
            padding: 15px;
            border-radius: 20px;
        }

        .feedback.great {
            background: #d4edda;
            color: #155724;
            border-left: 5px solid #28a745;
        }

        .feedback.good {
            background: #fff3cd;
            color: #856404;
            border-left: 5px solid #ffc107;
        }

        .feedback.keep {
            background: #f8d7da;
            color: #721c24;
            border-left: 5px solid #dc3545;
        }

        .next-btn {
            background: #667eea;
            color: white;
            border: none;
            padding: 12px;
            border-radius: 50px;
            font-size: 1rem;
            font-weight: bold;
            cursor: pointer;
            margin-top: 20px;
            width: 100%;
        }

        .leaderboard {
            background: rgba(255,255,255,0.95);
            border-radius: 25px;
            padding: 20px;
        }

        .leaderboard h3 {
            color: #333;
            margin-bottom: 15px;
        }

        .leaderboard ul {
            list-style: none;
        }

        .leaderboard li {
            padding: 10px 15px;
            background: #f0f0f0;
            margin-bottom: 8px;
            border-radius: 15px;
            display: flex;
            justify-content: space-between;
        }

        .reset-btn {
            background: #e74c3c;
            color: white;
            border: none;
            padding: 10px;
            border-radius: 50px;
            cursor: pointer;
            margin-top: 15px;
            width: 100%;
        }

        .end-screen {
            text-align: center;
        }

        .end-screen h2 {
            color: #667eea;
            font-size: 1.8rem;
        }

        @media (max-width: 550px) {
            .main-card { padding: 20px; }
        }
    </style>
</head>
<body>
<div class="game-box">
    <div class="header">
        <div class="score">🎧 Score: <span id="score">0</span></div>
        <div class="round">Round <span id="currentRound">1</span>/<span id="totalRounds">4</span></div>
        <div class="name-input">
            <input type="text" id="playerName" placeholder="Your name" value="Student">
            <button onclick="resetGame()">🔄 New</button>
        </div>
    </div>

    <div class="main-card" id="mainCard">
        <div id="content"></div>
    </div>

    <div class="leaderboard">
        <h3>🏆 Best Interpreters</h3>
        <ul id="leaderboardList">
            <li>Complete a round to appear!</li>
        </ul>
        <button class="reset-btn" onclick="resetAllScores()">🗑️ Reset Scores</button>
    </div>
</div>

<script>
    // Simple interpreting passages with key words
    const rounds = [
        {
            title: "🌾 What is Grain Rain?",
            audioText: "Grain Rain is the sixth solar term. It is the last term of spring. The name means 'rain helps grains grow.'",
            targetAnswer: "谷雨是第六个节气。它是春季的最后一个节气。名字的意思是'雨帮助谷物生长。'",
            keywords: ["谷雨", "第六个", "节气", "春季", "最后", "雨", "谷物", "生长"],
            maxPoints: 20
        },
        {
            title: "🍵 Drinking Guyu Tea",
            audioText: "In southern China, people drink Guyu tea. They believe it removes heat and brings good luck.",
            targetAnswer: "在中国南方,人们喝谷雨茶。他们相信它可以清热并带来好运。",
            keywords: ["南方", "喝", "谷雨茶", "清热", "好运"],
            maxPoints: 20
        },
        {
            title: "🥬 Eating Chinese Toon",
            audioText: "In northern China, people eat Chinese toon during Grain Rain. An old saying says it is as tender as silk before the rain.",
            targetAnswer: "在中国北方,人们在谷雨时节吃香椿。古语说雨前的香椿嫩如丝。",
            keywords: ["北方", "香椿", "谷雨", "雨前", "嫩如丝"],
            maxPoints: 20
        },
        {
            title: "🌸 Peony Flowers",
            audioText: "During Grain Rain, peony flowers bloom. The peony is called the 'Queen of All Flowers' in Chinese culture.",
            targetAnswer: "谷雨期间,牡丹花盛开。牡丹在中国文化中被称为'花中之王'。",
            keywords: ["谷雨", "牡丹", "开花", "花中之王", "中国文化"],
            maxPoints: 20
        }
    ];

    let currentIndex = 0;
    let totalScore = 0;
    let answered = false;
    let leaderboard = [];

    function loadLeaderboard() {
        const saved = localStorage.getItem("grainRainListen");
        if (saved) leaderboard = JSON.parse(saved);
        else leaderboard = [];
        showLeaderboard();
    }

    function saveLeaderboard() {
        localStorage.setItem("grainRainListen", JSON.stringify(leaderboard));
    }

    function showLeaderboard() {
        const list = document.getElementById("leaderboardList");
        if (!list) return;
        if (leaderboard.length === 0) {
            list.innerHTML = "<li>🎤 Play to become a top interpreter!</li>";
            return;
        }
        const top8 = [...leaderboard].sort((a,b) => b.score - a.score).slice(0,8);
        list.innerHTML = top8.map((entry, i) => 
            `<li><span>${i+1}. ${entry.name}</span><span>🎧 ${entry.score}</span></li>`
        ).join("");
    }

    function addScore(name, score) {
        leaderboard.push({ name: name, score: score });
        leaderboard.sort((a,b) => b.score - a.score);
        leaderboard = leaderboard.slice(0, 10);
        saveLeaderboard();
        showLeaderboard();
    }

    function updateDisplay() {
        document.getElementById("score").innerText = totalScore;
        document.getElementById("currentRound").innerText = currentIndex + 1;
        document.getElementById("totalRounds").innerText = rounds.length;
    }

    function toggleScript() {
        const scriptBox = document.querySelector(".script-box");
        if (scriptBox) scriptBox.classList.toggle("show");
    }

    function checkAnswer() {
        if (answered) return;
        
        const input = document.querySelector("textarea");
        const userAnswer = input.value.trim().toLowerCase();
        const round = rounds[currentIndex];
        
        // Count keywords found
        let found = 0;
        for (let kw of round.keywords) {
            if (userAnswer.includes(kw.toLowerCase())) {
                found++;
            }
        }
        
        const percentage = found / round.keywords.length;
        let earned = 0;
        let feedbackClass = "";
        let message = "";
        
        if (percentage >= 0.7) {
            earned = round.maxPoints;
            feedbackClass = "great";
            message = `🎉 EXCELLENT! +${earned} points! You got ${found}/${round.keywords.length} key words.`;
        } else if (percentage >= 0.4) {
            earned = Math.floor(round.maxPoints * 0.6);
            feedbackClass = "good";
            message = `👍 GOOD JOB! +${earned} points! You got ${found}/${round.keywords.length} key words.`;
        } else {
            earned = 0;
            feedbackClass = "keep";
            message = `📚 KEEP PRACTICING! +0 points. You got ${found}/${round.keywords.length} key words.<br><br>📝 Reference: ${round.targetAnswer}`;
        }
        
        totalScore += earned;
        updateDisplay();
        answered = true;
        
        const container = document.getElementById("content");
        const feedbackDiv = document.createElement("div");
        feedbackDiv.className = `feedback ${feedbackClass}`;
        feedbackDiv.innerHTML = message;
        container.appendChild(feedbackDiv);
        
        // Disable input and submit
        const textarea = document.querySelector("textarea");
        const submitBtn = document.querySelector(".submit-btn");
        if (textarea) textarea.disabled = true;
        if (submitBtn) submitBtn.disabled = true;
        
        // Next button
        const nextBtn = document.createElement("button");
        nextBtn.innerText = currentIndex + 1 === rounds.length ? "🏆 FINISH" : "➡️ NEXT ROUND";
        nextBtn.className = "next-btn";
        nextBtn.onclick = () => {
            currentIndex++;
            if (currentIndex < rounds.length) {
                renderRound();
            } else {
                endGame();
            }
        };
        container.appendChild(nextBtn);
    }
    
    function renderRound() {
        answered = false;
        const round = rounds[currentIndex];
        const container = document.getElementById("content");
        
        let html = `
            <div class="audio-section">
                <p style="font-size: 1.2rem; margin-bottom: 10px;">🎧 ${round.title}</p>
                <button class="play-sim" id="playBtn">🔊 CLICK - TEACHER READS</button>
                <button class="toggle-script" onclick="toggleScript()">📄 Show/Hide Script</button>
                <div class="script script-box">
                    <strong>📖 English Script (Teacher reads this):</strong><br>
                    "${round.audioText}"
                </div>
            </div>
            <div class="interpreting-area">
                <p style="margin-bottom: 10px; color: #555;">✍️ Write your Chinese interpretation below:</p>
                <textarea placeholder="Type your Chinese translation here..."></textarea>
                <button class="submit-btn" onclick="checkAnswer()">🎤 SUBMIT</button>
            </div>
        `;
        
        container.innerHTML = html;
        updateDisplay();
        
        // Add audio simulation
        const playBtn = document.getElementById("playBtn");
        if (playBtn) {
            playBtn.onclick = () => {
                alert(`🎧 TEACHER READS ALOUD:\n\n"${round.audioText}"\n\n👂 Listen carefully! The teacher will read it twice. Take notes!`);
                playBtn.style.background = "#4caf50";
                playBtn.innerText = "✅ AUDIO PLAYED";
            };
        }
    }
    
    function endGame() {
        const name = document.getElementById("playerName").value || "Student";
        addScore(name, totalScore);
        const container = document.getElementById("content");
        container.innerHTML = `
            <div class="end-screen">
                <h2>🎉 Congratulations! 🎉</h2>
                <p style="font-size: 1.8rem; margin: 20px;">🎧 ${totalScore} / ${rounds.length * 20}</p>
                <p>${name}, great interpreting practice!</p>
                <p>💡 Tip: Focus on key words when listening!</p>
                <button class="next-btn" onclick="resetGame()">🔄 Play Again</button>
            </div>
        `;
    }
    
    function resetGame() {
        currentIndex = 0;
        totalScore = 0;
        answered = false;
        renderRound();
    }
    
    function resetAllScores() {
        if (confirm("Delete all scores?")) {
            leaderboard = [];
            saveLeaderboard();
            showLeaderboard();
        }
    }
    
    loadLeaderboard();
    resetGame();
</script>
</body>
</html>

Game Source: 🎧 Grain Rain - Listen & Interpret

Creator: RocketGecko40

Libraries: none

Complexity: complex (490 lines, 15.3 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: grain-rain-listen-interpret-rocketgecko40" to link back to the original. Then publish at arcadelab.ai/publish.