Ver código fonte

Make answer checker messages more fun.

Gregory Huxley 1 semana atrás
pai
commit
faf7c632fa
1 arquivos alterados com 127 adições e 17 exclusões
  1. 127 17
      answerChecker2.php

+ 127 - 17
answerChecker2.php

@@ -19,6 +19,9 @@
  *  - getDifficulty(): MPREFIX instead of `e107.`, user escaped, no null result
  *  - removed the broken, unused shortCode() and findInList()
  *  - a wrong answer takes a minute off but never below zero
+ *  - a correct answer gets a friendlier, randomised message: a cheer, the answer
+ *    worked out, the play minutes earned, and a streak of correct answers (the
+ *    old "Congratulations" strings at messages[...][1] are no longer used)
  */
 class answerChecker2 {
 
@@ -136,18 +139,20 @@ class answerChecker2 {
         $word = (string) $answer['word'];
         $correct = $this->isCorrect($word, $usersAnswer);
 
-        $safeAnswer = htmlspecialchars($usersAnswer);
-        $safeWord = htmlspecialchars($word);
+        $minutes = $this->updateScore($correct);
+        $this->addToReport($word, $usersAnswer, 'spelling', "Spell the word " . $word, $correct);
 
         if ($correct) {
-            $text = "Congratulations '" . $safeAnswer . "' was correct for 'spell the word " . $safeWord . "'<br/>";
+            $text = $this->correctText('spelling', $word, $usersAnswer, $word, $minutes);
+            $title = 'Correct!';
         } else {
+            $safeAnswer = htmlspecialchars($usersAnswer);
+            $safeWord = htmlspecialchars($word);
             $text = "Sorry but '" . $safeAnswer . "' was incorrect it should have been '" . $safeWord . "' for 'spell the word " . $safeWord . "'<br/>";
+            $title = 'Spelling answer check';
         }
-        $this->updateScore($correct);
 
-        $this->addToReport($word, $usersAnswer, 'spelling', "Spell the word " . $word, $correct);
-        e107::getRender()->tablerender('Spelling answer check', $text);
+        e107::getRender()->tablerender($title, $text);
     }
 
     /**
@@ -159,19 +164,118 @@ class answerChecker2 {
         $expected = (string) $expected;
         $messages = $this->messages[$subject];
 
-        $safe = [
-            '{ANSWER}'      => htmlspecialchars($expected),
-            '{USER_ANSWER}' => htmlspecialchars($usersAnswer),
-            '{QUESTION}'    => htmlspecialchars($question),
-        ];
-
-        $text = strtr($correct ? $messages[1] : $messages[2], $safe) . "<br/>";
-        $this->updateScore($correct);
+        $minutes = $this->updateScore($correct);
 
         $questionString = strtr($messages[0], ['{ANSWER}' => $expected, '{QUESTION}' => $question]);
         $this->addToReport($expected, $usersAnswer, $subject, $questionString, $correct);
 
-        e107::getRender()->tablerender(ucfirst($subject) . ' answer check', $text);
+        if ($correct) {
+            $text = $this->correctText($subject, $expected, $usersAnswer, $question, $minutes);
+            $title = 'Correct!';
+        } else {
+            $safe = [
+                '{ANSWER}'      => htmlspecialchars($expected),
+                '{USER_ANSWER}' => htmlspecialchars($usersAnswer),
+                '{QUESTION}'    => htmlspecialchars($question),
+            ];
+            $text = strtr($messages[2], $safe) . "<br/>";
+            $title = ucfirst($subject) . ' answer check';
+        }
+
+        e107::getRender()->tablerender($title, $text);
+    }
+
+    private $cheers = [
+        "🎉 Woohoo! You got it!",
+        "⭐ Brilliant!",
+        "🚀 Boom! Nailed it!",
+        "💪 Spot on!",
+        "🙌 High five! That's right!",
+        "🧠 Big brain move!",
+        "🌟 You're a star!",
+        "😎 Too easy for you!",
+        "🏆 Champion answer!",
+        "✨ Yes! Exactly right!",
+        "🎯 Bullseye!",
+        "🦄 Magical! Correct!",
+    ];
+
+    /**
+     * The message for a correct answer: a cheer, the answer, minutes earned,
+     * and a streak when there is one. Everything typed by the student is escaped.
+     */
+    private function correctText($subject, $expected, $usersAnswer, $question, $minutes) {
+        $text = '<div style="font-size:160%;font-weight:bold;">' . $this->cheers[array_rand($this->cheers)] . '</div>';
+        $text .= '<p>' . $this->correctDetail($subject, $expected, $usersAnswer, $question) . '</p>';
+
+        if ($minutes > 0) {
+            $text .= '<p>🎮 <b>+' . (int) $minutes . ((int) $minutes === 1 ? ' minute' : ' minutes') . '</b> of play time earned!</p>';
+        }
+
+        $streak = $this->correctStreak();
+        if ($streak >= 25) {
+            $text .= '<p>🚀 25 or more correct in a row. Unstoppable!</p>';
+        } elseif ($streak >= 10) {
+            $text .= '<p>🚀 ' . $streak . ' correct in a row. Unstoppable!</p>';
+        } elseif ($streak >= 5) {
+            $text .= '<p>🔥 ' . $streak . ' correct in a row. You\'re on fire!</p>';
+        } elseif ($streak >= 3) {
+            $text .= '<p>🔥 ' . $streak . ' correct in a row!</p>';
+        }
+
+        return $text;
+    }
+
+    /**
+     * The line that says what the right answer was, for this kind of question.
+     */
+    private function correctDetail($subject, $expected, $usersAnswer, $question) {
+        $e = htmlspecialchars($expected);
+
+        switch ($subject) {
+            case 'numbers':
+                return 'The missing number was <b>' . $e . '</b>.';
+            case 'addition':
+            case 'subtraction':
+            case 'multiplication':
+            case 'division':
+                $sum = strtr($question, ['x' => ' × ', '/' => ' ÷ ', '+' => ' + ', '-' => ' − ']);
+                return '<b>' . htmlspecialchars($sum) . ' = ' . $e . '</b>';
+            case 'rounding':
+                return '<b>' . htmlspecialchars($question) . '</b> rounds to <b>' . $e . '</b> (the nearest 5 cents).';
+            case 'anagrams':
+                if (mb_strtolower(trim($usersAnswer)) !== mb_strtolower($expected)) {
+                    return 'You found <b>' . htmlspecialchars($usersAnswer) . '</b>. I was thinking of <b>' . $e . '</b>, but that is a real word too!';
+                }
+                return 'You unjumbled it: <b>' . $e . '</b>!';
+            case 'spelling':
+                return 'You spelled <b>' . $e . '</b> perfectly!';
+            default:
+                return '<b>' . $e . '</b> was exactly right.';
+        }
+    }
+
+    /**
+     * How many of the student's latest answers in a row were correct (up to 25).
+     * Called after the current answer has been written to the report.
+     */
+    private function correctStreak() {
+        $db = e107::getDb();
+        $db->gen("SELECT `correct` FROM `" . MPREFIX . "tkReport` WHERE `username` = '" . $db->escape($this->user) . "' ORDER BY `id` DESC LIMIT 25");
+
+        $recent = [];
+        while ($row = $db->fetch()) {
+            $recent[] = (int) $row['correct'];
+        }
+
+        $streak = 0;
+        foreach ($recent as $correct) {
+            if ($correct !== 1) {
+                break;
+            }
+            $streak++;
+        }
+        return $streak;
     }
 
     /**
@@ -228,7 +332,9 @@ class answerChecker2 {
     }
 
     /**
-     * Add or minus the score
+     * Add or minus the score.
+     *
+     * @return int The play minutes awarded for a correct answer (0 otherwise).
      */
     private function updateScore($scorePoint) {
         $db = e107::getDb();
@@ -241,9 +347,11 @@ class answerChecker2 {
             $currentScore = ['timekeeper_lifetimecorrect' => 0, 'timekeeper_lifetimequestions' => 0, 'timekeeper_minutes' => 0];
         }
 
+        $awarded = 0;
         if ($scorePoint) {
             $currentScore['timekeeper_lifetimecorrect']++;
-            $currentScore['timekeeper_minutes'] = $currentScore['timekeeper_minutes'] + $this->scaleTimeAddition();
+            $awarded = (int) $this->scaleTimeAddition();
+            $currentScore['timekeeper_minutes'] = $currentScore['timekeeper_minutes'] + $awarded;
         } else {
             // Never below zero: the column is signed now, and a negative balance would
             // otherwise have to be earned back before any play time counts.
@@ -260,6 +368,8 @@ class answerChecker2 {
             $currentScore['WHERE'] = 'timekeeper_username="' . $user . '"';
             $db->update('timekeeperScore', $currentScore);
         }
+
+        return $awarded;
     }
 
     /**