Python Forum
Presenting random test questions
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Presenting random test questions
#1
I have Python 3.10, and want to read a series of multiple choice or Yes-No/True-False test questions into a list (or array or whatever) from an Excel spreadsheet, complete with 5 possible answers for the multiple choice questions and, of course, 2 possible answers for the true/false or yes/no questions. Each question has a preferred answer priority, 1st or best answer, 2nd best answer… worst or 5th best answer, etc.

The program should first show how many questions there are to choose from, and the user chooses how many questions they want to answer. Can someone show me how to randomly choose the questions to ask (no repeats), as well as randomly shuffle the answers (while keeping track of their priority (i.e. 1st or best choice, 2nd best, etc.)? Seems like a nightmare for this novice Python programmer.

Many thanks in advance,
Perplexed in Pittsburgh
Reply
#2
I've not covered the 'Excel' part of this, as I'm not a Excel user, but from what I do know, I can't see that part being a huge challenge: I see the QandA dictionary being built, in part, from your Excel file, with which I'm sure OPs will be able to help, if needs be.

This is one way that one could begin to build the Q&A part:

from random import shuffle, randint

answered = 'answered'
answer   = 'answer'
question = 'question'
answers  = 'answers'

QandA = {
    1:{
        answered: False,
        answer: '',
        question: "This will be the text for question 1.",                    # place holder
        answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
        },
    2:{
        answered: False,
        answer: '',
        question: "This will be the text for question 2.",                    # place holder
        answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
        },
    3:{
        answered: False,
        answer: '',
        question: "This will be the text for question 3.",                    # place holder
        answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
        },
    4:{
        answered: False,
        answer: '',
        question: "This will be the text for question 4.",                    # place holder
        answers: ("Answer 1", "Answer 2", "Answer 3", "Answer 4", "Answer 5") # place holder
        },
    5:{
        answered: False,
        answer: '',
        question: "This will be the text for question 5.",                    # place holder
        answers: ("True", "False")                                            # place holder
        }
    
}

# the driver

no_of_qs = len(QandA)
print(f"There will be {no_of_qs} questions.\n")

q_asked = [] #holds the index of the question asked
q = 0

done = False
while not done:
    q = randint(1,no_of_qs)
    if len(q_asked) < no_of_qs:
        if q not in q_asked:
            q_asked.append(q)
            ask = QandA[q][question]
            print(ask)
            options = [option for option in range(0,len(QandA[q][answers]))]
            if len(options) > 2: # no need to shuffle True/False
                shuffle(options)
            for choose, ans in enumerate(options,1):
                print(f"{choose}: {QandA[q][answers][ans]}")
            the_answer = False
            while not the_answer:
                the_answer = input(f"\n1 to {len(options)} or 0 to pass.\n> ")
                if len(the_answer) > 1 or the_answer.isalpha() or int(the_answer)not in range(0,len(options)+1):
                    the_answer = False
                    print("Invalid answer.")
            if the_answer != '0':
                QandA[q][answered] = True
                QandA[q][answer] = QandA[q][answers][options[int(the_answer)-1]]
                print()
    else:
        done = True

for q in range(1,no_of_qs+1):
    if QandA[q][answered]:
        print(f"Question {q} was answered: {QandA[q][answer]}.")
    else:
        print(f"Question {q} was not answered.")
Not too sure if this is going to be of any help, or if anyone else has a better way for this to be done. I've also not covered the binary part of this (questions that have a simple yes/no answer), but I don't see why that could not be implemented in some way; I'll have a look at that next, if you're still interested in moving this forward.



Code update: Some minor changes, just to make for a better base solution...
Added a True/False option and also a feedback for the questions that have been answered, from which a score could be calculated, based on whatever system you choose.
Sig:
>>> import this

The UNIX philosophy: "Do one thing, and do it well."

"The danger of computers becoming like humans is not as great as the danger of humans becoming like computers." :~ Konrad Zuse

"Everything should be made as simple as possible, but not simpler." :~ Albert Einstein
Reply
#3
I'd bet Excel really means csv. After loading the csv file (or maybe the Excel file) the trickiest part will be formatting the question. For True/False the choices should be "T" and "F". for Yes/No the choices should be "Y" and "N". For multiple choice the choices can be anything. Letters, numbers, first unique letter in each choice, etc. I like letters because they are easier for me to type. For kids, numbers is probably a better choice.

For random, either use random.sample() or random.shuffle(). Both are guaranteed to not repeat.

This is a rough example. I have no idea how to handle "2nd best answer" because I have no idea what is meant by "2nd best answer" in a multiple choice test. Do you get partial credit if you don't pick the "worst" answer?
from io import StringIO
import csv
import random

# Standin for CSV file.  Question followed by choices.
#     Imagine "Question 1" is "What was the capital of Germany in 1956?", and it is followed
#     by "Bonn", "Berlin", "Frankfurt", "Flensburg", "Munich".  First choice is correct, but
#     all choices have been capitals except Munich (the worst choice).
file = StringIO(
    """\
"Question 1","Choice 1","Choice 2","Choice 3","Choice 4","Choice 5"
"Question 2","Choice 1","Choice 2","Choice 3","Choice 4"
"Question 3","True","False"
"Question 4","Choice 1","Choice 2","Choice 3"
"Question 5","False","True"
"Question 6","Yes","No"
"Question 7","No","Yes"
"""
)

# True/False and Yes/No are special cases and should always be presented
# in the same order and use special answer keys.  Choices for other questions
# appear in random order.
TRUE_FALSE = {"T": "True", "F": "False"}
YES_NO = {"Y": "Yes", "N": "No"}


def get_answer(question, choices):
    """Get user input.  Input must match one of the choice keys"""
    print(f"\n{question}")
    for key, value in choices.items():
        print(f"{key}: {value}")
    selection = input("> ").upper()
    while True:
        if selection in choices:
            return choices[selection]
        selection = input(f"Please choose from {', '.join(choices)}: ").upper()


def ask_question(question):
    """Format question.  Randomize choices.  Return True if selection is correct"""
    question, *choices = question
    if choices[0] in YES_NO.values():
        options = YES_NO
    elif choices[0] in TRUE_FALSE.values():
        options = TRUE_FALSE
    else:
        # Any multiple choice that is not True/False or Yes/No
        # Use 1234567 instead of ABCDEFG if want "1: choice" instead of "A: choice"
        options = {
            a: b for a, b in zip("ABCDEFG", random.sample(choices, k=len(choices)))
        }
    return get_answer(question, options) == choices[0]  # First choice is correct


# Load and shuffle the questions
questions = list(csv.reader(file))
random.shuffle(questions)

# Ask questions and keep score
score = 0
for question in questions:
    if ask_question(question):
        score += 1
print(score)
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Presenting multiline data into single line aaronbuhu 1 1,801 Aug-05-2021, 10:57 AM
Last Post: jamesaarr
  How to test and import a model form computer to test accuracy using Sklearn library Anldra12 6 3,117 Jul-03-2021, 10:07 AM
Last Post: Anldra12
  Generate questions from excel to test my chatbot mcubac08 5 2,859 Sep-01-2020, 06:15 PM
Last Post: mcubac08
  How to write test cases for a init function by Unit test in python? binhduonggttn 2 3,109 Feb-24-2020, 12:06 PM
Last Post: Larz60+
  How to write test cases by Unit test for database configuration file? binhduonggttn 0 2,553 Feb-18-2020, 08:03 AM
Last Post: binhduonggttn
  Discord bot that asks questions and based on response answers or asks more questions absinthium 1 38,763 Nov-25-2017, 06:21 AM
Last Post: heiner55

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020