['Find the missing number. {QUESTION}', "Congratulations '{USER_ANSWER}' was correct for Find the missing number '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Find the missing number in {QUESTION}'"], 'addition' => ['Solve the following equation. {QUESTION}.', "Congratulations '{USER_ANSWER}' was correct for Solve the following equation. '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Solve the following equation in {QUESTION}'"], 'subtraction' => ['Solve the following equation. {QUESTION}.', "Congratulations '{USER_ANSWER}' was correct for Solve the following equation. '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Solve the following equation in {QUESTION}'"], 'multiplication' => ['Solve the following equation. {QUESTION}.', "Congratulations '{USER_ANSWER}' was correct for Solve the following equation. '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Solve the following equation in {QUESTION}'"], 'division' => ['Solve the following equation. {QUESTION}.', "Congratulations '{USER_ANSWER}' was correct for Solve the following equation. '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Solve the following equation in {QUESTION}'"], 'rounding' => [], 'worded_add' => [], 'worded_sub' => [], 'worded_mult' => [], 'worded_devi' => [], 'anagrams' => ['Unjumble the letters to find the word. {QUESTION}.', "Congratulations '{USER_ANSWER}' was correct for Unjumble the letters '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Unjumble the letters in {QUESTION}'"], 'generalKnowledge' => [], 'elements' => ['Fill in the missing element information. {QUESTION}', "Congratulations '{USER_ANSWER}' was correct for Fill in the missing element information '{ANSWER}'", "Sorry but '{USER_ANSWER}' was incorrect it should have been '{ANSWER}' for 'Fill in the missing element information in {QUESTION}'"], 'continents' => [], 'countries' => [], 'flags' => [], 'capitalCities' => [], 'artists' => [], 'malaySpelling' => [], 'nameBodyParts' => [], 'nameBodyOrgans' => [], 'basicFirstAid' => [] ]; /** * Get the right answer checker for the subject */ public function checkQuestionSubject($subject, $user) { $this->user = $user; switch ($subject) { case 'numbers': case 'addition': case 'subtraction': case 'multiplication': case 'division': $this->checkGeneric($subject); break; case 'worded_add': case 'worded_sub': case 'worded_mult': case 'worded_devi': case 'spelling': $this->checkSpelling(); //Custom checker break; case 'anagrams': $this->checkAnagrams(); break; case 'generalKnowledge': case 'elements': $this->checkGeneric('elements'); break; case 'continents': case 'countries': case 'flags': case 'capitalCities': case 'artists': case 'malaySpelling': case 'nameBodyParts': case 'nameBodyOrgans': case 'basicFirstAid': default: print_a('An error has been detected in the answer checker. Please report this and refresh the page.'); break; } } /** * Check the answer for anything basic */ private function checkGeneric($subject) { $usersAnswer = (string) filter_input(INPUT_POST, 'a1'); $answer = $this->loadPending(); if ($answer === null) { return; } if (is_array($answer['question'])) { $answer['question'] = implode('', $answer['question']); } if (trim($usersAnswer) === trim((string) $answer['answer1'])) { $text = str_replace(['{ANSWER}', '{USER_ANSWER}'], [$answer['answer1'], trim($usersAnswer)], $this->messages[$subject][1]) . "
"; $this->updateScore(true); } else { $text = str_replace(['{ANSWER}', '{USER_ANSWER}', '{QUESTION}'], [$answer['answer1'], trim($usersAnswer), $answer['question']], $this->messages[$subject][2]) . "
"; $this->updateScore(false); } $this->addToReport($answer['answer1'], $usersAnswer, $subject, str_replace('{ANSWER}', $answer['answer1'], str_replace('{QUESTION}', $answer['question'], $this->messages[$subject][0])),$this->isCorrect($answer['answer1'], $usersAnswer)); e107::getRender()->tablerender(ucfirst($subject) . ' answer check', $text); } /** * Check the answer for anything basic */ private function checkAnagrams() { $usersAnswer = (string) filter_input(INPUT_POST, 'a1'); $answer = $this->loadPending(); if ($answer === null) { return; } if (is_array($answer['question'])) { $answer['question'] = implode('', $answer['question']); } $words = e107::getDb()->retrieve('tk_wordList', 'word'); if (trim($usersAnswer) === trim((string) $answer['answer1']) || $this->findInList($words, $usersAnswer)) { $text = str_replace(['{ANSWER}', '{USER_ANSWER}'], [$answer['answer1'], trim($usersAnswer)], $this->messages['anagrams'][1]) . "
"; $this->updateScore(true); } else { $text = str_replace(['{ANSWER}', '{USER_ANSWER}', '{QUESTION}'], [$answer['answer1'], trim($usersAnswer), $answer['question']], $this->messages['anagrams'][2]) . "
"; $this->updateScore(false); } $this->addToReport($answer['answer1'], $usersAnswer, 'anagrams', str_replace('{ANSWER}', $answer['answer1'], str_replace('{QUESTION}', $answer['question'], $this->messages['anagrams'][0])),$this->isCorrect($answer['answer1'], $usersAnswer)); e107::getRender()->tablerender(ucfirst('anagrams') . ' answer check', $text); } private function findInList($list, $needle) { foreach ($list as $listItem) { if ($listItem == $needle) { return true; } } return false; } /** * Check the answer for spelling */ private function checkSpelling() { $usersAnswer = (string) filter_input(INPUT_POST, 'a1'); $answer = $this->loadPending(); if ($answer === null) { return; } if (trim($usersAnswer) === trim((string) $answer['word'])) { $text = "Congratulations '" . trim($usersAnswer) . "' was correct for 'spell the word " . $answer['word'] . "'
"; $this->updateScore(true); //file_put_contents('debug_Spelling_data.txt','<->'.$answer['word'].'<->'.$usersAnswer.'<->True'."\n",FILE_APPEND);//================================= } else { $text = "Sorry but '" . trim($usersAnswer) . "' was incorrect it should have been '" . trim($answer['word']) . "' for 'spell the word " . $answer['word'] . "'
"; $this->updateScore(false); //file_put_contents('debug_Spelling_data.txt','<->'.$answer['word'].'<->'.$usersAnswer.'<->False'."\n",FILE_APPEND);//================================= } $this->addToReport($answer['word'], $usersAnswer, 'spelling', "Spell the word " . $answer['word'],$this->isCorrect($answer['word'], $usersAnswer)); e107::getRender()->tablerender('Spelling answer check', $text); } /** * Add or minus the score */ private function updateScore($scorePoint) { $currentScore = e107::getDb()->retrieve('timekeeperScore', 'timekeeper_lifetimecorrect, timekeeper_lifetimequestions, timekeeper_minutes', 'timekeeper_username="' . $this->user . '"'); if ($scorePoint) { $currentScore['timekeeper_lifetimecorrect']++; $currentScore['timekeeper_minutes'] = $currentScore['timekeeper_minutes'] + $this->scaleTimeAddition(); } else { $currentScore['timekeeper_minutes']--; } $currentScore['timekeeper_lifetimequestions']++; if ($currentScore['timekeeper_lifetimequestions'] == 1) { $currentScore['timekeeper_lastquestiondatestamp'] = time(); $currentScore['timekeeper_yearlevel'] = 0; $currentScore['timekeeper_username'] = $this->user; e107::getDb()->insert('timekeeperScore', $currentScore); } else { $currentScore['WHERE'] = 'timekeeper_username="' . $this->user . '"'; e107::getDb()->update('timekeeperScore', $currentScore); } } /** * Return how many minutes play time to award scaled by difficulty */ private function scaleTimeAddition() { //TODO look at this and fix it. $difficulty = $this->getDifficulty($this->user); //replace with db call $maxDifficulty = 5000000; // 5 mil is max here //$returnMinutes = 10 - ($difficulty / $maxDifficulty * 100) / 10; $returnMinutes = (int) $difficulty / 10; //print_a(['diffi'=>$difficulty,'fprint'=> round($difficulty),'retmins'=>round($returnMinutes)]); $returnMinutes = round($returnMinutes); if ($returnMinutes <= 1) { $returnMinutes = 1; } return round($returnMinutes); } /** * Return users overall difficulty. */ private function getDifficulty($user) { $returnArray = []; //$returnArray['totalQuestionCount'] = e107::getDb()->count("tkReport", "(id)", "username = '" . $user . "'"); e107::getDb()->gen("SELECT COUNT(id) as cntr, CAST((SUM(correct)/COUNT(id)*100) as DECIMAL(5,2)) as percent FROM e107.`e107_tkReport` WHERE username = '" . $user . "' AND answereddatestamp >= unix_timestamp(CURRENT_DATE() - INTERVAL 1 MONTH) AND answereddatestamp <= unix_timestamp(CURRENT_DATE() + INTERVAL 1 DAY)"); while ($row = e107::getDb()->fetch()) { $returnArray = array_merge($returnArray, $row); } return $returnArray['percent']; //($returnArray['totalQuestionCount']*$returnArray['percent']); } /** * Add the last answered question to the report DB table. */ private function addToReport($answer, $usersAnswer, $subject, $questionString, $isCorrect) { if ($isCorrect) { $correct = 1; } else { $correct = 0; } $insert = [ 'username' => $this->user, 'question' => $questionString, 'answereddatestamp' => time(), 'userAnswer' => trim($usersAnswer), 'answer' => trim($answer), 'subject' => $subject, 'correct' => $correct ]; e107::getDb()->insert('tkReport', $insert); } /** * ShortCode engine */ private function shortCode($keys, $message) { $returnMessage = $message; foreach ($keys as $key => $value) { $returnMessage = $str; } } private function loadPending(): ?array { $token = filter_input(INPUT_POST, 'checkerData'); $answer = TkAnswerStore::consume($this->user, is_string($token) ? $token : null); if ($answer === null) { e107::getRender()->tablerender('Answer check', 'That question has expired or was already answered. Please answer the new question.'); } return $answer; } private function isCorrect($expected, $given): bool { $expected = trim((string) $expected); $given = trim((string) $given); if (is_numeric($expected) && is_numeric($given)) { return abs((float) $expected - (float) $given) < 1e-9; } return mb_strtolower($expected) === mb_strtolower($given); } }