| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- <?php
- /**
- * "Find the missing number" sequence generator.
- *
- * Changes from the current repo version:
- * - difficulty() returned the int 1 for a new user and the code then indexed
- * it like an array (null values, notices on PHP 7.4+/8); it always returns
- * ['percent' => .., 'count' => ..] now
- * - user escaped in SQL; the hard-coded `e107.` database name replaced by
- * MPREFIX
- * - the previous tkLastQuestion row is removed before inserting the new one
- * (each question used to add another row)
- * - the token from TkAnswerStore::issue() is built once, before the form
- * - leftover commented-out debug line removed
- */
- class numbers2 {
- private $user;
- /**
- * Setup new numbers engine
- *
- * @param string $user User to supply the question for.
- */
- public function __construct($user) {
- $this->user = $user;
- }
- public function getNumbers() {
- $difficulty = $this->difficulty();
- $question = $this->getSequence($difficulty);
- $questionHtml = $this->htmlify($question);
- $db = e107::getDb();
- $db->delete('tkLastQuestion', "user = '" . $db->escape($this->user) . "'");
- $db->insert('tkLastQuestion', ['user' => $this->user, 'LastQuestionHtml' => base64_encode($questionHtml)]);
- e107::getRender()->tablerender('Numbers', $questionHtml);
- }
- /**
- * Difficulty based on the last month of answers.
- *
- * @return array ['percent' => float 0-100, 'count' => int]
- */
- 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 = 'numbers'"
- );
- if (!is_array($stats) || (int) $stats['count'] === 0) {
- return ['percent' => 0, 'count' => 0];
- }
- return ['percent' => (float) $stats['percent'], 'count' => (int) $stats['count']];
- }
- private function getSequence($difficulty) {
- $count = (int) $difficulty['count'];
- $percent = (float) $difficulty['percent'];
- $startingNumber = mt_rand(0, (int) pow($count, ($percent / 100) * 2));
- if ($count >= 300) {
- $incrementalNumber = mt_rand(1, 100);
- } elseif ($count >= 200) {
- $incrementalNumber = mt_rand(1, 10);
- } elseif ($count >= 100) {
- $incrementalNumber = mt_rand(1, 5);
- } else {
- $incrementalNumber = mt_rand(1, 2);
- }
- $missingNumber = mt_rand(1, 10);
- $TempQuestion = [];
- for ($i = 1; $i <= 10; $i++) {
- if ($i == $missingNumber) {
- $TempQuestion[] = "___,";
- $solution = round($startingNumber);
- } elseif ($i == 10) {
- $TempQuestion[] = round($startingNumber);
- } else {
- $TempQuestion[] = round($startingNumber) . ",";
- }
- if ($percent >= 90 && $count >= 200) {
- $startingNumber += round((2 * $incrementalNumber) / $i);
- } elseif ($percent >= 80 && $count >= 100) {
- $startingNumber += $incrementalNumber * ($i * 15);
- } else {
- $startingNumber += $incrementalNumber;
- }
- }
- return ['answer1' => $solution, 'question' => $TempQuestion, 'type' => 'numbers'];
- }
- private function htmlify($question) {
- // Expected answer stays on the server; the form only carries a token.
- $token = TkAnswerStore::issue($this->user, $question);
- $frm = e107::getForm();
- $fString = $frm->open('questionForm', 'post', '', ['autocomplete' => 'off', 'class' => 'formclass']);
- $fString .= $frm->label('<h4>Numbers</h4>') . "</br>\n";
- $fString .= $frm->label('Find the missing number.') . "\n";
- $fString .= '</br>';
- foreach ($question['question'] as $seq) {
- $fString .= $frm->label($seq . " ") . "\n";
- }
- $fString .= '</br></br>';
- $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', 'numbers', ['id' => 'subject']);
- $fString .= '</br>' . "\n";
- $fString .= $frm->button('Answer', 'Check answer') . "\n";
- $fString .= $frm->close();
- $fString .= '</br></br>';
- return $fString;
- }
- }
|