Chahn
Chahn

Reputation: 25

Is there a faster and more simple way for randomizing the order of these questions?

i am learning python and am following a tutorial the current lesson has us creating a quiz game and instead of making the game static i wanted to make it so the order in which the answers to each question where given is random so i wrote some code. But it seems terribly inefficient and was wondering if some more experienced coders could help me analyze and see what i could have done better. its python 3 btw

import random
def random_letter(possible_answers):
    x = random.choice(possible_answers)
    return x

def random_question(q_correct,q_incorrect,answer):
    templist = []
    if answer == 'a':
        templist =[]
        templist2=[0,1,2]
        templist3=['B: ','C: ', 'D: ']
        templist.insert(0,'A: '+q_correct)
        for i in range(3):
            x = random.choice(templist2)
            templist2.remove(x)
            templist.append(templist3[i]+q_incorrect[x])
    if answer == 'b':
        templist =[]
        templist2=[0,1,2]
        templist3=['A: ','C: ','D: ']
        for i in range(3):
            x = random.choice(templist2)
            templist2.remove(x)
            templist.append(templist3[i]+q_incorrect[x])
        templist.insert(1, 'B: ' + q_correct)
    if answer == 'c':
        templist =[]
        templist2=[0,1,2]
        templist3=['A: ','B: ', 'D: ']
        for i in range(3):
            x = random.choice(templist2)
            templist2.remove(x)
            templist.append(templist3[i]+q_incorrect[x])
        templist.insert(2, 'C: ' + q_correct)
    if answer == 'd':
        templist =[]
        templist2=[0,1,2]
        templist3=['A: ','B: ', 'C: ']
        for i in range(3):
            x = random.choice(templist2)
            templist2.remove(x)
            templist.append(templist3[i]+q_incorrect[x])
        templist.insert(3,'D: '+q_correct)
    return templist
possible_answers = ['a','b','c','d']

questions = {
    "who created Python?" :random_letter(possible_answers),
    "What year was python created":random_letter(possible_answers),
    "Python is tributed to which comedy group":random_letter(possible_answers),
    "Is the Earth Round":random_letter(possible_answers)
}
templist = []
for value in questions.values():
    templist.append(value)
q1_correct = "Guido van Rossum"
q1_incorrect = ["Elon Musk", "Bill Gates","Mark Zuckerburg"]
q2_correct = "1991"
q2_incorrect = ['1989','2000','2016']
q3_correct = 'Monty Python'
q3_incorrect = ['Lonely Island', 'Smosh',"SNL"]
q4_correct = 'True'
q4_incorrect =['False','sometimes','the f*cks wrong with u']
q1_list = random_question(q1_correct,q1_incorrect,templist[0])
q2_list = random_question(q2_correct,q2_incorrect,templist[1])
q3_list = random_question(q3_correct,q3_incorrect,templist[2])
q4_list = random_question(q4_correct,q4_incorrect,templist[3])
final_questions = [q1_list,q2_list,q3_list,q4_list]
print(q1_list,q2_list,q3_list,q4_list)

Upvotes: 2

Views: 333

Answers (3)

Stef
Stef

Reputation: 15525

A few comments about your code:

  • It is good practice to separate cleanly data from code; I recommend moving the list of questions and answers to a .csv document and keep only the code in the .py file;
  • As much as possible, avoid long "forests of ifs", and prefer using lists and dicts and loops instead;
  • Keep each function small and easily readable and with one single purpose, writing multiple functions if necessary.

An added benefit of putting the data in a separate file is that you can ask your friends to contribute to the list of questions, without risking them inadvertently damaging the code in the python file.

Putting these comments into practice, I get two files, questions.csv and questions.py:

questions.csv

"Who created Python?","Guido van Rossum","Elon Musk", "Bill Gates","Mark Zuckerberg"
"What year was python created",1991,1989,2000,2016
"Python is tributed to which comedy group","Monty Python","Lonely Island", "Smosh","SNL"
"Is the Earth Round","True","False","sometimes","the f*cks wrong with u"

questions.py

import csv      # reader
import random   # choice, shuffle
import string   # ascii_uppercase

def get_data(filename):
    with open(filename, 'r') as f:
        r = csv.reader(f)
        data = [row for row in r]
    return data

def get_random_question(data):
    row = random.choice(data)
    question = row[0]
    correct_answer = row[1]
    possible_answers = row[1:]
    random.shuffle(possible_answers)
    return question, correct_answer, possible_answers

def ask_question(question, correct_answer, possible_answers):
    d = {index: answer for index,answer in zip(string.ascii_uppercase, possible_answers)}
    print(question)
    for index, answer in d.items():
        print(f'  {index}: {answer}')
    user_answer = input()
    while d[user_answer[0].upper()] != correct_answer:
        print('Wrong!! Try again')
        user_answer = input()
    print('Correct!!')

if __name__ == '__main__':
    data = get_data('questions.csv')
    question, correct_answer, possible_answers = get_random_question(data)
    ask_question(question, correct_answer, possible_answers)

Execution:

$ python3 questions.py 
Python is tributed to which comedy group
  A: Lonely Island
  B:  "Smosh"
  C: Monty Python
  D: SNL
c
Correct!!
$ python3 questions.py 
What year was python created
  A: 1989
  B: 2016
  C: 2000
  D: 1991
b
Wrong!! Try again
a
Wrong!! Try again
c
Wrong!! Try again
d
Correct!!

Upvotes: 1

Eddy Todd
Eddy Todd

Reputation: 81

To simplify your code the "expert" way you should use random.shuffle. This might be the simplest way to accomplish what you're trying to do. To understand how to make the code you have more efficient without using random.shuffle there are some modifications you can do to your code. This might not necessarily make it more efficient but it simplifies what you already have.

  • There's no need to have templist2 = [0, 1, 2] inside all ifs so you can just take it outside.

  • Instead of having to type 'A: ', 'B: ', 'C: ' and 'D: ', you can get that dynamically by using ans = answer.upper() + ': '.

  • Instead of getting the index of the answer you can get it by subtracting the char value of 'a' to the answer using ord(answer) - ord('a').

  • The for loop is repeated in all ifs so you can also just take that out of the ifs.

That would save a lot of space.

def random_question(q_correct, q_incorrect, answer):
templist = []
templist2 = [0, 1, 2]
templist3 = ['A: ', 'B: ', 'C: ', 'D: ']
ans = answer.upper() + ': '
templist3.remove(ans)
for i in range(3):
    x = random.choice(templist2)
    templist2.remove(x)
    templist.append(templist3[i] + q_incorrect[x])
templist.insert(ord(answer) - ord('a'), ans + q_correct)
return templist

Upvotes: 0

blazej
blazej

Reputation: 961

You can use random.shuffle to randomize answers for a single question. I know that you are a beginner for python so I decided to write more clear code to show you how you can use it.

from typing import List
import string
from random import shuffle

class Question:
    def __init__(self, question, answers: List[str]):
        self.question = question
        self.answers = answers

    def ask(self):
        answers = self.answers.copy() # the best way is just to copy this list because assignment would just create a reference (and we don't want that to happen)
        shuffle(answers) # randomizing order of answers
        correct_index = answers.index(self.answers[0]) # we keep here the index of the correct answer in case of checking if the user provided the correct answer

        # printing out the question and randomized answers with letters from `string.ascii_uppercase` list
        print(self.question)
        for i, ans in enumerate(answers):
            print(f'{string.ascii_uppercase[i]}) {ans}')

q = Question(question="Who created Python?", answers=["Guido van Rossum", "Elon Musk", "Bill Gates","Mark Zuckerburg"])
q.ask()

The Question class takes two parameters, question and answers. We can assume that always the first answer is correct to avoid making more class parameters. We are going to randomize it any way. Method ask prints out the question and randomized answers.

Here is an example of the output:

Who created Python?
A) Bill Gates
B) Mark Zuckerburg
C) Guido van Rossum
D) Elon Musk
Who created Python?
A) Guido van Rossum
B) Elon Musk
C) Bill Gates
D) Mark Zuckerburg

Hope that it's all clear for you

Upvotes: 1

Related Questions