moodle/mod/hotpot/template/v6/hp6checkshortanswer.js_

400 lines
10 KiB
Plaintext

//CORE CODE FOR CHECKING SHORT ANSWER GUESSES AGAINST ANSWER ARRAYS
var CaseSensitive = [boolCaseSensitive];
var ShowAlsoCorrect = [boolShowAlsoCorrect];
var PleaseEnter = '[strPleaseEnter]';
var HybridTries = [intHybridTries];
var PartlyIncorrect = '[strPartlyIncorrect]';
var CorrectList = '[strCorrectList]';
var NextCorrect = '[strNextCorrect]';
var CurrBox = null;
function TrackFocus(BoxID){
InTextBox = true;
CurrBox = document.getElementById(BoxID);
}
function LeaveGap(){
InTextBox = false;
}
function TypeChars(Chars){
if (CurrBox != null){
//Following check added for 6.0.4.4 to avoid error message in IE6
if (CurrBox.style.display != 'none'){
CurrBox.value += Chars;
CurrBox.focus();
}
}
}
function CheckGuess(Guess, Answer, CaseSensitive, PercentCorrect, Feedback){
this.Guess = Guess;
this.Answer = Answer;
this.PercentCorrect = PercentCorrect;
this.Feedback = Feedback;
if (CaseSensitive == false){
this.WorkingGuess = Guess.toLowerCase();
this.WorkingAnswer = Answer.toLowerCase();
}
else{
this.WorkingGuess = Guess;
this.WorkingAnswer = Answer;
}
this.Hint = '';
this.HintPenalty = 1/Answer.length;
this.CorrectStart = '';
this.WrongMiddle = '';
this.CorrectEnd = '';
this.PercentMatch = 0;
this.DoCheck();
}
function CheckGuess_DoCheck(){
//Check if it's an exact match
if (this.WorkingAnswer == this.WorkingGuess){
this.PercentMatch = 100;
this.CorrectStart = this.Guess;
return;
}
//Figure out how much of the beginning is correct
var i = 0;
var CorrectChars = 0;
while (this.WorkingAnswer.charAt(i) == this.WorkingGuess.charAt(i)){
i++;
CorrectChars++;
}
//Stash the hint
this.Hint = this.Answer.charAt(i);
this.CorrectStart = this.Guess.substring(0, i);
//If there's more to the answer, look at the rest of it
if (i<this.Guess.length){
//Figure out how much of the end is correct
var j = this.WorkingGuess.length-1;
var k = this.WorkingAnswer.length-1;
while ((j>=i)&&((this.WorkingAnswer.charAt(k) == this.WorkingGuess.charAt(j))&&(CorrectChars < this.Answer.length))){
CorrectChars++;
j--;
k--;
}
this.CorrectEnd = this.Guess.substring(j+1, this.Guess.length);
this.WrongMiddle = this.Guess.substring(i, j+1);
}
if (TrimString(this.WrongMiddle).length < 1){this.WrongMiddle = '_';}
//Calculate match score based on how much of the guess is correct
if (CorrectChars < this.Answer.length){
this.PercentMatch = Math.floor(100*CorrectChars)/this.Answer.length;
}
else{
this.PercentMatch = Math.floor((100 * CorrectChars)/this.Guess.length);
}
}
CheckGuess.prototype.DoCheck = CheckGuess_DoCheck;
function CheckAnswerArray(CaseSensitive){
this.CaseSensitive = CaseSensitive;
this.Answers = new Array();
this.Score = 0;
this.Feedback = '';
this.Hint = '';
this.HintPenalty = 0;
this.MatchedAnswerLength = 1;
this.CompleteMatch = false;
this.MatchNum = -1;
}
function CheckAnswerArray_AddAnswer(Guess, Answer, PercentCorrect, Feedback){
this.Answers.push(new CheckGuess(Guess, Answer, this.CaseSensitive, PercentCorrect, Feedback));
}
CheckAnswerArray.prototype.AddAnswer = CheckAnswerArray_AddAnswer;
function CheckAnswerArray_ClearAll(){
this.Answers.length = 0;
}
CheckAnswerArray.prototype.ClearAll = CheckAnswerArray_ClearAll;
function CheckAnswerArray_GetBestMatch(){
//First check for a 100% match
for (var i=0; i<this.Answers.length; i++){
if (this.Answers[i].PercentMatch == 100){
this.Feedback = this.Answers[i].Feedback;
this.Score = this.Answers[i].PercentCorrect;
this.CompleteMatch = true;
this.MatchNum = i;
return;
}
}
//Now check for the best alternative match
var PercentMatch = 0;
var BestMatch = -1;
for (i=0; i<this.Answers.length; i++){
if ((this.Answers[i].PercentMatch > PercentMatch)&&(this.Answers[i].PercentCorrect == 100)){
BestMatch = i;
PercentMatch = this.Answers[i].PercentMatch;
}
}
if (BestMatch > -1){
this.Score = this.Answers[BestMatch].PercentMatch;
this.Feedback = PartlyIncorrect + ' ';
this.Feedback += '<span class="PartialAnswer">' + this.Answers[BestMatch].CorrectStart;
this.Feedback += '<span class="Highlight">' + this.Answers[BestMatch].WrongMiddle + '</span>';
this.Feedback += this.Answers[BestMatch].CorrectEnd + '</span>';
this.Hint = '<span class="PartialAnswer">' + this.Answers[BestMatch].CorrectStart;
this.Hint += '<span class="Highlight">' + this.Answers[BestMatch].Hint + '</span></span>';
this.HintPenalty = this.Answers[BestMatch].HintPenalty;
}
else{
this.Score = 0;
this.Feedback = '';
}
}
CheckAnswerArray.prototype.GetBestMatch = CheckAnswerArray_GetBestMatch;
function CheckShortAnswer(QNum){
//bail if question doesn't exist or exercise finished
if ((State[QNum].length < 1)||(Finished == true)){return;}
//bail if question already complete
if (State[QNum][0] > -1){return;}
//Get the guess (TrimString added to fix bug for 6.0.4.3)
var G = TrimString(document.getElementById('Q_' + QNum + '_Guess').value);
//If no guess, bail with message; no penalty
if (G.length < 1){
ShowMessage(PleaseEnter);
return;
}
//Increment tries
State[QNum][2]++;
//Create a check object
var CA = new CheckAnswerArray(CaseSensitive);
CA.ClearAll();
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
CA.AddAnswer(G, I[QNum][3][ANum][0], I[QNum][3][ANum][3], I[QNum][3][ANum][1]);
}
CA.GetBestMatch();
//Store any match in the state tracking field
if (CA.MatchNum > -1){
State[QNum][5] += String.fromCharCode(65+CA.MatchNum) + ',';
}
//Add the percent correct value for this answer to the Q State (works for all
//situations, wrong or right)
State[QNum][3] += CA.Score;
//Now branch, based on the nature of the match
//Is it a complete match?
if (CA.CompleteMatch == true){
//Is it with a wrong answer, or a right answer?
if (CA.Score == 100){
//It's right
CalculateShortAnsQuestionScore(QNum);
//Get correct answer list if required, assuming there are any other correct alternatives
if (ShowAlsoCorrect == true){
var AlsoCorrectList = GetCorrectList(QNum, G, false);
if (AlsoCorrectList.length > 0){
CA.Feedback += '<br />' + CorrectList + '<br />' + AlsoCorrectList;
}
}
//Get the overall score and add it to the feedback
if (ContinuousScoring == true){
CalculateOverallScore();
CA.Feedback += '<br />' + YourScoreIs + ' ' + Score + '%.';
WriteToInstructions(YourScoreIs + ' ' + Score + '%.');
}
ShowMessage(CA.Feedback);
//Put the answer in
ReplaceGuessBox(QNum, G);
CheckFinished();
return;
}
}
//Otherwise, it's a match to a predicted wrong/partially correct, or a partial
//match to a right answer
if (CA.Feedback.length < 1){CA.Feedback = DefaultWrong;}
//Remove any previous score unless exercise is finished (6.0.3.8+)
if (Finished == false){
WriteToInstructions(strInstructions);
}
ShowMessage(CA.Feedback);
//If necessary, switch a hybrid question to m/c
if (State[QNum][2] >= HybridTries){
SwitchHybridDisplay(QNum);
}
}
function CalculateShortAnsQuestionScore(QNum){
var Tries = State[QNum][2] + State[QNum][4]; //include tries and hint penalties;
var PercentCorrect = State[QNum][3];
var HintPenalties = State[QNum][4];
//Make sure it's not already complete
if (State[QNum][0] < 0){
if (HintPenalties >= 1){
State[QNum][0] = 0;
}
else{
State[QNum][0] = (PercentCorrect/(100*Tries));
}
if (State[QNum][0] < 0){
State[QNum][0] = 0;
}
}
}
function SwitchHybridDisplay(QNum){
if (document.getElementById('Q_' + QNum + '_Hybrid_MC') != null){
document.getElementById('Q_' + QNum + '_Hybrid_MC').style.display = '';
if (document.getElementById('Q_' + QNum + '_SA') != null){
document.getElementById('Q_' + QNum + '_SA').style.display = 'none';
}
}
}
function GetCorrectArray(QNum){
var Result = new Array();
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
if (I[QNum][3][ANum][2] == 1){ //This is an acceptable correct answer
Result.push(I[QNum][3][ANum][0]);
}
}
return Result;
}
function GetCorrectList(QNum, Answer, IncludeAnswer){
var As = GetCorrectArray(QNum);
var Result = '';
for (var ANum=0; ANum<As.length; ANum++){
if ((IncludeAnswer == true)||(As[ANum] != Answer)){
Result += As[ANum] + '<br />';
}
}
return Result;
}
function GetFirstCorrectAnswer(QNum){
var As = GetCorrectArray(QNum);
if (As.length > 0){
return As[0];
}
else{
return '';
}
}
function ReplaceGuessBox(QNum, Ans){
if (document.getElementById('Q_' + QNum + '_SA') != null){
var El = document.getElementById('Q_' + QNum + '_SA');
while (El.childNodes.length > 0){
El.removeChild(El.childNodes[0]);
}
var A = document.createElement('span');
A.setAttribute('class', 'Answer');
var T = document.createTextNode(Ans);
A.appendChild(T);
El.appendChild(A);
}
}
[inclShowAnswer]
function ShowAnswers(QNum){
//bail if question doesn't exist or exercise finished
if ((State[QNum].length < 1)||(Finished == true)){return;}
//Get the answer list to display
var Ans = GetCorrectList(QNum, '', false);
Ans = CorrectList + '<br />' + Ans;
//Display feedback
ShowMessage(Ans);
//Set the score for this question to 0 if no
if (State[QNum][0] < 1){
State[QNum][0] = 0;
}
//Get the first correct answer
var FirstAns = GetFirstCorrectAnswer(QNum);
//Replace the textbox
ReplaceGuessBox(QNum, FirstAns);
//Remove any current score
WriteToInstructions(strInstructions);
//This may be the last, so check finished status
CheckFinished();
}
[/inclShowAnswer]
[inclHint]
function ShowHint(QNum){
//bail if question doesn't exist or exercise finished
if ((State[QNum].length < 1)||(Finished == true)){return;}
//bail if question already complete
if (State[QNum][0] > -1){return;}
//Get the guess
var G = document.getElementById('Q_' + QNum + '_Guess').value;
//If no guess, give the first correct bit
if (G.length < 1){
var Ans = GetFirstCorrectAnswer(QNum);
var Hint = Ans.charAt(0);
ShowMessage(NextCorrect + '<br />' + Hint);
//Penalty for hint
State[QNum][4] += (1/Ans.length);
return;
}
//Increment tries
State[QNum][2]++;
//Create a check object
var CA = new CheckAnswerArray(CaseSensitive);
CA.ClearAll();
for (var ANum=0; ANum<I[QNum][3].length; ANum++){
//Use only correct answers
if (I[QNum][3][ANum][2] == 1){
CA.AddAnswer(G, I[QNum][3][ANum][0], I[QNum][3][ANum][3], I[QNum][3][ANum][1]);
}
}
CA.GetBestMatch();
if (CA.CompleteMatch == true){
//It's right!
CheckShortAnswer(QNum);
return;
}
else{
if (CA.Hint.length > 0){
ShowMessage(NextCorrect + '<br />' + CA.Hint);
State[QNum][4] += CA.HintPenalty;
}
else{
ShowMessage(DefaultWrong + '<br />' + NextCorrect + '<br />' + GetFirstCorrectAnswer(QNum).charAt(0));
}
}
}
[/inclHint]