Esempio n. 1
0
 /**
  * Selects the next question base appropriate for the quiz attempt passed
  * @param Model_Quiz_QuizAttempt $vQuizAttempt
  * @param boolean $debug Being Phased out TODO
  * @throws Exception
  * @return Model_Quiz_QuestionBase|NULL NULL Should only be returned in exceptional circumstances
  */
 public static function select_next_question($vQuizAttempt, $debug = false)
 {
     //Get all the concepts this quiz tests
     $vQuiz = $vQuizAttempt->getQuiz();
     $vTestedConcepts = $vQuiz->getTestedConcepts();
     if (sizeof($vTestedConcepts) < 1) {
         throw new Exception("This quiz is not ready yet - reason: No testedConcepts specified.");
     }
     //Foreach concept tested, see how many questions we've attempted
     foreach ($vTestedConcepts as $vTestedConcept) {
         Model_Shell_Debug::getInstance()->log("Looking at TestedConcept: " . $vTestedConcept->getConcept()->getConcept_name());
         $vQuestionAttempts = Model_Quiz_QuestionAttempt::getAllFromQuizAttemptAndConcept($vQuizAttempt, $vTestedConcept->getConcept());
         Model_Shell_Debug::getInstance()->log("Done " . sizeof($vQuestionAttempts) . "/" . $vTestedConcept->getNumber_tested());
         //If we haven't attempted enough in this concept, we need to choose a question difficulty
         if (sizeof($vQuestionAttempts) < $vTestedConcept->getNumber_tested()) {
             //What difficulties are there being tested within this concept?
             $vLowest = $vTestedConcept->getLower_difficulty();
             $vHighest = $vTestedConcept->getHigher_difficulty();
             //Find out how many questions I should allocate for each difficulty
             $mQuestionsPerDifficultyLevel = floor(0.8 / ($vHighest + 1 - $vLowest) * $vTestedConcept->getNumber_tested());
             $mBuffer = $vTestedConcept->getNumber_tested() - ($vHighest + 1 - $vLowest) * $mQuestionsPerDifficultyLevel;
             //If there's only one difficulty, that settles that
             if ($vLowest == $vHighest) {
                 return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vLowest);
             }
             //Were there any previous attempts at this concept? If not, we need to start a Q at the lowest specified difficulty
             $vQuestionAttempts = $vQuizAttempt->getQuestionAttempts($vTestedConcept->getConcept());
             //echo "Size of vQuestionAttempts:".sizeof($vQuestionAttempts)."<br/>";
             if (sizeof($vQuestionAttempts) == 0) {
                 return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vLowest);
             }
             //Find the highest attempted difficulty done so far
             $vHighestSoFar = $vQuizAttempt->getHighestDifficultyTestedSoFar();
             //echo "The highest difficulty so far: $vHighestSoFar<br/>";
             if ($vHighestSoFar >= $vHighest) {
                 //Already at the highest difficulty, the next question will be at this difficulty too
                 return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vHighest);
             }
             //Look at the last attempts in this difficulty. Were they below-par (use a percentage?)?
             $vTotal = 0;
             $vTotalRight = 0;
             Model_Shell_Debug::getInstance()->log("Checking your previous attempts...Size of vQuestionAttempts:" . sizeof($vQuestionAttempts));
             foreach ($vQuestionAttempts as $vQA) {
                 $vQB = $vQA->getQuestion_base();
                 //echo "Looking at " . $vQB->getDifficulty() . " vs $vHighestSoFar<br/>";
                 if ($vQB->getDifficulty() == $vHighestSoFar) {
                     $vTotal++;
                     if ($vQB->getEstimated_time() > $vQA->getTime_finished() - $vQA->getTime_started()) {
                         //You did this question in a reasonable time... did you get it right first time?
                         if ($vQA->getInitial_result() == "1") {
                             $vTotalRight++;
                         }
                     }
                 }
             }
             //Note, a divide by 0 happened here before...
             if ($vTotal == 0 || $vTotalRight / $vTotal > 0.8) {
                 //OK. If they WERE good attempts, I should move on if I've hit my quota for this difficulty
                 if ($vTotal >= $mQuestionsPerDifficultyLevel) {
                     //Reached our minumum quota for this difficulty level. NEXT!
                     return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vHighestSoFar + 1);
                 } else {
                     //We've done well so far, but we need to do more in this difficulty
                     return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vHighestSoFar);
                 }
             } else {
                 //Your previous attempts weren't all that good.
                 //Figure out how much buffer we have left. Can we afford to give you a question at $vHighestSoFar? Or do we have to move onto something harder?
                 $mBuffer = $vTestedConcept->getNumber_tested() - ($vHighest - $vHighestSoFar) * $mQuestionsPerDifficultyLevel - sizeof($vQuestionAttempts);
                 if ($mBuffer > 1) {
                     //We can afford to give you another easier question
                     return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vHighestSoFar);
                 } else {
                     //Sorry.. buffer is dry. You weren't going too well, but you gotta do the harder stuff
                     return Model_Shell_QuestionChooser::select_next_question_2($vQuizAttempt, $vTestedConcept->getConcept(), $vHighestSoFar + 1);
                 }
             }
         }
         //End If
     }
     //End Foreach testedConcept
     //We shouldn't really ever get here, but in case we do -> null
     return null;
 }