Как настроить механизм обработки нескольких событий в боте с использованием aiogram?

Как можно реализовать задачу, связанную с определением столиц стран в рамках "большого квиза", где все данные представлены в словаре по регионам и странам?
  • 18 марта 2024 г. 17:09
Ответы на вопрос 2
Для настройки механизма обработки нескольких событий в боте с использованием aiogram, можно воспользоваться функцией `dispatcher`. Например, для обработки нескольких команд можно использовать декоратор `message_handler`:

```python
from aiogram import Bot, Dispatcher, types

bot = Bot(token="YOUR_TOKEN")
dp = Dispatcher(bot)

@dp.message_handler(commands=['start'])
async def start(message: types.Message):
    await message.answer("Привет! Я бот.")

@dp.message_handler(commands=['help'])
async def help(message: types.Message):
    await message.answer("Помощь по использованию бота.")

if __name__ == '__main__':
    import asyncio
    from aiogram import executor
    loop = asyncio.get_event_loop()
    executor.start_polling(dp, skip_updates=True, loop=loop)
```

Для реализации задачи связанной с определением столиц стран в рамках "большого квиза", можно создать словарь, в котором ключами будут являться регионы, а значениями - словари с парами "страна:столица". Например:

```python
countries_capitals = {
    "Европа": {
        "Германия": "Берлин",
        "Франция": "Париж",
        "Италия": "Рим"
    },
    "Азия": {
        "Китай": "Пекин",
        "Япония": "Токио"
    },
    # другие регионы и страны
}
```

Затем можно реализовать логику получения случайной пары "страна:столица" из этого словаря и отправлять пользователю вопросы с вариантами ответов. При получении ответа можно проверить правильность и отправить результат пользователю.
В общем, обошелся с FSM только для запроса начальных данных. 
Дальше исходя из этих данных формируем нужные нам списки в функции стэйта, в ней же посылаем первый вопрос и дальше обрабатываем ответы в пустом хендлере, который читает все сообщения, отправленные боту.

Вот пример примерной реализации
@dp.message(Command("start"))
async def start(message: types.Message, state: FSMContext):
    await state.set_state(Start.start_name)
    await bot.send_message(message.from_user.id,
                           text='Можно выбрать один материк или перечислить несколько через пробел:\n'
                                '1 - Европа\n'
                                '2 - Азия\n'
                                '3 - Африка\n'
                                '4 - Северная Америка\n'
                                '5 - Южная Америка\n'
                                '6 - Австралия\n')


@dp.message(Start.start_name)
async def test(message: types.Message, state: FSMContext):
    await state.update_data(name=message.text)
    data = await state.get_data()
    
    # Создаем словарь перемешанных вопросов и ответов
    cities: dict = {}

    # Список вариантов материков
    data_list: list = [i for i in data["name"].strip(' ').split(' ') if i]
    
    # Исходя из списка вариантов и основного словаря со столицами CD обновляем cities
    for i in data_list:
        cities.update(CD[int(i)])
        
    # Разбиваем на словари вопросов и ответов для записи в БД
    questions_list, answers_list = list(shuffle_dict(cities))
    
    # Записываем в БД (создаем нового юзера, если нет. Создаем под него вопросы и ответы, если нет. Иначе обновляем)
    await db.insert('users', [message.from_user.id, message.from_user.username, 1])
    await db.insert('questions', [message.from_user.id, ', '.join(questions_list), ', '.join(answers_list), 0])
    
    # Отправляем первый вопрос. Завершаем стейт
    await bot.send_message(message.from_user.id, await db.select_question(message.from_user.id))
    await state.clear()


@dp.message()
async def test1(message: types.Message):

    # Проверяем, что пользователь играет (флажок in_game из БД)
    if await db.select_in_game(message.from_user.id) == 1:

        # Если его ответ совпал с ответом из БД, то:
        # 1. Увеличиваем счетчик вопросов в БД на 1
        # 2. Отправляем следующий вопрос, исходя из счетчика
        if message.text == await db.select_answer(message.from_user.id):
            await db.update_question_number(message.from_user.id)
            await bot.send_message(message.from_user.id, await db.select_question(message.from_user.id))

        # Если его ответ = 1, то:
        # 1. Отправляем правильный ответ
        # 2. Увеличиваем счетчик вопросов в БД на 1
        # 3. Отправляем следующий вопрос
        if message.text == '1':
            await bot.send_message(message.from_user.id, await db.select_answer(message.from_user.id))
            await db.update_question_number(message.from_user.id)
            await bot.send_message(message.from_user.id, await db.select_question(message.from_user.id))

        # Если его ответ = 0, то:
        # 1. Завершаем игру. Чистим все нужные строки в БД.
        # 2. Отправляем сообщение о завершении
        if message.text == '0':
            await db.the_end(message.from_user.id)
            await bot.send_message(message.from_user.id, 'Завершено')
Похожие вопросы