File size: 9,571 Bytes
dbdfa02
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
document.addEventListener('DOMContentLoaded', () => {
    const scoreDisplay = document.getElementById('score');
    const totalQuestionsDisplay = document.getElementById('total-questions');
    const num1Display = document.getElementById('num1');
    const num2Display = document.getElementById('num2');
    const feedbackArea = document.getElementById('feedback-area');
    const fieldChoicesContainer = document.getElementById('field-choices');

    const OPTIONS_COUNT = 3; // Number of plot choices (1 correct, 2 incorrect)
    const MAX_FACTOR = 6; // Maximum number for factors (e.g., up to 6x6)
    const TOTAL_ROUNDS = 10; // Number of questions in a game

    // --- Items for the Farm ---
    const farmItems = ['🍎', 'πŸ₯•', 'πŸ”', 'πŸ‘', '🌻', '🌽'];

    // --- Generate Multiplication Problems ---
    let possibleProblems = [];
    function generateProblems() {
        possibleProblems = [];
        for (let i = 1; i <= MAX_FACTOR; i++) {
            // Start j from 1 to include squares and both orders (e.g., 2x3 and 3x2 are distinct visual arrays)
            for (let j = 1; j <= MAX_FACTOR; j++) {
                possibleProblems.push({ num1: i, num2: j, answer: i * j });
            }
        }
        // Remove duplicates might be needed if we consider A*B same as B*A later
    }

    // --- Game State ---
    let score = 0;
    let currentProblem = null;
    let currentRound = 0;
    let waitingForNext = false;

    // --- Utility: Get Random Int ---
    function getRandomInt(max) {
        return Math.floor(Math.random() * max);
    }

    // --- Utility: Shuffle Array ---
    function shuffleArray(array) {
        for (let i = array.length - 1; i > 0; i--) {
            const j = getRandomInt(i + 1);
            [array[i], array[j]] = [array[j], array[i]];
        }
    }

    // --- Setup a New Round ---
    function setupNewRound() {
        if (currentRound >= TOTAL_ROUNDS) {
            endGame();
            return;
        }

        waitingForNext = false;
        fieldChoicesContainer.innerHTML = '';
        feedbackArea.textContent = "Click the farm plot that matches the problem!";
        feedbackArea.className = '';

        currentRound++;

        // 1. Choose a target problem
        if (!possibleProblems || possibleProblems.length === 0) generateProblems(); // Regenerate if empty
        const problemIndex = getRandomInt(possibleProblems.length);
        currentProblem = possibleProblems.splice(problemIndex, 1)[0]; // Pick and remove

        num1Display.textContent = currentProblem.num1;
        num2Display.textContent = currentProblem.num2;

        // 2. Create options array (as {rows, cols})
        // Allow commutative property visually (3x4 can be 3 rows of 4 OR 4 rows of 3)
        const correctOption = { rows: currentProblem.num1, cols: currentProblem.num2 };
        const options = [correctOption];

        // 3. Generate incorrect options
        while (options.length < OPTIONS_COUNT) {
            let wrongRows, wrongCols;
            let isDuplicate = true;
            let attempts = 0; // Prevent infinite loop

            while(isDuplicate && attempts < 20) {
                // Generate wrong dimensions, make sure at least one is different
                const changeRows = Math.random() > 0.5;
                 wrongRows = changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.rows;
                 wrongCols = !changeRows ? getRandomInt(MAX_FACTOR) + 1 : correctOption.cols;

                 // Ensure it's actually wrong AND not zero product AND different from target
                 if((wrongRows !== correctOption.rows || wrongCols !== correctOption.cols) &&
                    (wrongRows * wrongCols > 0) ) {

                     // Check if this combination (or its commutative pair) is already in options
                     isDuplicate = options.some(opt =>
                         (opt.rows === wrongRows && opt.cols === wrongCols) ||
                         (opt.rows === wrongCols && opt.cols === wrongRows)
                     );
                 } else {
                      isDuplicate = true; // Force retry if generated same as correct or zero product
                 }
                 attempts++;
            }
             // If stuck finding unique, just create a simple wrong one
             if (attempts >= 20) {
                 wrongRows = correctOption.rows === 1 ? 2 : correctOption.rows -1;
                 wrongCols = correctOption.cols;
                 isDuplicate = options.some(opt =>
                     (opt.rows === wrongRows && opt.cols === wrongCols) ||
                     (opt.rows === wrongCols && opt.cols === wrongRows)
                 ); // Final check
             }


            if (!isDuplicate) {
                options.push({ rows: wrongRows, cols: wrongCols });
            }
        }

        // 4. Shuffle options
        shuffleArray(options);

        // 5. Create and display field elements
        options.forEach(plot => {
            const fieldDiv = document.createElement('div');
            fieldDiv.classList.add('field-option');
            fieldDiv.dataset.rows = plot.rows;
            fieldDiv.dataset.cols = plot.cols;

            // Style the grid layout for items *inside* this field
            fieldDiv.style.gridTemplateColumns = `repeat(${plot.cols}, auto)`; // auto size columns
            fieldDiv.style.gridTemplateRows = `repeat(${plot.rows}, auto)`; // auto size rows
             // Set a max-width to prevent huge single rows/columns
             fieldDiv.style.maxWidth = `${plot.cols * 35}px`; // Approx item size + gap


            // Add items (emoji)
            const itemEmoji = farmItems[getRandomInt(farmItems.length)];
            for (let i = 0; i < plot.rows * plot.cols; i++) {
                const itemSpan = document.createElement('span');
                itemSpan.classList.add('item');
                itemSpan.textContent = itemEmoji;
                fieldDiv.appendChild(itemSpan);
            }

            fieldDiv.addEventListener('click', handleChoiceClick);
            fieldChoicesContainer.appendChild(fieldDiv);
        });

        console.log("New round setup. Target:", currentProblem);
    }

    // --- Handle Field Choice Click ---
    function handleChoiceClick(event) {
        if (waitingForNext) return;

        const clickedField = event.currentTarget;
        const clickedRows = parseInt(clickedField.dataset.rows);
        const clickedCols = parseInt(clickedField.dataset.cols);

        waitingForNext = true;

        // Remove listeners
        document.querySelectorAll('.field-option').forEach(opt => {
             const clone = opt.cloneNode(true);
             opt.parentNode.replaceChild(clone, opt);
        });

        // Check if correct (allow commutative: A x B or B x A)
        const isCorrect = (clickedRows === currentProblem.num1 && clickedCols === currentProblem.num2) ||
                          (clickedRows === currentProblem.num2 && clickedCols === currentProblem.num1);

        if (isCorrect) {
            score++;
            scoreDisplay.textContent = score;
            feedbackArea.textContent = `Yes! ${currentProblem.num1} x ${currentProblem.num2} = ${currentProblem.answer}! πŸŽ‰`;
            feedbackArea.className = 'correct-feedback';

            const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`);
            if (newClickedElement) newClickedElement.classList.add('correct-choice');

        } else {
            feedbackArea.textContent = `Oops! That shows ${clickedRows} x ${clickedCols}. The answer was ${currentProblem.answer}. πŸ€”`;
            feedbackArea.className = 'incorrect-feedback';

             const newClickedElement = fieldChoicesContainer.querySelector(`.field-option[data-rows="${clickedRows}"][data-cols="${clickedCols}"]`);
             if (newClickedElement) newClickedElement.classList.add('incorrect-choice');

             // Highlight the correct answer(s)
             setTimeout(() => {
                 const correctElement1 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num1}"][data-cols="${currentProblem.num2}"]`);
                 if (correctElement1) correctElement1.classList.add('correct-choice');
                 // Also highlight commutative pair if it exists and is different
                 const correctElement2 = fieldChoicesContainer.querySelector(`.field-option[data-rows="${currentProblem.num2}"][data-cols="${currentProblem.num1}"]`);
                 if (correctElement2 && correctElement1 !== correctElement2) correctElement2.classList.add('correct-choice');
             }, 300);
        }

        // Load next round
        setTimeout(setupNewRound, 2500); // Longer delay to see feedback/answer
    }

     // --- End Game ---
     function endGame() {
        feedbackArea.textContent = `Game Over! Your final score: ${score} / ${TOTAL_ROUNDS}! Great work! πŸ₯³`;
        feedbackArea.className = 'correct-feedback'; // Use correct style for positive end
        fieldChoicesContainer.innerHTML = '<p style="font-size:1.2em; color: #795548;">Refresh the page to play again!</p>'; // Clear options
        // Optionally disable further interaction if needed
    }

    // --- Initial Game Start ---
    totalQuestionsDisplay.textContent = TOTAL_ROUNDS; // Set total rounds display
    generateProblems(); // Create the initial list of problems
    setupNewRound();

}); // End DOMContentLoaded