HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Calculating quiz score, with weights and partial credit

Submitted by: @import:stackexchange-codereview··
0
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:

  • 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 statement

Solution

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:

  • 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 quiz


Finally, 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.