Как устроен тренажёр для решения задач по Python
Основные принципы построения тренажера
Как сделать простой тренажер математических задач с проверкой ответа?
Наиболее эффективный способ - написать скрипт, который генерирует случайное выражение, выводит его пользователю и сравнивает введенный ответ с правильным. Такой подход позволяет быстро проверить понимание базовых операций и арифметики.
import random
def generate_task():
a = random.randint(1, 10)
b = random.randint(1, 10)
op = random.choice(['+', '-', '*'])
task = f"{a} {op} {b}"
answer = eval(task) # только для демонстрации, eval опасен
return task, answer
def main():
score = 0
for _ in range(5):
task, correct = generate_task()
print(f"Решите: {task}")
try:
user_input = input("Ваш ответ: ")
user_answer = float(user_input)
if abs(user_answer - correct) < 0.001:
print("Верно!")
score += 1
else:
print(f"Неверно, правильный ответ: {correct}")
except ValueError:
print("Ошибка: введите число")
print(f"Итоговый счёт: {score}/5")
if __name__ == "__main__":
main()тренажер задач python (тренажер задач по python)
Пояснение: в цикле генерируются 5 примеров. Ответ проверяется с плавающей точкой через сравнение модуля разности. Обрабатывается исключение, если пользователь вводит не число.
Типичные проблемы и ошибки:
- Использование eval() небезопасно - злоумышленник может ввести вредоносный код. Для учебного тренажера допустимо, но лучше заменить на безопасный калькулятор (например, разбор выражения вручную).
- Сравнение чисел с плавающей точкой через == приводит к ошибкам из-за погрешности. Правильно использовать модуль разности с эпсилон.
- Пользователь может ввести пустую строку - тогда float() вызовет ошибку. Нужна обработка ValueError.
Как добавить выбор темы задач?
Позволяет пользователю тренировать разные разделы: математика, строки, списки. Для этого вводится словарь с функциями генерации заданий.
import random
def math_task():
a, b = random.randint(1,20), random.randint(1,20)
op = random.choice(['+','-'])
return f"{a} {op} {b}", eval(f"{a}{op}{b}")
def string_task():
word = random.choice(['hello','python','code'])
return f"Сколько букв в слове '{word}'?", len(word)
def list_task():
lst = [random.randint(0,100) for _ in range(5)]
correct = sum(lst)
return f"Сумма чисел {lst}", correct
functions = {
'1': math_task,
'2': string_task,
'3': list_task
}
print("Выберите тему: 1 - математика, 2 - строки, 3 - списки")
choice = input()
task_func = functions.get(choice)
if not task_func:
print("Неверный выбор")
else:
task, correct = task_func()
print(task)
try:
ans = float(input())
print("Верно" if abs(ans-correct)<0.001 else f"Неверно, ответ {correct}")
except ValueError:
print("Ошибка ввода")Такой тренажер легко расширяется новыми темами - достаточно добавить функцию в словарь.
Ошибочно предполагать, что input() всегда возвращает число. Без обработки исключения программа упадет при вводе букв.
Как добавить таймер для ограничения времени?
Модуль time позволяет засекать время выполнения одной задачи или всей сессии. Пользователь может ставить личный рекорд.
import random, time
task, correct = random.randint(1,100)*2, random.randint(1,100)*2 # пример
time_limit = 10 # секунд
start = time.time()
print("Решите пример за 10 секунд:", task)
user = input()
elapsed = time.time() - start
if elapsed > time_limit:
print("Время вышло!")
else:
try:
if float(user) == correct:
print("Верно!")
else:
print("Неверно")
except:
print("Ошибка ввода")Для реального тренажера лучше использовать асинхронный таймер или многопоточность, но для консоли простой замер времени подходит.
Ошибка: если пользователь не вводит ответ, программа ждет бесконечно. Таймер не прерывает input(). Нужен другой подход (например, модуль threading).
Как сохранять прогресс пользователя?
Запись результатов в файл JSON или CSV позволяет анализировать успехи со временем. Файл обновляется после каждой попытки.
import json, os
STATS_FILE = 'progress.json'
def load_stats():
if os.path.exists(STATS_FILE):
with open(STATS_FILE, 'r') as f:
return json.load(f)
return {'attempts': 0, 'correct': 0}
def save_stats(stats):
with open(STATS_FILE, 'w') as f:
json.dump(stats, f)
stats = load_stats()
stats['attempts'] += 1
# ... симуляция проверки
correct = True # замените на реальную проверку
if correct:
stats['correct'] += 1
save_stats(stats)
print(f"Статистика: {stats['correct']}/{stats['attempts']} верных")Файл progress.json будет лежать рядом со скриптом и накапливать историю.
Если файл поврежден, загрузка вызовет ошибку. Стоит добавить try-except при чтении.
Расширенные примеры тренажеров
Тренажер с чтением задач из внешнего JSON
Позволяет менять задания без изменения кода. Создадим файл tasks.json с набором вопросов и ответов.
# tasks.json
[
{
"question": "Что выведет print(2**3)?",
"answer": "8"
},
{
"question": "Какой тип данных у '123'?",
"answer": "str"
}
]import json
def load_tasks(filename):
with open(filename, 'r', encoding='utf-8') as f:
return json.load(f)
def run_quiz(tasks):
score = 0
for i, task in enumerate(tasks, 1):
print(f"{i}. {task['question']}")
user = input("Ответ: ").strip().lower()
correct = task['answer'].strip().lower()
if user == correct:
print("Верно")
score += 1
else:
print(f"Неверно, правильный ответ: {task['answer']}")
print(f"Итог: {score}/{len(tasks)}")
if __name__ == '__main__':
tasks = load_tasks('tasks.json')
run_quiz(tasks)Результат выполнения (при условии, что файл tasks.json подготовлен):
1. Что выведет print(2**3)? Ответ: 8 Верно 2. Какой тип данных у '123'? Ответ: str Верно Итог: 2/2
Ошибка: несовпадение регистра или лишние пробелы. В примере используется lower() и strip() для обеих сторон.
Тренажер с графическим интерфейсом на tkinter
Простое окно с кнопкой «Проверить» и полем ввода. Сложность - синхронизация таймера и обновления виджетов.
import tkinter as tk
import random
class App:
def __init__(self, master):
self.master = master
master.title("Тренажёр")
self.label = tk.Label(master, text="")
self.label.pack()
self.entry = tk.Entry(master)
self.entry.pack()
self.button = tk.Button(master, text="Проверить", command=self.check)
self.button.pack()
self.result = tk.Label(master, text="")
self.result.pack()
self.new_task()
def new_task(self):
a = random.randint(10,99)
b = random.randint(10,99)
self.answer = a + b
self.label.config(text=f"{a} + {b} = ?")
self.entry.delete(0, tk.END)
def check(self):
try:
user = float(self.entry.get())
if abs(user - self.answer) < 0.01:
self.result.config(text="Верно!", fg="green")
else:
self.result.config(text=f"Неверно, ответ {self.answer}", fg="red")
except ValueError:
self.result.config(text="Введите число", fg="orange")
self.master.after(1000, self.new_task)
root = tk.Tk()
app = App(root)
root.mainloop()Результат:
Открывается окно с примером, после ввода ответа и нажатия кнопки выводится результат, через 1 секунду появляется новый пример.
Проблема: после ввода неверного ответа окно не блокируется. Можно добавить счётчик попыток.
Тренажер с адаптивной сложностью
Алгоритм подстраивает уровень сложности на основе предыдущих ответов. Если пользователь отвечает верно, сложность растёт, если неверно - падает.
import random
difficulty = 1 # от 1 до 5
correct_streak = 0
def generate_task(diff):
if diff == 1:
a,b = random.randint(1,10), random.randint(1,10)
op = '+'
elif diff == 2:
a,b = random.randint(1,20), random.randint(1,20)
op = random.choice(['+','-'])
elif diff == 3:
a,b = random.randint(1,30), random.randint(1,30)
op = random.choice(['+','-','*'])
# ... продолжить для 4,5
return f"{a} {op} {b}", eval(f"{a}{op}{b}")
for _ in range(10):
task, correct = generate_task(difficulty)
print(f"Сложность {difficulty}: {task}")
user = input("Ответ: ")
try:
if abs(float(user) - correct) < 0.01:
print("Правильно")
correct_streak += 1
if correct_streak >= 3 and difficulty < 5:
difficulty += 1
correct_streak = 0
else:
print("Неправильно")
correct_streak = 0
if difficulty > 1:
difficulty -= 1
except ValueError:
print("Ошибка ввода")Вывод (пример):
Сложность 1: 3 + 5 Ответ: 8 Правильно Сложность 1: 7 + 2 Ответ: 9 Правильно Сложность 2: 15 - 6 Ответ: 9 Правильно ...
Ошибка: если пользователь вводит не число, correct_streak не сбрасывается. Лучше обнулять его и при ошибке ввода.