Skip to content

Instantly share code, notes, and snippets.

@latviancoder
Last active October 28, 2018 12:00
Show Gist options
  • Save latviancoder/34608fe785b62f49aa63c69dbfa051dd to your computer and use it in GitHub Desktop.
Save latviancoder/34608fe785b62f49aa63c69dbfa051dd to your computer and use it in GitHub Desktop.
import * as _ from 'lodash';
class Course {
students = [];
quizzes = [];
constructor(name, teacher) {
this.name = name;
this.teacher = teacher;
}
getTeacher() {
return this.teacher;
}
addStudent(student) {
this.students.push(student);
}
hasStudent(student) {
return this.students.includes(student);
}
getStudents() {
return this.students;
}
getQuizzes() {
return this.quizzes;
}
addQuiz(name, questions) {
const quiz = new Quiz(name, questions);
this.quizzes.push(quiz);
return quiz;
}
calculateGrade(student) {
let grade = 0;
for (let quiz of this.quizzes) {
grade += student.getQuizAnswers(quiz).calculateGrade();
}
return grade;
}
}
class Quiz {
constructor(name, questions) {
this.name = name;
this.questions = questions;
}
getQuestions() {
return this.questions;
}
}
class Student {
courses = [];
quizAnswers = new Map();
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
enroll(course) {
this.courses.push(course);
course.addStudent(this);
}
getCourses() {
return this.courses;
}
answerQuiz(quiz, answers) {
const quizAnswers = new QuizAnswers(this, quiz, answers);
this.quizAnswers.set(quiz, quizAnswers);
return quizAnswers;
}
getQuizAnswers(quiz) {
return this.quizAnswers.get(quiz);
}
}
class QuizAnswers {
constructor(student, quiz, answers) {
this.student = student;
this.quiz = quiz;
this.answers = answers;
}
getAnswers() {
return this.answers;
}
getAnsweredQuestionsCount() {
return Object.keys(this.answers).length;
}
calculateGrade() {
let questions = this.quiz.getQuestions();
let totalScore = 0;
// `answers` is an object because partial submissions can be made
// unanswered questions are not scored
_.forOwn(this.answers, function(answers, questionIndex) {
let questionScore = 0;
const correctAnswers = questions[questionIndex].correctAnswers;
// partial scoring is enabled - selecting wrong option will result in negative score
for (const answer of answers) {
if (correctAnswers.includes(answer)) {
questionScore += 1;
} else {
questionScore -= 1;
}
}
if (questionScore > 0) {
totalScore += (questionScore/correctAnswers.length);
}
});
// Minimum grade - 0
// Maximum grade - 10
// Because unanswered questions are not scored we do not divide by overall questions count
return Math.floor(totalScore/this.getAnsweredQuestionsCount() * 10);
}
}
class Teacher {
courses = [];
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
getCourses() {
return this.courses;
}
addCourse(name) {
const course = new Course(name, this);
this.courses.push(course);
return course;
}
}
export {
Student,
Teacher,
Course,
Quiz,
QuizAnswers
};
import {Student, Teacher} from './index';
// I assumed nobody is going to try to break this stuff and didn't add almost any error handling
let smith;
let bob;
beforeEach(() => {
smith = new Teacher('Mr. Smith');
bob = new Student('Bob');
});
test('can create instances of teacher', () => {
expect(smith).toBeInstanceOf(Teacher);
expect(smith.getName()).toBe('Mr. Smith');
});
test('can create instances of student', () => {
expect(bob).toBeInstanceOf(Student);
expect(bob.getName()).toBe('Bob');
});
describe('enrollment and quizzes', () => {
let smithBiology;
let quiz;
beforeEach(() => {
// For the sake of simplicity I assume 1 course can only have 1 teacher, but teachers can have many courses
smithBiology = smith.addCourse('Biology');
bob.enroll(smithBiology);
// I assumed teachers can't assign different quizzes to different students in course
// Quizzes are automatically applied to everyone in course
quiz = smithBiology.addQuiz(
'Quiz number 1',
[
{
question: 'Another question?',
options: [
'Option 0', 'Option 1', 'Option 2'
],
correctAnswers: [1]
},
{
question: 'What is round?',
options: [
'Ball', 'Knife', 'Sun', 'Orange', 'Car'
],
correctAnswers: [0, 2, 3]
}
]
);
});
test('teacher can create courses', () => {
expect(smithBiology.getTeacher()).toBe(smith);
expect(smith.getCourses()).toHaveLength(1);
expect(smith.getCourses()).toContain(smithBiology);
});
test('teacher can create multiple courses', () => {
smith.addCourse('Algebra');
expect(smith.getCourses()).toHaveLength(2);
expect(smith.getCourses()).toContain(smithBiology);
});
test('students can enroll into courses', () => {
expect(bob.getCourses()).toContain(smithBiology);
expect(smithBiology.getStudents()).toContain(bob);
});
test('quizzes can be added to the course', () => {
expect(smithBiology.getQuizzes()).toHaveLength(1);
expect(smithBiology.getQuizzes()).toContain(quiz);
});
describe('grading quizzes', () => {
test('maximum score is 10', () => {
const bobQuizAnswers = bob.answerQuiz(quiz, {
0: [1],
1: [0, 2, 3]
});
expect(bobQuizAnswers.calculateGrade()).toBe(10);
});
test('minimum score is 0', () => {
const bobQuizAnswers = bob.answerQuiz(quiz, {
0: [0],
1: [1]
});
expect(bobQuizAnswers.calculateGrade()).toBe(0);
});
test('partial submissions can be made, unanswered questions are not graded', () => {
const bobQuizAnswers = bob.answerQuiz(quiz, {
1: [0, 2, 3]
});
expect(bobQuizAnswers.calculateGrade()).toBe(10);
});
test('student can be graded in course', () => {
bob.answerQuiz(quiz, {
0: [1],
1: [0, 1, 3]
});
expect(smithBiology.calculateGrade(bob)).toBe(6);
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment