patternjavascriptMinor
Calculating quiz score, with weights and partial credit
Viewed 0 times
withcreditweightsquizscorecalculatingpartialand
Problem
There is a quiz-game with simple rules. You have to guess one of three options. Each option has a particular weight, for example:
If player guesses the right option, he gets all amount of points. If not, he gets a part of those points:
You can easilly write a method to calculate score:
It works, but it looks horrible. How do I get rid of all this
- Option 1: 20 points
- Option 2: 30 points
- Option 3: 50 points
If player guesses the right option, he gets all amount of points. If not, he gets a part of those points:
User choice || Right Answer || Score
1 1 100%
2 1 75%
3 1 50%
1 2 75%
2 2 100%
3 2 75%
1 3 25%
2 3 50%
3 3 100%You can easilly write a method to calculate score:
calcRateScore: function(fact, user) {
var rateScore = 0;
switch (fact) {
case 1:
switch (user) {
case 1:
rateScore = 20;
break;
case 2:
rateScore = 20 * 0.75;
break;
case 3:
rateScore = 20 * 0.5;
break;
}
break;
case 2:
switch (user) {
case 1:
rateScore = 30 * 0.75;
break;
case 2:
rateScore = 30;
break;
case 3:
rateScore = 30 * 0.75;
break;
}
break;
case 3:
switch (user) {
case 1:
rateScore = 50 * 0.25;
break;
case 2:
rateScore = 50 * 0.5;
break;
case 3:
rateScore = 50;
break;
}
break;
}
return rateScore;
}It works, but it looks horrible. How do I get rid of all this
switch statementSolution
You don't seem to have any concept of objects or other reusable code in what you have written. I would take a step back and think about what real-word objects you are trying to model. At a minimum, I would think you would need three different concepts:
Let me start by modeling the objects noted above:
You now have the basic building blocks to create your quiz. You could include this code anywhere and have a reusable quiz.
Now you need to build the quiz itself. That may look like this:
Finally, we can start working with the quiz to set answers and get scores.
Note that the outcome here is very reusable code that could be pretty much dropped anywhere within a larger application to implement your quiz. In a real application you may also add something like a quiz rendering class to be able to render the quiz using javascript (and to separate display of quiz from core quiz objects).
It also makes
- Answer Option: a single answer option that will be related to the question and hold logic on it fractional value as an answer.
- Question: which stores a related set of answers and provides logic on calculating score for the question.
- Quiz: which represents an ordered collection of questions.
Let me start by modeling the objects noted above:
// let's build a question class
function Question(text, baseScore) {
this.text = null;
this.answerOptions = [];
this.selectedAnswerIndex = null;
this.baseScore = null;
this.setText(text);
this.setBaseScore(baseScore);
}
// add methods to question class
Question.prototype = {
setText: function(text) {
this.text = text;
// return the question object to allow for chaining
return this;
},
setBaseScore: function(score) {
this.baseScore = score;
return this;
},
addAnswerOption: function(answer) {
if(!answer instanceof Answer) {
console.log('Give me an answer object!');
return null;
}
this.answerOptions.push(answer);
return this;
}
setAnswerIndex: function(idx) {
this.selectedAnswerIndex = idx;
return this;
},
getScore: function() {
if(this.selectedAnswerIndex === null || this.baseScore === null) {
return null;
}
var ansIdx = this.selectedAnswerIndex;
var scoreModifier = this.answerOptions[ansIdx].questionScoreModifier;
if(scoreModifier === null) {
return null;
}
return this.baseScore * scoreModifier;
}
};
// build answer class
function Answer(text, modifier) {
this.text = null;
this.questionScoreModifier = null;
this.setText(text);
this.setScoreModifier(modifier);
};
// answer class methods
Answer.prototype = {
setText: function(text) {
this.text = text;
return this;
},
setScoreModifier(value) {
this.questionScoreModifier = value;
return this;
}
};
// build quiz class
function Quiz(title) {
this.title = null;
this.questions = [];
this.score = null;
this.setTitle(title);
}
// quiz class methods
Quiz.prototype = {
setTitle: function(text) {
this.title = text;
return this;
},
addQuestion: function(question) {
if(question instanceof Question) {
console.log('Give me a Question object!');
return null;
}
this.questions.push(question);
return this;
},
answerQuestion: function(questionIndex, answerIndex) {
this.questions[questionIndex].setAnswerIndex(answerIndex);
return this;
},
getTotalScore: function() {
var total = 0;
for(i=0; i<this.questions.length; i++) {
var questionScore = this.questions[i].getScore();
if (questionScore !== null) {
total +== questionScore;
}
}
this.score = total;
return total;
}
}You now have the basic building blocks to create your quiz. You could include this code anywhere and have a reusable quiz.
Now you need to build the quiz itself. That may look like this:
// build your quiz
var myQuiz = new Quiz('My cool quiz');
// now let build some questions
var question1 = new Question(
'This is text of question 1. What is correct answer?',
50
);
// now attach answers to the question
question1
.addAnswerOption(new Answer('Answer worth 50%', .5))
.addAnswerOption(new Answer('Answer worth 100%', 1))
.addAnswerOption(new Answer('Answer worth 25%', .25));
// add the question to the quiz
myQuiz.addQuestion(question1);
// you could continue code like above to fill out your quizFinally, we can start working with the quiz to set answers and get scores.
// now let's set a user answer on a question
// we can assume that we get both the question index
// and the answer index for the question from elsewhere in javascript
// for example from clicking on answer selection
var questionIdx = {some value};
var answerIdx = {some value};
// set the answer
myQuiz.answerQuestion(questionIdx, answerIdx);
// we can also get total quiz score
var totalQuizScore = myQuiz.getTotalScore();
// or we can get scores on individual questions
var question1Score = myQuiz.questions[0].getScore();Note that the outcome here is very reusable code that could be pretty much dropped anywhere within a larger application to implement your quiz. In a real application you may also add something like a quiz rendering class to be able to render the quiz using javascript (and to separate display of quiz from core quiz objects).
It also makes
Code Snippets
// let's build a question class
function Question(text, baseScore) {
this.text = null;
this.answerOptions = [];
this.selectedAnswerIndex = null;
this.baseScore = null;
this.setText(text);
this.setBaseScore(baseScore);
}
// add methods to question class
Question.prototype = {
setText: function(text) {
this.text = text;
// return the question object to allow for chaining
return this;
},
setBaseScore: function(score) {
this.baseScore = score;
return this;
},
addAnswerOption: function(answer) {
if(!answer instanceof Answer) {
console.log('Give me an answer object!');
return null;
}
this.answerOptions.push(answer);
return this;
}
setAnswerIndex: function(idx) {
this.selectedAnswerIndex = idx;
return this;
},
getScore: function() {
if(this.selectedAnswerIndex === null || this.baseScore === null) {
return null;
}
var ansIdx = this.selectedAnswerIndex;
var scoreModifier = this.answerOptions[ansIdx].questionScoreModifier;
if(scoreModifier === null) {
return null;
}
return this.baseScore * scoreModifier;
}
};
// build answer class
function Answer(text, modifier) {
this.text = null;
this.questionScoreModifier = null;
this.setText(text);
this.setScoreModifier(modifier);
};
// answer class methods
Answer.prototype = {
setText: function(text) {
this.text = text;
return this;
},
setScoreModifier(value) {
this.questionScoreModifier = value;
return this;
}
};
// build quiz class
function Quiz(title) {
this.title = null;
this.questions = [];
this.score = null;
this.setTitle(title);
}
// quiz class methods
Quiz.prototype = {
setTitle: function(text) {
this.title = text;
return this;
},
addQuestion: function(question) {
if(question instanceof Question) {
console.log('Give me a Question object!');
return null;
}
this.questions.push(question);
return this;
},
answerQuestion: function(questionIndex, answerIndex) {
this.questions[questionIndex].setAnswerIndex(answerIndex);
return this;
},
getTotalScore: function() {
var total = 0;
for(i=0; i<this.questions.length; i++) {
var questionScore = this.questions[i].getScore();
if (questionScore !== null) {
total +== questionScore;
}
}
this.score = total;
return total;
}
}// build your quiz
var myQuiz = new Quiz('My cool quiz');
// now let build some questions
var question1 = new Question(
'This is text of question 1. What is correct answer?',
50
);
// now attach answers to the question
question1
.addAnswerOption(new Answer('Answer worth 50%', .5))
.addAnswerOption(new Answer('Answer worth 100%', 1))
.addAnswerOption(new Answer('Answer worth 25%', .25));
// add the question to the quiz
myQuiz.addQuestion(question1);
// you could continue code like above to fill out your quiz// now let's set a user answer on a question
// we can assume that we get both the question index
// and the answer index for the question from elsewhere in javascript
// for example from clicking on answer selection
var questionIdx = {some value};
var answerIdx = {some value};
// set the answer
myQuiz.answerQuestion(questionIdx, answerIdx);
// we can also get total quiz score
var totalQuizScore = myQuiz.getTotalScore();
// or we can get scores on individual questions
var question1Score = myQuiz.questions[0].getScore();Context
StackExchange Code Review Q#132620, answer score: 6
Revisions (0)
No revisions yet.