Я новичок в Python и Tkinter. Я создал базовое приложение-викторину для проекта в колледже, которое отображает случайные 10 вопросов из набора из 30 вопросов.
В словаре ВОПРОСЫ каждый вопрос имеет 4 ответа, первый из которых является правильным. В функцииgenerate_quiz() на каждый вопрос правильный ответ перемешан среди трех других. В конце викторины сбрасывает все при возврате в главное меню. При выборе правильных ответов в 1-м туре викторина проходит гладко, но когда я перезапускаю викторину и выбираю те же правильные ответы, они отображаются как неправильные. Это происходит только с вопросами, которые являются общими с вопросами предыдущего раунда, в новых вопросах такой проблемы нет.
Любая помощь будет принята с благодарностью!
Вот весь код:
from tkinter import *
import random
QUESTIONS = {
"What is the capital of France?": ["Paris", "London", "Berlin", "Madrid"],
"Who wrote 'To Kill a Mockingbird'?": ["Harper Lee", "Mark Twain", "Jane Austen", "J.K. Rowling"],
"What is the largest planet in our solar system?": ["Jupiter", "Mars", "Earth", "Venus"],
"What is the chemical symbol for water?": ["H2O", "CO2", "O2", "NaCl"],
"Who was the first president of the United States?": ["George Washington", "Thomas Jefferson", "Abraham Lincoln", "John Adams"],
"What is the square root of 64?": ["8", "6", "7", "9"],
"Who painted the Mona Lisa?": ["Leonardo da Vinci", "Vincent van Gogh", "Pablo Picasso", "Claude Monet"],
"What is the longest river in the world?": ["Nile", "Amazon", "Yangtze", "Mississippi"],
"What is the smallest country in the world?": ["Vatican City", "Monaco", "Nauru", "San Marino"],
"What is the fastest land animal?": ["Cheetah", "Lion", "Tiger", "Leopard"],
"Who discovered penicillin?": ["Alexander Fleming", "Marie Curie", "Louis Pasteur", "Isaac Newton"],
"What is the hardest natural substance on Earth?": ["Diamond", "Gold", "Iron", "Silver"],
"What is the capital of Japan?": ["Tokyo", "Beijing", "Seoul", "Bangkok"],
"Who wrote '1984'?": ["George Orwell", "Aldous Huxley", "Ray Bradbury", "J.R.R. Tolkien"],
"What is the chemical symbol for gold?": ["Au", "Ag", "Pb", "Fe"],
"What is the tallest mountain in the world?": ["Mount Everest", "K2", "Kangchenjunga", "Lhotse"],
"What is the main ingredient in guacamole?": ["Avocado", "Tomato", "Onion", "Garlic"],
"Who is known as the father of computers?": ["Charles Babbage", "Alan Turing", "John von Neumann", "Bill Gates"],
"What is the largest ocean on Earth?": ["Pacific Ocean", "Atlantic Ocean", "Indian Ocean", "Arctic Ocean"],
"What is the speed of light?": ["299,792,458 meters per second", "150,000,000 meters per second", "186,282 miles per second", "300,000,000 meters per second"],
"Who painted the ceiling of the Sistine Chapel?": ["Michelangelo", "Raphael", "Leonardo da Vinci", "Donatello"],
"What is the capital of Australia?": ["Canberra", "Sydney", "Melbourne", "Brisbane"],
"Who wrote 'Pride and Prejudice'?": ["Jane Austen", "Charlotte Bronte", "Mary Shelley", "Emily Dickinson"],
"What is the chemical symbol for oxygen?": ["O", "O2", "Ox", "Og"],
"What is the largest mammal in the world?": ["Blue Whale", "Elephant", "Giraffe", "Hippopotamus"],
"What is the smallest bone in the human body?": ["Stapes", "Femur", "Tibia", "Fibula"],
"Who invented the telephone?": ["Alexander Graham Bell", "Thomas Edison", "Nikola Tesla", "Guglielmo Marconi"],
"What is the primary language spoken in Brazil?": ["Portuguese", "Spanish", "French", "English"],
"What is the result of 1 + 1?": ["2", "3", "1", "0"],
"What is the capital of Canada?": ["Ottawa", "Toronto", "Vancouver", "Montreal"]
}
MAX_SCORE = 10
questions = random.sample(list(QUESTIONS.items()), 10)
score = 0
message_label = None
answer_selected = None
# Defining all functions
def display_frame(frame):
frame.tkraise()
def create_welcome_frame():
welcome_frame = Frame(container, bg = 'gray12')
welcome_frame.grid(row = 0, column = 0, sticky = 'nsew')
title_label = Label(welcome_frame, text = "QuizApp", font = ('Arial', 24), fg = 'white', bg = 'gray12')
title_label.pack(fill = X, pady = 30)
welcome_label = Label(welcome_frame, text = 'Welcome to QuizApp! Press the \'Start\' button to begin the quiz.', font = ('Arial', 20), fg = 'white', bg = 'gray12', pady = 40)
welcome_label.pack(pady = 20)
start_button = Button(welcome_frame, text = 'Start', font = ('Arial', 24), fg = 'white', bg = 'SpringGreen2', padx = 20, pady = 20, command = generate_quiz_frame)
start_button.pack(pady = (60, 0))
return welcome_frame
def create_quiz_frame():
quiz_frame = Frame(container, bg = 'gray12')
quiz_frame.grid(row = 0, column = 0, sticky = 'nsew')
return quiz_frame
def generate_quiz():
global questions, answer_selected
if questions:
global question
question, answers = questions.pop(0)
correct_answer = answers[0]
question_label = Label(quiz_frame, text = question, font = ('Arial', 25), fg = 'white', bg = 'gray12', pady = 40)
question_label.pack(anchor = W, padx = (200, 0))
random.shuffle(answers)
for answer in answers:
answer_selected = False
answer_button = Button(quiz_frame, text = answer, width = 30, pady = 17, font = ('Arial', 19), command = lambda chosen_answer = answer: display_quiz_message(chosen_answer, correct_answer))
answer_button.pack(anchor = W, padx = (200, 0), pady = 10)
else:
display_frame(results_frame)
update_results_frame()
def display_quiz_message(chosen_answer, correct_answer):
global message_label, score, answer_selected
if not answer_selected:
if message_label:
message_label.destroy()
message = ''
message_color = ''
answer_selected = True
if chosen_answer == correct_answer:
message = 'You got it correct!'
message_color = 'SpringGreen3'
score += 1
else:
message = 'You got it wrong...'
message_color = 'red2'
message_label = Label(quiz_frame, text = message, font = ('Arial', 20), fg = message_color, bg = 'gray12')
message_label.pack(anchor = W, padx = (200, 0))
next_button = Button(quiz_frame, text = 'Next', font = ('Arial', 15), command = lambda: clear_frame(quiz_frame))
next_button.pack(anchor = W, padx = (200, 0), pady = (20,0))
else:
pass
def clear_frame(frame):
for widget in frame.winfo_children():
widget.destroy()
generate_quiz()
def generate_quiz_frame():
generate_quiz()
display_frame(quiz_frame)
def create_results_frame():
results_frame = Frame(container, bg = 'gray12')
results_frame.grid(row = 0, column = 0, sticky = 'nsew')
return results_frame
def update_results_frame():
for widget in results_frame.winfo_children():
widget.destroy()
results_label = Label(results_frame, text = f"Your score: {score} / {MAX_SCORE}", font = ('Arial', 20), fg = 'white', bg = 'gray12', pady = 40)
results_label.pack(anchor = CENTER)
button = Button(results_frame, text = 'Back to main menu', font = ('Arial', 24), fg = 'white', bg = 'SpringGreen2', padx = 20, pady = 20, command = reset_quiz)
button.pack(anchor = CENTER, pady = (60,0))
def reset_quiz():
global questions, score, answer_selected
questions = random.sample(list(QUESTIONS.items()), 10)
score = 0
answer_selected = None
display_frame(welcome_frame)
# Main app window
master = Tk()
master.title('QuizApp')
master.config(bg = 'gray12')
# Container for all frames
container = Frame(master, bg = 'gray12')
container.pack(fill = BOTH, expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
welcome_frame = create_welcome_frame()
quiz_frame = create_quiz_frame()
results_frame = create_results_frame()
display_frame(welcome_frame)
master.mainloop()
Я попытался исправить это с помощью Я попробовал закрыть и открыть VSCode.
после применения решения Шарима у меня нет ошибок ни в этом вопросе, ни в любом другом вопросе, это должно быть Токио
Проблема в вашей функции generate_quiz()
, вы написали в этой функции эту строку кода, чтобы перетасовать ответы.
random.shuffle(answers)
Теперь проблема возникает из-за того, что природа списка изменчива, а это означает, что даже если вы обновите список с помощью другой функции, он обновится в исходном месте.
Это означает, что это обновит список answers
, который есть в вашем QUESTIONS
словаре.
Таким образом, из-за этого впервые у вас будут правильные ответы, потому что вы получите их до выполнения этой строки, но в следующем раунде правильные ответы будут перемешиваться в списке.
Таким образом, вместо того, чтобы использовать исходный список для перетасовки, вы можете перетасовать копию ответов, чтобы она обновляла ответы только в скопированном списке, а не в исходном месте.
Для этого вы можете использовать метод .copy()
.
def generate_quiz():
global questions, answer_selected
if questions:
global question
question, answers = questions.pop(0)
answers = answers.copy() # Copy the original list
correct_answer = answers[0]
question_label = Label(quiz_frame, text = question, font = ('Arial', 25), fg = 'white', bg = 'gray12', pady = 40)
question_label.pack(anchor = W, padx = (200, 0))
random.shuffle(answers)
for answer in answers:
answer_selected = False
answer_button = Button(quiz_frame, text = answer, width = 30, pady = 17, font = ('Arial', 19), command = lambda chosen_answer = answer: display_quiz_message(chosen_answer, correct_answer))
answer_button.pack(anchor = W, padx = (200, 0), pady = 10)
else:
display_frame(results_frame)
update_results_frame()
answers = answers[:]
Итак, для этого мы можем использовать метод deepcopy() из библиотеки под названием copy
.
Вот как это сделать
from copy import deepcopy
...
def generate_quiz():
global questions, answer_selected
if questions:
global question
question, answers = deepcopy(questions.pop(0)) # copy the whole question
correct_answer = answers[0]
question_label = Label(quiz_frame, text = question, font = ('Arial', 25), fg = 'white', bg = 'gray12', pady = 40)
question_label.pack(anchor = W, padx = (200, 0))
random.shuffle(answers)
for answer in answers:
answer_selected = False
answer_button = Button(quiz_frame, text = answer, width = 30, pady = 17, font = ('Arial', 19), command = lambda chosen_answer = answer: display_quiz_message(chosen_answer, correct_answer))
answer_button.pack(anchor = W, padx = (200, 0), pady = 10)
else:
display_frame(results_frame)
update_results_frame()
...
О чувак, спасибо, что помог мне, работает отлично! Вы сэкономили мне много времени, когда я беспомощно пытался разобраться в проблеме, ха-ха. Я не знал о глубокой копии или о том, что копирование словаря по-прежнему будет копировать ссылку на значение списка вместо значения.
Помимо ответа Шарима09, который объяснил вашу проблему, есть еще один способ — использовать функцию перемешивания, которая не меняет список на месте: random.sample()
которую вы уже использовали для случайного выбора 10 вопросов.
Просто замените следующую строку
random.shuffle(answers)
к
answers = random.sample(answers, len(answers))
в чем разница между обеими строками? изменяет ли перемешивание список, а образец - нет?
Да, sample()
не изменяет список, а вместо этого возвращает новый список.
У меня все еще есть проблема: какая столица Японии. Я выбрал Токио. И получил неправильный ответ и так далее.