Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Quailty of Life Changes #11

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions _classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,17 @@ def __get_correct_answer(self, card_body) -> str:
"""

cabody = card_body.find("p", attrs={'class': "card-text question-answer bg-light white-text"}) # correct answers body

comm_correct_answer = cabody.find("div", attrs={'class': "vote-bar progress-bar bg-primary"}) # the bar with community answer
if cabody is not None:
comm_correct_answer = cabody.find("div", attrs={'class': "vote-bar progress-bar bg-primary"})
comm_correct_answer = cabody.find("div", attrs={'class': "vote-bar progress-bar bg-primary"}) # the bar with community answer

# in the cases where the community agrees with ExamTopics, there is no community voting bar
if comm_correct_answer != None:
correct_answer = comm_correct_answer.text.split(" ")[0] # vote-bar progress-bar bg-primary
if comm_correct_answer != None:
correct_answer = comm_correct_answer.text.split(" ")[0] # vote-bar progress-bar bg-primary
else:
correct_answer = cabody.find("span",attrs={'class': "correct-answer"}).text
else:
correct_answer = cabody.find("span",attrs={'class': "correct-answer"}).text
correct_answer = None

return correct_answer

Expand All @@ -167,3 +170,4 @@ def get_cards(self) -> list:
Getter for the lsit of cards
"""
return self.cards_list

146 changes: 67 additions & 79 deletions quiz.py
Original file line number Diff line number Diff line change
@@ -1,152 +1,140 @@
from io import TextIOWrapper
from _classes import CardList, os, re
import random
from datetime import datetime
from datetime import datetime
import json
import textwrap

class Quiz:
def __init__(self, resources_dir = None) -> None:
def __init__(self, resources_dir=None) -> None:
self.__cardlist = CardList(resources_dir)
self.__log_dirname = "wrong_answers" # the name of the directory where the .txt files with wrong answers will be stored
self.__log_dirname = "quiz_logs" # the name of the directory where the JSON files with quiz logs will be stored

self.__init_questions_per_quiz()
self.__init_show_answer_immediately()
self.__init_questions_per_quiz()
self.__init_show_answer_immediately()

self.__create_wrong_answers_directory()

self.quiz_cards = self.__generate_quiz()
self.__create_logs_directory()

self.quiz_logs = self.__generate_quiz_logs()

def __init_questions_per_quiz(self):
"""
Initializez the varialbe that shows how many question should be shown in a quiz run
Initialize the variable that shows how many questions should be shown in a quiz run
"""

try:
self.__questions_per_quiz = \
int(input("How many questions do you want to have? (Max: " + str(len(self.__cardlist.cards_list)) + ") "))
self.__questions_per_quiz = int(input("How many questions do you want to have? (Max: " + str(
len(self.__cardlist.cards_list)) + ") "))

while type(self.__questions_per_quiz) != int or self.__questions_per_quiz > len(self.__cardlist.cards_list):
self.__questions_per_quiz = \
int(input("Please pick a NUMBER. (Max: " + str(len(self.__cardlist.cards_list)) + ")"))
while type(self.__questions_per_quiz) != int or self.__questions_per_quiz > len(
self.__cardlist.cards_list):
self.__questions_per_quiz = int(input("Please pick a NUMBER. (Max: " + str(
len(self.__cardlist.cards_list)) + ")"))
except:
print("Defaulted to max number of questions.")
print("Defaulted to the max number of questions.")
self.__questions_per_quiz = len(self.__cardlist.cards_list)

def __init_show_answer_immediately(self):
"""
Initializes the variable that decides if you want the correct answer shown after you respond
Initializes the variable that decides if you want the correct answer shown after you respond
"""
self.__show_answer_immediately = \
input("Do you want to have the answer shown immediately after you respond?\n(If not, you will be shown a score at the end and a file will be generated with the wrong answers anyway.)[Y/n] ")
self.__show_answer_immediately = input(
"Do you want to have the answer shown immediately after you respond?\n"
"(If not, you will be shown a score at the end and a file will be generated with the wrong answers anyway.)[Y/n] ")

if self.__show_answer_immediately == "": # if only Enter was pressed
self.__show_answer_immediately = "y" # default to y

self.__show_answer_immediately = self.__show_answer_immediately.lower()
while self.__show_answer_immediately != "n" and self.__show_answer_immediately != "y":
self.__show_answer_immediately = \
input("Please pick between 'y'(yes) or 'n'(no): ")
self.__show_answer_immediately = input("Please pick between 'y'(yes) or 'n'(no): ")
self.__show_answer_immediately = self.__show_answer_immediately.lower()


def __generate_quiz(self) -> list:
def __generate_quiz_logs(self) -> list:
"""
Generate a random list of card objects that are limited by the size of how
many questions the player wants to have
Generate a list of dictionaries containing quiz data before the user answers the questions
"""
random.shuffle(self.__cardlist.cards_list)
return self.__cardlist.cards_list[:self.__questions_per_quiz]

quiz_logs = []
for card in self.__cardlist.cards_list[:self.__questions_per_quiz]:
quiz_logs.append({
'question_number': card.question_number,
'question': card.question,
'answers': card.answers,
'correct_answer': card.correct_answer,
'user_response': None
})

return quiz_logs

def __clear(self):
"""
Clear the terminal window
Clear the terminal window
"""
print("") # get a new empty line
# for windows
if os.name == 'nt':
_ = os.system('cls')
# for mac and linux(here, os.name is 'posix')
else:
_ = os.system('clear')

_ = os.system('clear')

def __create_wrong_answers_directory(self):
def __create_logs_directory(self):
try:
os.mkdir(self.__log_dirname)
except:
print("Wrong answers directory already exists. Continuing..")
print("Quiz logs directory already exists. Continuing..")

def __init_answers_file(self) -> TextIOWrapper:
"""
Initialize the filename with the current datetime, while omitting spaces and colon
Initialize the filename with the current datetime, while omitting spaces and colon
"""
filename = re.sub(" ", "_", str(datetime.now())).split(".")[0] # remove the miliseconds as they were delimited by '.'
filename = re.sub(":", "-", filename) # remove ':' as they are a special char on Windows..
filename += ".txt"
filename = re.sub(" ", "_", str(datetime.now())).split(".")[0] # remove the milliseconds as they were delimited by '.'
filename = re.sub(":", "-", filename) # remove ':' as they are a special char on Windows..
filename += ".json"
filename = os.path.join(self.__log_dirname, filename)
wrong_answers_file = open(filename, "w") # file where the wrong answers will be written to

return wrong_answers_file


def __write_to_file(self, wrong_answers_file, card, your_answer):

wrapper = textwrap.TextWrapper() # wrap text so it looks better

wrong_answers_file.write(card.question_number + " " + wrapper.fill(text= card.question) + "\n")
wrong_answers_file.write("-" * 40 + "\n")
for ans in card.answers:
try:
# ans = str(ans.encode('utf-8')) # some answers give a UnicodeEncodeError: 'charmap' codec can't encode character '\u05d2' in position 192: character maps to <undefined>
wrong_answers_file.write(wrapper.fill(text= ans) + "\n") # one answer had a weird encoding
except:
wrong_answers_file.write(str(ans) + "\n")

wrong_answers_file.write("Your answer: " + your_answer.upper() + "\n")
wrong_answers_file.write("Correct answer: " + card.correct_answer + "\n")
wrong_answers_file.write("-" * 40 + "\n\n")
quiz_log_file = open(filename, "w") # file where the quiz log will be written to

return quiz_log_file

def start_quiz(self):
"""
The main logic function for the quiz to run
"""
The main logic function for the quiz to run
"""
self.__clear()

correct_answers = 0 # initialize correct answers

wrong_answers_file = self.__init_answers_file()
wrapper = textwrap.TextWrapper() # wrap text so it looks better

print("Your quiz starts now. Please enter one single character, coresponding to the answers (A,B,C or D). Answers are NOT case sensitive, so response 'b' is good if 'B' is the correct answer.\n")
print("Your quiz starts now. Please enter one single character, corresponding to the answers (A,B,C, or D). "
"Answers are NOT case sensitive, so response 'b' is good if 'B' is the correct answer.\n")
input("Press Enter to continue..")

for index, card in enumerate(self.quiz_cards):
for index, quiz_log in enumerate(self.quiz_logs):
print("")
print(str(index + 1) + "/" + str(self.__questions_per_quiz))
print(card.question_number + " " + wrapper.fill(text= card.question))
print(quiz_log['question_number'] + " " + textwrap.fill(text=quiz_log['question']))
print("-" * 40)
for ans in card.answers:
print(wrapper.fill(text= ans))
for ans in quiz_log['answers']:
print(textwrap.fill(text=ans))
print("-" * 40)

your_answer = ""
while your_answer.upper() not in ['A', 'B', 'C', 'D']:
your_answer = input("Your answer: ")

if your_answer.upper() == card.correct_answer:
correct_answers += 1
else:
# write to the wrong answer to the file
self.__write_to_file(wrong_answers_file, card, your_answer)

self.quiz_logs[index]['user_response'] = your_answer.upper()

if self.__show_answer_immediately == "y":
print("Correct answer: ", card.correct_answer)
print("Correct answer: ", quiz_log['correct_answer'])
input("Press Enter to continue..")

wrong_answers_file.close() # writing is done so we close the file

quiz_log_file = self.__init_answers_file()
json.dump(self.quiz_logs, quiz_log_file, indent=2)
quiz_log_file.close()

correct_answers = sum(1 for quiz_log in self.quiz_logs if
quiz_log['user_response'] == quiz_log['correct_answer'])
print("=^=" * 40)
print("The quiz is DONE! Good job!")
print("Your score: " + str(correct_answers) + "/" + str(self.__questions_per_quiz))
print("Your score: " + str(correct_answers) + "/" + str(self.__questions_per_quiz))