Обучающий телеграм бот. Пример задачника по математике

Технология телеграм бота подкупила меня своей универсальностью. Можно использовать в телеграмм, можно просто в браузере, можно формировать любую логику работы… Сегодня рассмотрим вариант телеграм бота, представляющего собой фрагмент задачника по математике для 4 класса. Почему так все заморочено, просто ребенок учится в 4 классе и активно юзает телегу.

Начнем. В телеге запускаем бота BotFether, регистрируем новое имя бота. Имя и токен бота будут нам всегда доступны в BotFether.

Затем на комп накатываем Питон, PyCharm. Проверяем, что они видят друг друга и накатываем модуль telebot. Данные действия привожу в хронологическом порядке, более подробно можно найти данную информацию в нете.

Выбираем классическую задачу из учебника.

Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля составляет 57,8 км/час. Скорость второго автомобиля — 63,5 км/час. Через сколько часов расстояние между ними будет составлять 363,9 км?

Отлично. Из этой задачи можно сформулировать 4 задачи с определением различных параметров: скорость первого автомобиля, скорость второго автомобиля, время и расстояние.

При этом часть числовых значений делаем рандомными, а путь всегда просчитываем. Немного переформулируем задачу и получим на Питоне вот такой исходник.

    users[message.from_user.id]['v1'] = random.randint(50, 90)
    users[message.from_user.id]['v2'] = random.randint(50, 90)
    users[message.from_user.id]['t'] = random.randint(2, 7)
    users[message.from_user.id]['S'] = (users[message.from_user.id]['v1'] + users[message.from_user.id]['v2']) * users[message.from_user.id]['t']
    users[message.from_user.id]['mode'] = random.randint(1, 4)
    if users[message.from_user.id]['mode'] == 1:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля " + str(users[message.from_user.id]['v1']) + " км/ч. Скорость второго " + str(users[message.from_user.id]['v2']) + " км/ч. Через сколько часов расстояние между ними будет составлять " + str(users[message.from_user.id]['S']) + " км?"
    elif users[message.from_user.id]['mode'] == 2:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля " + str(users[message.from_user.id]['v1']) + " км/ч. Скорость второго " + str(users[message.from_user.id]['v2']) + " км/ч. Какое расстояние будет между ними через " + str(users[message.from_user.id]['t']) + " ч?"
    elif users[message.from_user.id]['mode'] == 3:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля " + str(users[message.from_user.id]['v1']) + " км/ч. Через " + str(users[message.from_user.id]['t']) + " ч расстояние между ними было " + str(users[message.from_user.id]['S']) + " км. Определите скорость второго автомобиля."
    else:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость второго автомобиля " + str(users[message.from_user.id]['v2']) + " км/ч. Через " + str(users[message.from_user.id]['t']) + " ч расстояние между ними было " + str(users[message.from_user.id]['S']) + " км. Определите скорость первого автомобиля."
    bot.send_message(message.chat.id, a)
    bot.send_message(message.chat.id, "Введите ответ")

При этом в строке 5 выберим вариант вопроса.

Обработаем введенный ответ от ученика.

    if users[message.from_user.id]['mode'] > 0:
        if is_number(message.text)==True:
            if users[message.from_user.id]['mode']==1:
                if users[message.from_user.id]['t'] == int(message.text):
                    zapis(True,message.from_user.id,users[message.from_user.id]['mode'])
                else:
                    zapis(False,message.from_user.id,users[message.from_user.id]['mode'])
            elif users[message.from_user.id]['mode']==2:
                if users[message.from_user.id]['S'] == int(message.text):
                    zapis(True,message.from_user.id,users[message.from_user.id]['mode'])
                else:
                    zapis(False, message.from_user.id, users[message.from_user.id]['mode'])
            elif users[message.from_user.id]['mode']==3:
                if users[message.from_user.id]['v2'] == int(message.text):
                    zapis(True, message.from_user.id, users[message.from_user.id]['mode'])
                else:
                    zapis(False,message.from_user.id,users[message.from_user.id]['mode'])
            else:
                if users[message.from_user.id]['v1'] == int(message.text):
                    zapis(True, message.from_user.id, users[message.from_user.id]['mode'])
                else:
                    zapis(False, message.from_user.id, users[message.from_user.id]['mode'])

При этом не забываем проверять, что введенный ответ является цифрой.

def is_number(s):
    """ Функция проверки ввода на число """
    try:
        float(s)
        return True
    except ValueError:
        return False

Обозначенная ранее функция zapis осуществляет вывод сообщения о правильности ответа и запись в файл для учителя.

def zapis(r,id,md):
    if r==True:
        stroka="Правильно"
        bot.send_message(id, "Правильно.")
    else:
        stroka = "Неправильно"
        bot.send_message(id, "Неправильно.")
    f = open('result.txt', 'a', encoding='utf-8')
    f.write(users[id]['name'] + "  "+str(md)+"  "+stroka+'\n')
    f.close()

Для определения кому какой результат принадлежит, просим ученика ввести имя и сопоставляем его с числовым идентификатором при старте бота.

@bot.message_handler(commands=['start'])
def start_message(message):
    global chet
    users.setdefault(message.from_user.id, {'v1': 0,
                                            'v2': 0,
                                            't': 0,
                                            'name': "",
                                            'mode': 0,
                                            'S': 0})
    # Создание reply кнопки 'Меню'
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    btn = types.KeyboardButton("Новая задача")
    markup.add(btn)
    bot.send_message(message.chat.id, "Введите имя",
                     reply_markup=markup)
    chet = 1
 if message.text!="password" and is_number(message.text)==False and chet==1:
        users[message.from_user.id]['name']=message.text
        chet=0
        bot.send_message(message.chat.id, "Нажмите 'Новая задача'")

Запускаем бота. Вводим имя, кликаем кнопку Новая задача. Вводи неправиоьный ответ, вводим правильный ответ.

da197af3fe20dec9a20c874d1a9b2ca4.jpg

Все работает. Пробуем генерить новые задачи.

55caad5f164ec9f00b7cc72e5fab5be0.jpg

Все верно. Каждый раз новые задачи. Добавляем учителю возможность выгрузки файла с результатами и его очистку.

    if message.text =="password":
        file = open("./result.txt", "rb")
        bot.send_document(message.chat.id, file)

    if message.text =="pass_del":
        f = open('result.txt', 'w', encoding='utf-8')
        f.write("Результаты решения задач:"+'\n')
        f.close()
        bot.send_message(message.chat.id, "Данные удалены")

Пробуем.

d9f4b376c12007913a6750ca69eaa361.jpg

Файл с результатами выгружается по нашему паролю.

81a51ec44297643c0f68e6b18f9669c7.jpg

Теперь у нас есть работающий бот с вариативной задачей под весь класс. При этом данная технология позволит работать с телеграм ботом одновременно всему классу. Есть механизм выгрузки результатов. Подобным образом можно перерабатывать практически любой учебным материал. Вариативность заданий не позволит списывать друг у друга, и проверка правильности уже автоматизирована. Ниже представлен весь исходник главного файла.

import telebot  # Импортируем telebot
from secrets import secrets  # Словарь с токеном из файла secrets.py
from users import users  # Импортируем словарь для работы нескольких пользователей одновременно
from telebot import types  # для указания типов
from inline import del_inline  # для работы функции удаления предыдущего сообщения inline
import time
import random

# передаём значение переменной с кодом экземпляру бота
token = secrets.get('BOT_API_TOKEN')
bot = telebot.TeleBot(token)


def is_number(s):
    """ Функция проверки ввода на число """
    try:
        float(s)
        return True
    except ValueError:
        return False


# хендлер и функция для обработки команды /start
@bot.message_handler(commands=['start'])
def start_message(message):
    global chet
    users.setdefault(message.from_user.id, {'v1': 0,
                                            'v2': 0,
                                            't': 0,
                                            'name': "",
                                            'mode': 0,
                                            'S': 0})
    # Создание reply кнопки 'Меню'
    markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
    btn = types.KeyboardButton("Новая задача")
    markup.add(btn)
    bot.send_message(message.chat.id, "Введите имя",
                     reply_markup=markup)
    chet = 1

def zapis(r,id,md):
    if r==True:
        stroka="Правильно"
        bot.send_message(id, "Правильно.")
    else:
        stroka = "Неправильно"
        bot.send_message(id, "Неправильно.")
    f = open('result.txt', 'a', encoding='utf-8')
    f.write(users[id]['name'] + "  "+str(md)+"  "+stroka+'\n')
    f.close()

@bot.message_handler(content_types=["text"])
def text(message):
    global chet     # Для работы возможности выбора только одной операции в один момент времени (Калькулятор или список продуктов)
    if message.text == "Новая задача":  # При поступлении сообщения 'Меню' в чат
        menu(message)   # Вызов функции меню

    if message.text!="password" and is_number(message.text)==False and chet==1:
        users[message.from_user.id]['name']=message.text
        chet=0
        bot.send_message(message.chat.id, "Нажмите 'Новая задача'")

    if message.text =="password":
        file = open("./result.txt", "rb")
        bot.send_document(message.chat.id, file)

    if message.text =="pass_del":
        f = open('result.txt', 'w', encoding='utf-8')
        f.write("Результаты решения задач:"+'\n')
        f.close()
        bot.send_message(message.chat.id, "Данные удалены")

    if users[message.from_user.id]['mode'] > 0:
        if is_number(message.text)==True:
            if users[message.from_user.id]['mode']==1:
                if users[message.from_user.id]['t'] == int(message.text):
                    zapis(True,message.from_user.id,users[message.from_user.id]['mode'])
                else:
                    zapis(False,message.from_user.id,users[message.from_user.id]['mode'])
            elif users[message.from_user.id]['mode']==2:
                if users[message.from_user.id]['S'] == int(message.text):
                    zapis(True,message.from_user.id,users[message.from_user.id]['mode'])
                else:
                    zapis(False, message.from_user.id, users[message.from_user.id]['mode'])
            elif users[message.from_user.id]['mode']==3:
                if users[message.from_user.id]['v2'] == int(message.text):
                    zapis(True, message.from_user.id, users[message.from_user.id]['mode'])
                else:
                    zapis(False,message.from_user.id,users[message.from_user.id]['mode'])
            else:
                if users[message.from_user.id]['v1'] == int(message.text):
                    zapis(True, message.from_user.id, users[message.from_user.id]['mode'])
                else:
                    zapis(False, message.from_user.id, users[message.from_user.id]['mode'])
@bot.message_handler(content_types=["text"])
def menu(message):
    """
    Функция вызова меню с выбором inline кнопок
    """
    users[message.from_user.id]['v1'] = random.randint(50, 90)
    users[message.from_user.id]['v2'] = random.randint(50, 90)
    users[message.from_user.id]['t'] = random.randint(2, 7)
    users[message.from_user.id]['S'] = (users[message.from_user.id]['v1'] + users[message.from_user.id]['v2']) * users[message.from_user.id]['t']
    users[message.from_user.id]['mode'] = random.randint(1, 4)
    if users[message.from_user.id]['mode'] == 1:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля " + str(users[message.from_user.id]['v1']) + " км/ч. Скорость второго " + str(users[message.from_user.id]['v2']) + " км/ч. Через сколько часов расстояние между ними будет составлять " + str(users[message.from_user.id]['S']) + " км?"
    elif users[message.from_user.id]['mode'] == 2:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля " + str(users[message.from_user.id]['v1']) + " км/ч. Скорость второго " + str(users[message.from_user.id]['v2']) + " км/ч. Какое расстояние будет между ними через " + str(users[message.from_user.id]['t']) + " ч?"
    elif users[message.from_user.id]['mode'] == 3:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость первого автомобиля " + str(users[message.from_user.id]['v1']) + " км/ч. Через " + str(users[message.from_user.id]['t']) + " ч расстояние между ними было " + str(users[message.from_user.id]['S']) + " км. Определите скорость второго автомобиля."
    else:
        a = "Из города в противоположных направлениях выехали два автомобиля. Скорость второго автомобиля " + str(users[message.from_user.id]['v2']) + " км/ч. Через " + str(users[message.from_user.id]['t']) + " ч расстояние между ними было " + str(users[message.from_user.id]['S']) + " км. Определите скорость первого автомобиля."
    bot.send_message(message.chat.id, a)
    bot.send_message(message.chat.id, "Введите ответ")

# бесконечное выполнение кода
while True:
    try:
      bot.polling(none_stop=True, interval=0)
    except:
      continue
#bot.polling(none_stop=True, interval=0)

© Habrahabr.ru