Skip to content

Intermediate · Projects: put it all together · topic 34 of 50 · 30 min

Project: quiz game with negative marking

Explanation

You will build the logic of a quiz game like a mock test for a competitive exam: questions stored as data, answers checked fairly, +4 for right, -1 for wrong and 0 for skipped. You will also make a result summary and shuffle questions with a seed so the order can be repeated.

The plan

PartFor our quiz
InputsA list of questions (dictionaries) and a list of the player's answers
OutputsScore with negative marking, counts of correct, wrong and skipped, a shuffled order
Rule+4 for correct, -1 for wrong, 0 for skipped (blank or None)

The game takes answers as a list instead of calling input(). This keeps the logic separate from the screen, so the same functions work in a terminal game, a website or a phone app, and they are easy to test.

Think of it like this: Think of an OMR sheet in an exam. The question paper is one thing, the answer sheet is another, and the machine that checks them is a third. Our questions list is the paper, the answers list is the OMR sheet, and our functions are the checking machine.

Step 1: questions as data

python
questions = [
    {"question": "Capital of India?", "options": ["Mumbai", "New Delhi", "Kolkata"], "answer": "New Delhi"},
    {"question": "5 * 6 = ?", "options": ["30", "11", "56"], "answer": "30"},
    {"question": "Largest planet?", "options": ["Earth", "Mars", "Jupiter"], "answer": "Jupiter"},
]
for number, q in enumerate(questions, start=1):
    print(number, q["question"], "/".join(q["options"]))
Adding a question means adding data, not changing code.

Step 2: check one answer fairly

People type in different ways: "new delhi", " New Delhi ", "NEW DELHI". These should all count as correct. So we strip spaces from both ends and compare in lower case. A blank answer or None means the player skipped.

python
def is_skipped(given):
    return given is None or given.strip() == ""

def check_answer(given, correct):
    if is_skipped(given):
        return False
    return given.strip().lower() == correct.strip().lower()

print(check_answer("  new delhi ", "New Delhi"))  # True
print(check_answer("Mumbai", "New Delhi"))        # False
print(is_skipped("   "))                          # True
Clean both sides before comparing.

Step 3: score with negative marking

python
def is_skipped(given):
    return given is None or given.strip() == ""

def check_answer(given, correct):
    return not is_skipped(given) and given.strip().lower() == correct.strip().lower()

def summary(questions, answers, right=4, wrong=-1):
    answers = list(answers) + [None] * (len(questions) - len(answers))
    result = {"correct": 0, "wrong": 0, "skipped": 0}
    for q, given in zip(questions, answers):
        if is_skipped(given):
            result["skipped"] += 1
        elif check_answer(given, q["answer"]):
            result["correct"] += 1
        else:
            result["wrong"] += 1
    result["score"] = result["correct"] * right + result["wrong"] * wrong
    result["max_score"] = len(questions) * right
    return result

questions = [{"answer": "New Delhi"}, {"answer": "30"}, {"answer": "Jupiter"}, {"answer": "7"}]
print(summary(questions, ["new delhi", "56", "", "7"]))
# 2 correct, 1 wrong, 1 skipped -> score 2*4 - 1 = 7 out of 16
right and wrong are parameters, so the same code works for +3/-1 or +1/0 exams.
Careful: zip() stops at the shorter list. If a player answers only 3 of 10 questions, zip would silently ignore the last 7. That is why summary() pads the answers list with None first, so unanswered questions count as skipped.

Step 4: shuffle with a seed

Shuffling stops students copying by position. But for testing, and for showing a student the same paper again, we want to repeat a shuffle exactly. A seed is a starting number for the random generator: the same seed always gives the same order.

python
import random

def shuffled(questions, seed):
    rng = random.Random(seed)   # its own generator, does not disturb others
    copy = list(questions)      # never change the caller's list
    rng.shuffle(copy)
    return copy

qs = ["Q1", "Q2", "Q3", "Q4", "Q5"]
print(shuffled(qs, 42))
print(shuffled(qs, 42))  # same order again
print(qs)                # original unchanged
random.Random(seed) makes a private generator; random.shuffle would change the list in place.
Tip: Use the roll number or test ID as the seed. Every student gets a different order, but you can always rebuild any student's paper from their seed.

Step 5: test the rules

  • All correct: score equals max_score.
  • All wrong: score is minus the number of questions.
  • All skipped, or an empty answers list: score 0.
  • Same seed gives the same order; the shuffled list has the same items as the original.

Watch the lesson

Project: quiz game with negative marking · 1/6

Project: quiz game

In this project you will build the checking engine of a quiz game, with negative marking like real competitive exams.

Prefer a video by a teacher? Find free videos on “python quiz game project with score” on YouTube ↗

In real life: A coaching centre mock test

A JEE coaching centre in Kota runs a weekly mock test on tablets. The screens are built by a web developer, but the checking is done by functions like ours: answers come in as a list, the score uses +4 and -1, and each student gets the paper shuffled with their roll number as the seed.

python
correct, wrong, skipped = 52, 18, 20
score = correct * 4 - wrong * 1
print("Score:", score, "out of", (correct + wrong + skipped) * 4)
52 right and 18 wrong gives 190 out of 360.

Practice (0/3 done)

Task 1 · Code · Python

Write check_answer(given, correct). Return True when the answers match, ignoring spaces at the ends and capital letters. If given is None or only spaces, return False.

Task 2 · Code · Python

Write score_quiz(questions, answers). Each question is a dictionary with an "answer". Give +4 for a correct answer, -1 for a wrong one and 0 for a skipped one (None or blank). Compare like check_answer: ignore end spaces and case. If answers is shorter than questions, the missing ones are skipped.

Task 3 · Code · Python

Write shuffled(questions, seed) that returns a NEW list with the questions in a random order. Use random.Random(seed) so the same seed always gives the same order. Do not change the original list.

Quick quiz

Question 1

1.With +4 and -1 marking, what is the score for 10 correct, 5 wrong and 5 skipped?

Question 2

2.Why do the functions take answers as a list instead of calling input()?

Question 3

3.What does zip([1, 2, 3], ["a"]) produce?

Question 4

4.What is the point of shuffling with a seed?

Question 5

5.Which comparison accepts " JUPITER " for the answer "Jupiter"?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Project: expense tracker