Last active
February 14, 2023 17:01
-
-
Save rodion-gudz/2138228a86be34d8a7b315e4ca13f6f5 to your computer and use it in GitHub Desktop.
Пример чат-бота для выступления на проекте "Школьная Лига Лекторов" – Бот для игры "Города России"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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