user = $user; } /** * Make a problem, show it, and remember it as the student's open question. */ public function getWordProblem() { $problem = $this->getProblem(); $questionHtml = $this->htmlify($problem); $db = e107::getDb(); $db->delete('tkLastQuestion', "user = '" . $db->escape($this->user) . "'"); $db->insert('tkLastQuestion', ['user' => $this->user, 'LastQuestionHtml' => base64_encode($questionHtml)]); e107::getRender()->tablerender('Word problems', $questionHtml); } /** * Make a problem without showing it. * * @return array ['answer1' => int, 'question' => string, 'type' => 'word_problems'] */ public function getProblem() { $this->level = $this->difficulty(); $makers = ['pillowCases', 'sponges', 'elephant', 'sandwiches', 'marbles', 'beach', 'cupcakes', 'sugarBags']; $maker = $makers[array_rand($makers)]; list($question, $answer) = $this->$maker(); return ['answer1' => (int) $answer, 'question' => $question, 'type' => self::SUBJECT]; } /** * How hard to make the numbers, 0-100: last month's accuracy, scaled up * over the first 30 answers. * * @return float */ private function difficulty() { $db = e107::getDb(); $stats = $db->retrieve( "SELECT (SUM(correct)/COUNT(correct)*100) AS percent, COUNT(correct) AS count FROM `" . MPREFIX . "tkReport` WHERE answereddatestamp >= UNIX_TIMESTAMP(NOW() - INTERVAL 1 MONTH) AND username = '" . $db->escape($this->user) . "' AND subject = '" . self::SUBJECT . "'" ); if (!is_array($stats) || (int) $stats['count'] === 0) { return 0.0; } $sample = min(1.0, ((int) $stats['count']) / 30); return max(0.0, min(100.0, (float) $stats['percent'])) * $sample; } /** * A random whole number from $min up to $maxAtFull. At level 0 the top of * the range is a quarter of the way there; at level 100 it is all of it. */ private function num($min, $maxAtFull) { $span = max(0, $maxAtFull - $min); $max = $min + (int) ceil($span * (0.25 + 0.75 * $this->level / 100)); return mt_rand($min, max($min, $max)); } private function name() { return $this->names[array_rand($this->names)]; } // ---- the problems: each returns [question text, whole number answer] private function pillowCases() { $perCase = $this->num(2, 12); $made = $this->num(2, 10); $wanted = $this->num(2, 20); if ($wanted === $made) { $wanted++; } return [ $this->name() . ' used ' . ($perCase * $made) . ' metres of cloth to sew ' . $made . ' pillow cases. How much cloth would be used to sew ' . $wanted . ' pillow cases?', $perCase * $wanted, ]; } private function sponges() { $mass = $this->num(10, 60); $gain = $this->num(2, 30); $count = $this->num(2, 12); return [ 'The mass of a sponge is ' . $mass . ' g. When put in water it expanded and its mass became ' . ($mass + $gain) . ' g. How much extra mass would ' . $count . ' similar sponges gain altogether?', $gain * $count, ]; } private function elephant() { $kg = $this->num(10, 150); $years = $this->num(2, 10); return [ 'An elephant eats ' . $kg . ' kg of food a week. How many kg will it eat in ' . $years . ' years? (Use 52 weeks in a year.)', $kg * 52 * $years, ]; } private function sandwiches() { $each = $this->num(2, 5); $children = $this->num(3, 30); return [ 'A mother makes ' . ($each * $children) . ' sandwiches for a party. Each child receives ' . $each . ' sandwiches. How many children were at the party?', $children, ]; } private function marbles() { $quarter = $this->num(5, 60); return [ 'There were ' . ($quarter * 4) . ' marbles in a jar. ' . $this->name() . ' dropped the jar and lost 3 quarters of the marbles. How many marbles were left?', $quarter, ]; } private function beach() { $fifth = $this->num(10, 200); return [ 'At the beach there were ' . ($fifth * 5) . ' people. One fifth were children and the rest were adults. How many adults were at the beach?', $fifth * 4, ]; } private function cupcakes() { $fifth = $this->num(10, 100); return [ $this->name() . ' baked ' . ($fifth * 5) . ' cupcakes and sold 2 fifths of them at the market. How many cupcakes were left?', $fifth * 3, ]; } private function sugarBags() { $perBag = $this->num(2, 20); $bags = $this->num(2, 10); return [ $this->name() . ' has to pack ' . ($perBag * $bags) . ' kg of sugar equally into ' . $bags . ' bags. How many kg of sugar will each bag contain?', $perBag, ]; } private function htmlify($problem) { // Expected answer stays on the server; the form only carries a token. $token = TkAnswerStore::issue($this->user, $problem); $frm = e107::getForm(); $fString = $frm->open('questionForm', 'post', '', ['autocomplete' => 'off', 'class' => 'formclass']); $fString .= $frm->label('

Word problems

') . "
\n"; $fString .= $frm->label('Read the problem and write just the number as your answer.') . "\n"; $fString .= '
'; $fString .= '

' . htmlspecialchars($problem['question']) . '

'; $fString .= '
'; $fString .= $frm->text('a1', '', 80, ['placeholder' => 'Write answer here!', 'autocomplete' => "off", 'spellcheck' => "false"]) . "\n"; $fString .= $frm->hidden('checkerData', $token, ['id' => 'checkerData']); $fString .= $frm->hidden('subject', self::SUBJECT, ['id' => 'subject']); $fString .= '
' . "\n"; $fString .= $frm->button('Answer', 'Check answer') . "\n"; $fString .= $frm->close(); $fString .= '

'; return $fString; } }