Skip to content

Instantly share code, notes, and snippets.

@rodion-gudz
Last active February 14, 2023 17:01
Show Gist options
  • Save rodion-gudz/2138228a86be34d8a7b315e4ca13f6f5 to your computer and use it in GitHub Desktop.
Save rodion-gudz/2138228a86be34d8a7b315e4ca13f6f5 to your computer and use it in GitHub Desktop.
Пример чат-бота для выступления на проекте "Школьная Лига Лекторов" – Бот для игры "Города России"
import asyncio
import random
import requests
from aiogram import Bot, Dispatcher, F
from aiogram.fsm.state import StatesGroup, State
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import Message, ContentType, CallbackQuery
from aiogram_dialog import (
Dialog,
DialogManager,
DialogRegistry,
Window,
DialogProtocol,
ShowMode,
)
from aiogram_dialog.widgets.input import MessageInput
from aiogram_dialog.widgets.kbd import Next, Button
from aiogram_dialog.widgets.media import StaticMedia
from aiogram_dialog.widgets.text import Const
cities_alphabet = {
"а", "б", "в", "г", "д", "е", "ё", "ж", "з", "и", "й", "к", "л", "м", "н", "о",
"п", "р", "с", "т", "у", "ф", "х", "ц", "ч", "ш", "щ", "э", "ю", "я"
}
class DialogSG(StatesGroup):
greeting = State()
game = State()
end = State()
async def city_handler(
message: Message, dialog: DialogProtocol, manager: DialogManager
):
cities = manager.middleware_data["cities"]
used_cities = manager.middleware_data["used_cities"]
manager.show_mode = ShowMode.EDIT
city = message.text.strip().lower()
if city in used_cities:
await message.answer("<b>Такой город уже был</b>")
return
if city not in cities:
await message.answer(
"<b>К сожалению, я не знаю такого города, попробуйте другой</b>"
)
return
if len(used_cities) > 2:
for letter in reversed(used_cities[-1]):
if letter in cities_alphabet:
if city[0] != letter:
await message.answer(
f"<b>Город должен начинаться на букву</b> <code>{letter}</code>"
)
return
break
for letter in reversed(list(city)):
if letter in cities_alphabet:
allowed_cities = list(
filter(lambda x: x.startswith(letter) and x not in used_cities, cities)
)
if not allowed_cities:
break
answer_city = random.choice(allowed_cities)
await message.answer(
" ".join(
map(
lambda x: x[0].upper() + x[1:],
("-".join(map(str.capitalize, answer_city.split("-")))).split(),
)
)
)
used_cities.append(city)
used_cities.append(answer_city)
manager.dialog_data["score"] = manager.dialog_data.get("score", 0) + 1
return
await message.answer(
"<b>🎁 Вы победили!</b> \n\n"
f"<b>Ваш результат:</b> <code>{manager.dialog_data['score']}</code>"
)
await manager.done()
async def end_handler(
callback_query: CallbackQuery, button: Button, manager: DialogManager
):
if "score" in manager.dialog_data:
score = manager.dialog_data["score"]
else:
score = 0
await callback_query.message.answer(
"<b>✅ Игра закончена.</b> \n\n" f"<b>Ваш результат:</b> <code>{score}</code>"
)
await manager.done()
def get_city_list():
r = requests.get("https://raw.githubusercontent.com/hflabs/city/master/city.csv")
lines = r.text.splitlines()
return list(
map(
str.lower,
filter(
lambda x: x not in ("", "г", "Респ", "обл"),
[
line.split(",")[10] or line.split(",")[9] or line.split(",")[5]
for line in lines[1:]
],
),
)
) + ["Иннополис"]
dialog = Dialog(
Window(
Const("<b>👋 Приветствую!</b> \n"),
Const("Это бот для игры в города."),
StaticMedia(
url="https://www.iphones.ru/wp-content/uploads/2014/11/goroda-0.jpg",
type=ContentType.PHOTO,
),
Next(Const("🚀 Начать")),
state=DialogSG.greeting,
),
Window(
Const("<b>Ты играешь первым, напиши название города.</b> \n"),
Const("Например, <code>Москва</code>"),
MessageInput(city_handler, content_types=[ContentType.TEXT]),
Button(Const("✅ Закончить"), id="end", on_click=end_handler),
state=DialogSG.game,
),
)
async def start(message: Message, dialog_manager: DialogManager):
await dialog_manager.start(DialogSG.greeting)
async def main():
API_TOKEN = "TOKEN:42"
bot = Bot(token=API_TOKEN, parse_mode="HTML")
c = get_city_list()
dp = Dispatcher(storage=MemoryStorage(), cities=c, used_cities=[])
dp.message.register(start, F.text == "/start")
registry = DialogRegistry(dp)
registry.register(dialog)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment