/
shotus
/
Practice_2026
Обзор
Документация
Войти
/
shotus
/
Practice_2026
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/bot.py
403 строки
19 KB
shotus
create: bot_guide.md, bot.py
24 май 2026, 04:40
Верифицирован
24 май 2026, 04:40
05eaf39
Код
Авторство
О чём код?
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import Application, CommandHandler, CallbackQueryHandler, ContextTypes # конфигурация TOKEN = "8823016359:AAEwSgdeej72-EBVmtxFrtBPxAHz_XJTbmc" # токен # за каждые 3 правильных ответа даём 1 медальку CORRECT_ANSWERS_PER_MEDAL = 3 # 15 задачек QUEST = { 1: { "question": "Программист написал алгоритм для заваривания чая: «1. Налить воду. 2. Вскипятить. 3. Положить пакетик. 4. Налить воду в чашку». Робот-исполнитель сломался на шаге 4, потому что вода уже закончилась. Какое программистское правило нарушено?", "options": [ "Бесконечный цикл", "Жесткая перезапись переменной", "Неверный порядок действий", "Отсутствие интернета" ], "correct": 2 }, 2: { "question": "Создатели языков программирования часто вдохновляются окружающим миром: одни названия связаны с опасными змеями, другие — с островами и кофе, а третьи — с драгоценными камнями. Какого «языка» из этого списка не существует в реальности?", "options": ["Python", "Ruby", "Kryptonite", "Java"], "correct": 2 }, 3: { "question": "Петя решил создать самый надежный пароль в мире. Он взял слово Password и повторил его 10000 раз. Почему этот пароль плохой с точки зрения кибербезопасности?", "options": [ "Его слишком долго вводить", "Компьютер запутается в буквах", "В нем легко найти закономерность", "Он занимает много места" ], "correct": 2 }, 4: { "question": "Робот-пылесос запрограммирован так: «Если видишь стену — поверни на 90 градусов направо». Он заехал в квадратную комнату-коробку и бесконечно крутится в одном углу. Что произошло в его коде?", "options": [ "Зацикливание", "Перегрев процессора", "Он ищет Wi-Fi", "Сбой оперативной памяти" ], "correct": 0 }, 5: { "question": "Вам нужно найти слово по маске *о*а. Звезда (*) заменяет любое количество букв (даже ноль). Какое из этих слов не подходит под это правило?", "options": ["Роза", "Корова", "Крошка", "Окно"], "correct": 3 }, 6: { "question": "У вас есть «черный ящик». Если отправить туда число 3, на выходе будет 9. Если отправить 5, на выходе 25. Если отправить 2, на выходе 4. Что выдаст ящик, если отправить туда -4?", "options": ["-16", "16", "0", "Ошибку SyntaxError"], "correct": 1 }, 7: { "question": "Вы заархивировали папку с фотографиями в .zip, а потом заархивировали этот .zip еще раз, и так 5 раз подряд. Что произошло с размером итогового файла?", "options": [ "Он уменьшился в 5 раз", "Он стал равен нулю", "После 1-го раза размер почти не менялся", "Компьютер взорвался от мощности" ], "correct": 2 }, 8: { "question": "База данных ищет студентов по условию: (Класс == 9) И (Спортсмен == Истина). Какого студента найдет система?", "options": [ "Десятиклассника-футболиста", "Девятиклассника, который не любит спорт", "Девятиклассника-баскетболиста", "Любого школьника 9 класса" ], "correct": 2 }, 9: { "question": "Условие для открытия двери звучит так: НЕ (Дверь заперта ИЛИ Ключ потерян). В каком случае дверь откроется?", "options": [ "Дверь не заперта, и ключ на месте", "Дверь заперта, но ключ на месте", "Дверь не заперта, но ключ потерян", "Дверь заперта, и ключ потерян" ], "correct": 0 }, 10: { "question": "Инструмент «Зеркало» в графическом редакторе переворачивает картинку слева направо. Что произойдет, если применить этот инструмент к картинке 2026 раз?", "options": [ "Картинка вернется в исходный вид", "Картинка останется перевернутой", "Картинка сотрется", "Картинка повернется на 90 градусов" ], "correct": 0 }, 11: { "question": "Если дать калькулятору задачу разделить 5 на 0, он выдаст ошибку. Почему?", "options": [ "Ноль слишком маленький", "Калькулятор считает только единицы", "Деление на ноль не определено", "Закончится заряд батарейки" ], "correct": 2 }, 12: { "question": "Алиса зашифровала слово, сдвинув каждую букву в алфавите на 1 позицию вперед (А→Б, Б→В...). Получилось слово «Лпу». Какое слово было изначально?", "options": ["Мув", "Кот", "Лук", "Пес"], "correct": 1 }, 13: { "question": "Вы скопировали текст «Привет». Потом скопировали текст «Пока». Потом нажали Ctrl+Z. Что вставится, если теперь нажать Ctrl+V?", "options": ["Привет", "Пока", "Ничего", "ПриветПока"], "correct": 1 }, 14: { "question": "Вы архивируете текст, где слово «информатика» повторяется 1000 раз. Архиватор заменяет каждое такое слово на короткий символ @ и сохраняет «словарь». Почему этот архив весит меньше оригинала?", "options": [ "Повторы заменены короткими кодами", "Архиватор удаляет буквы наугад", "Текст физически сжимается на диске", "Символ @ весит меньше букв" ], "correct": 0 }, 15: { "question": "Раньше на компьютерах экономили память и записывали год двумя цифрами (например, 98 вместо 1998). К какому логическому сбою это привело в 2000 году?", "options": [ "Компьютеры решили, что наступил 2200", "Компьютеры решили, что снова 1900", "Календарь просто остановился", "Все файлы переименовались в ноль" ], "correct": 1 } } # хранилище прогресса пользователей user_progress = {} def calculate_medals(correct_answers): """Конвертирует количество правильных ответов в медальки""" return correct_answers // CORRECT_ANSWERS_PER_MEDAL def get_medal_display(medals): """Отображение медалек""" if medals >= 5: return "🏅🏅🏅 " + "🏅" * min(medals, 10) elif medals >= 2: return "🏅🏅 " + "🏅" * medals elif medals >= 1: return "🏅 " + "🏅" * medals else: return "⚪️ 0 медалек" async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id username = update.effective_user.username or "Игрок" user_progress[user_id] = { "current": 1, "score": 0, "correct_count": 0, "medals": 0, "completed": False, "username": username } await update.message.reply_text( f"🎮 <b>Привет, {username}!</b>\n\n" "Добро пожаловать в <b>IT-квест</b> от Московского Политеха!\n\n" "<b>📋 Правила:</b>\n" f"• Всего вопросов: {len(QUEST)}\n" "• За каждый правильный ответ — <b>10 баллов</b>\n" f"• За каждые {CORRECT_ANSWERS_PER_MEDAL} правильных ответа — <b>1 монетка</b> 🏅\n\n" "💡 <b>Что делать с монетками?</b>\n" "Монетки можно обменять на призы в магазине!\n\n" "👇 <b>Поехали!</b> 👇", parse_mode="HTML" ) await send_question(update.effective_chat.id, context, 1) async def send_question(chat_id, context, task_num): """Отправляет вопрос с кнопками-ответами""" q = QUEST[task_num] keyboard = [] for i, option in enumerate(q["options"]): keyboard.append([InlineKeyboardButton(option, callback_data=f"answer_{task_num}_{i}")]) keyboard.append([InlineKeyboardButton("📊 Моя статистика", callback_data="stats")]) keyboard.append([InlineKeyboardButton("🏁 Завершить квест", callback_data="finish")]) reply_markup = InlineKeyboardMarkup(keyboard) await context.bot.send_message( chat_id=chat_id, text=f"<b>Вопрос {task_num}/{len(QUEST)}</b>\n\n{q['question']}", parse_mode="HTML", reply_markup=reply_markup ) async def show_stats(update: Update, context: ContextTypes.DEFAULT_TYPE, user_id): """Показывает статистику""" state = user_progress[user_id] correct = state["correct_count"] total_questions = len(QUEST) earned = calculate_medals(correct) next_at = (earned + 1) * CORRECT_ANSWERS_PER_MEDAL need_for_next = max(1, next_at - correct) if correct < total_questions else 0 progress_in_group = correct % CORRECT_ANSWERS_PER_MEDAL bar = "⬜" * progress_in_group + "⬛" * (CORRECT_ANSWERS_PER_MEDAL - progress_in_group) stats_text = ( f"<b>📊 Твоя статистика</b>\n\n" f"🎯 Пройдено вопросов: {state['current'] - 1} из {total_questions}\n" f"✅ Правильных ответов: {correct} из {state['current'] - 1}\n" f"⭐️ Баллов: <b>{state['score']}</b> из {total_questions * 10}\n" f"🏅 Монеток: <b>{state['medals']}</b>\n\n" f"💰 До следующей монетки: {need_for_next} правильных ответ(а)\n" f"{bar}" ) keyboard = [[InlineKeyboardButton("🔙 Вернуться к вопросу", callback_data="back")]] reply_markup = InlineKeyboardMarkup(keyboard) if update.callback_query: await update.callback_query.edit_message_text(stats_text, parse_mode="HTML", reply_markup=reply_markup) else: await update.message.reply_text(stats_text, parse_mode="HTML", reply_markup=reply_markup) async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query await query.answer() user_id = query.from_user.id data = query.data if user_id not in user_progress or user_progress[user_id]["completed"]: await query.edit_message_text("Квест не начат. Напиши /start!") return state = user_progress[user_id] if data == "stats": await show_stats(update, context, user_id) return if data == "back": await send_question(update.effective_chat.id, context, state["current"]) return if data == "finish": await finish_quest(query, context, user_id) return if data.startswith("answer_"): parts = data.split("_") task_num = int(parts[1]) selected_idx = int(parts[2]) if task_num != state["current"]: await query.edit_message_text("Отвечай на текущий вопрос!") await send_question(update.effective_chat.id, context, state["current"]) return q = QUEST[task_num] is_correct = (selected_idx == q["correct"]) old_medals = state["medals"] if is_correct: state["score"] += 10 state["correct_count"] += 1 new_medals = calculate_medals(state["correct_count"]) state["medals"] = new_medals medal_earned = new_medals - old_medals msg = f"✅ <b>Правильно!</b> +10 баллов\n📊 <b>Баллов:</b> {state['score']}\n🎯 <b>Правильных ответов:</b> {state['correct_count']}\n🏅 <b>Монеток:</b> {state['medals']}" if medal_earned > 0: msg += f"\n\n🎉 <b>Ты получил {medal_earned} монетку!</b> 🎉" await query.edit_message_text(msg, parse_mode="HTML") state["current"] += 1 if state["current"] > len(QUEST): await finish_quest(query, context, user_id) else: await send_question(update.effective_chat.id, context, state["current"]) else: correct_option = q["options"][q["correct"]] await query.edit_message_text( f"❌ <b>Неправильно!</b>\n\n" f"Правильный ответ: <b>{correct_option}</b>\n\n" f"⭐️ <b>Баллов:</b> {state['score']}\n" f"🏅 <b>Монеток:</b> {state['medals']}\n\n" f"➡️ Следующий вопрос!", parse_mode="HTML" ) state["current"] += 1 if state["current"] > len(QUEST): await finish_quest(query, context, user_id) else: await send_question(update.effective_chat.id, context, state["current"]) async def finish_quest(query, context, user_id): state = user_progress[user_id] state["completed"] = True total = len(QUEST) * 10 percent = int((state["score"] / total) * 100) if total > 0 else 0 max_medals = len(QUEST) // CORRECT_ANSWERS_PER_MEDAL if percent >= 80: grade = "🏆 <b>Отлично! Ты настоящий знаток IT!</b>" elif percent >= 60: grade = "🎉 <b>Хороший результат!</b>" elif percent >= 40: grade = "👍 <b>Неплохо! Приходи на наши мастер-классы!</b>" else: grade = "💪 <b>Хорошая попытка! В следующий раз будет лучше!</b>" medal_display = get_medal_display(state["medals"]) await query.edit_message_text( f"🎓 <b>Квест пройден!</b> 🎓\n\n" f"{grade}\n\n" f"<b>📊 Твой результат:</b>\n" f"• Баллы: {state['score']} из {total}\n" f"• Процент: {percent}%\n" f"• Правильных ответов: {state['correct_count']} из {len(QUEST)}\n\n" f"<b>🏅 Монетки:</b> {state['medals']} из {max_medals}\n" f"<b>✨ Что дальше?</b>\n" f"• 🏅 Обменяй монетки на призы в магазине!\n\n" f"• 📚 Запишись на наши мастер-классы\n" f"• 🔄 Напиши /reset, чтобы пройти квест заново\n\n" f"🤖 <b>Бот создан командой наставников Московского Политеха</b>", parse_mode="HTML" ) async def stats_command(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id if user_id not in user_progress or user_progress[user_id]["completed"]: await update.message.reply_text("Напиши /start, чтобы начать квест!") return await show_stats(update, context, user_id) async def reset(update: Update, context: ContextTypes.DEFAULT_TYPE): user_id = update.effective_user.id if user_id in user_progress: del user_progress[user_id] await update.message.reply_text( "🔄 <b>Прогресс сброшен!</b>\nНапиши /start, чтобы начать квест заново.", parse_mode="HTML" ) async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE): await update.message.reply_text( "<b>📖 Справка по боту</b>\n\n" "/start — начать квест\n" "/stats — показать мою статистику\n" "/reset — сбросить прогресс\n" "/help — эта справка\n\n" f"🎮 <b>Правила:</b> {len(QUEST)} вопросов, за правильный ответ — 10 баллов.\n" f"🏅 За каждые {CORRECT_ANSWERS_PER_MEDAL} правильных ответа — 1 монетка.\n\n" f"🏆 <b>Призы:</b> обменяй монетки на сувениры в магазине!", parse_mode="HTML" ) def main(): app = Application.builder().token(TOKEN).build() app.add_handler(CommandHandler("start", start)) app.add_handler(CommandHandler("stats", stats_command)) app.add_handler(CommandHandler("reset", reset)) app.add_handler(CommandHandler("help", help_command)) app.add_handler(CallbackQueryHandler(button_callback)) print("🤖 Бот запущен!") print(f"📊 Всего вопросов: {len(QUEST)}") print(f"🏅 Монетка за {CORRECT_ANSWERS_PER_MEDAL} правильных ответа") app.run_polling() if __name__ == "__main__": main()