numbers2.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. /**
  3. * "Find the missing number" sequence generator.
  4. *
  5. * Changes from the current repo version:
  6. * - difficulty() returned the int 1 for a new user and the code then indexed
  7. * it like an array (null values, notices on PHP 7.4+/8); it always returns
  8. * ['percent' => .., 'count' => ..] now
  9. * - user escaped in SQL; the hard-coded `e107.` database name replaced by
  10. * MPREFIX
  11. * - the previous tkLastQuestion row is removed before inserting the new one
  12. * (each question used to add another row)
  13. * - the token from TkAnswerStore::issue() is built once, before the form
  14. * - leftover commented-out debug line removed
  15. */
  16. class numbers2 {
  17. private $user;
  18. /**
  19. * Setup new numbers engine
  20. *
  21. * @param string $user User to supply the question for.
  22. */
  23. public function __construct($user) {
  24. $this->user = $user;
  25. }
  26. public function getNumbers() {
  27. $difficulty = $this->difficulty();
  28. $question = $this->getSequence($difficulty);
  29. $questionHtml = $this->htmlify($question);
  30. $db = e107::getDb();
  31. $db->delete('tkLastQuestion', "user = '" . $db->escape($this->user) . "'");
  32. $db->insert('tkLastQuestion', ['user' => $this->user, 'LastQuestionHtml' => base64_encode($questionHtml)]);
  33. e107::getRender()->tablerender('Numbers', $questionHtml);
  34. }
  35. /**
  36. * Difficulty based on the last month of answers.
  37. *
  38. * @return array ['percent' => float 0-100, 'count' => int]
  39. */
  40. private function difficulty() {
  41. $db = e107::getDb();
  42. $stats = $db->retrieve(
  43. "SELECT (SUM(correct)/COUNT(correct)*100) AS percent, COUNT(correct) AS count
  44. FROM `" . MPREFIX . "tkReport`
  45. WHERE answereddatestamp >= UNIX_TIMESTAMP(NOW() - INTERVAL 1 MONTH)
  46. AND username = '" . $db->escape($this->user) . "' AND subject = 'numbers'"
  47. );
  48. if (!is_array($stats) || (int) $stats['count'] === 0) {
  49. return ['percent' => 0, 'count' => 0];
  50. }
  51. return ['percent' => (float) $stats['percent'], 'count' => (int) $stats['count']];
  52. }
  53. private function getSequence($difficulty) {
  54. $count = (int) $difficulty['count'];
  55. $percent = (float) $difficulty['percent'];
  56. $startingNumber = mt_rand(0, (int) pow($count, ($percent / 100) * 2));
  57. if ($count >= 300) {
  58. $incrementalNumber = mt_rand(1, 100);
  59. } elseif ($count >= 200) {
  60. $incrementalNumber = mt_rand(1, 10);
  61. } elseif ($count >= 100) {
  62. $incrementalNumber = mt_rand(1, 5);
  63. } else {
  64. $incrementalNumber = mt_rand(1, 2);
  65. }
  66. $missingNumber = mt_rand(1, 10);
  67. $TempQuestion = [];
  68. for ($i = 1; $i <= 10; $i++) {
  69. if ($i == $missingNumber) {
  70. $TempQuestion[] = "___,";
  71. $solution = round($startingNumber);
  72. } elseif ($i == 10) {
  73. $TempQuestion[] = round($startingNumber);
  74. } else {
  75. $TempQuestion[] = round($startingNumber) . ",";
  76. }
  77. if ($percent >= 90 && $count >= 200) {
  78. $startingNumber += round((2 * $incrementalNumber) / $i);
  79. } elseif ($percent >= 80 && $count >= 100) {
  80. $startingNumber += $incrementalNumber * ($i * 15);
  81. } else {
  82. $startingNumber += $incrementalNumber;
  83. }
  84. }
  85. return ['answer1' => $solution, 'question' => $TempQuestion, 'type' => 'numbers'];
  86. }
  87. private function htmlify($question) {
  88. // Expected answer stays on the server; the form only carries a token.
  89. $token = TkAnswerStore::issue($this->user, $question);
  90. $frm = e107::getForm();
  91. $fString = $frm->open('questionForm', 'post', '', ['autocomplete' => 'off', 'class' => 'formclass']);
  92. $fString .= $frm->label('<h4>Numbers</h4>') . "</br>\n";
  93. $fString .= $frm->label('Find the missing number.') . "\n";
  94. $fString .= '</br>';
  95. foreach ($question['question'] as $seq) {
  96. $fString .= $frm->label($seq . " &nbsp; ") . "\n";
  97. }
  98. $fString .= '</br></br>';
  99. $fString .= $frm->text('a1', '', 80, ['placeholder' => 'Write answer here!', 'autocomplete' => "off", 'spellcheck' => "false"]) . "\n";
  100. $fString .= $frm->hidden('checkerData', $token, ['id' => 'checkerData']);
  101. $fString .= $frm->hidden('subject', 'numbers', ['id' => 'subject']);
  102. $fString .= '</br>' . "\n";
  103. $fString .= $frm->button('Answer', 'Check answer') . "\n";
  104. $fString .= $frm->close();
  105. $fString .= '</br></br>';
  106. return $fString;
  107. }
  108. }