nards/bot/main.py
2024-12-18 22:53:38 +07:00

189 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from aiogram import Bot, Dispatcher, types, F
from aiogram.filters import Command
from aiogram.types import WebAppInfo, KeyboardButton, ReplyKeyboardMarkup
from bot.database import Database
import json
import asyncio
from bot.config import BOT_TOKEN, WEBAPP_URL
import logging
# Настройка логирования
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Инициализация бота и диспетчера
bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()
db = Database()
# Упрощенная клавиатура
def get_main_keyboard():
keyboard = [
[
KeyboardButton(
text="Записать броски 🎲",
web_app=WebAppInfo(url=WEBAPP_URL)
)
],
[KeyboardButton(text="Статистика 📊")]
]
return ReplyKeyboardMarkup(keyboard=keyboard, resize_keyboard=True)
@dp.message(Command("start"))
async def start_command(message: types.Message):
logger.info(f"User {message.from_user.id} ({message.from_user.username}) started the bot")
await message.answer(
"🎲 Добро пожаловать в счётчик кубиков для нард!\n\n"
"Нажмите «Записать броски» чтобы начать новую игру.",
reply_markup=get_main_keyboard()
)
# Обновляем функцию подсчета статистики в handle_webapp_data
def calculate_throw_sum(throw):
dice1, dice2 = throw['dice']
base_sum = (dice1 + dice2) * 2 if dice1 == dice2 else dice1 + dice2
return base_sum - (throw.get('unusedPoints', 0))
@dp.message(F.web_app_data)
async def handle_webapp_data(message: types.Message):
try:
user = message.from_user
logger.info(f"Received webapp data from user {user.id} ({user.username})")
data = json.loads(message.web_app_data.data)
if data['type'] == 'game_session':
# Создаем новую игру
game_id = db.create_game(user.id, user.username)
logger.info(f"Created new game {game_id} for user {user.id}")
# Записываем все броски
throws = data['throws']
for throw in throws:
db.add_throw(
game_id,
throw['dice'][0],
throw['dice'][1],
throw.get('unusedPoints', 0)
)
# Завершаем игру
db.end_game(game_id)
logger.info(f"Game {game_id} completed with {len(throws)} throws")
# Обновляем подсчет статистики
total_throws = len(throws)
total_base_sum = sum((t['dice'][0] + t['dice'][1]) * 2 if t['dice'][0] == t['dice'][1] else t['dice'][0] + t['dice'][1] for t in throws)
total_final_sum = sum(calculate_throw_sum(t) for t in throws)
# Обновляем подсчет статистики
total_throws = len(throws)
avg_sum = total_base_sum / total_throws if total_throws > 0 else 0
avg_sum_with_minus = total_final_sum / total_throws if total_throws > 0 else 0
doubles = sum(1 for t in throws if t['dice'][0] == t['dice'][1])
# Находим максимальный и минимальный броски с учетом дублей
throws_with_sums = [(t, calculate_throw_sum(t)) for t in throws]
max_throw = max(throws_with_sums, key=lambda x: x[1])
min_throw = min(throws_with_sums, key=lambda x: x[1])
# Формируем сообщение
response = "🎯 Игра завершена!\n\n"
response += f"📊 Статистика игры:\n"
response += f"Всего бросков: {total_throws}\n"
response += f"• Общая сумма: {total_final_sum}\n"
if total_base_sum != total_final_sum:
unused_sum = total_base_sum - total_final_sum
response += f" (без минусов: {total_base_sum})\n"
response += f"• Неиспользовано: {unused_sum}\n"
response += f"• Эффективность: {(total_final_sum / total_base_sum * 100):.1f}%\n"
response += f"• Средняя сумма: {avg_sum_with_minus:.1f} \n"
response += f" (без минусов: {avg_sum:.1f})\n"
else:
response += "\n"
response += f"• Средняя сумма: {avg_sum:.1f}\n"
response += f"• Дублей выпало: {doubles}\n"
# Добавляем последние броски
response += "\n🎲 Последние броски:\n"
for i, throw in enumerate(throws[:5]):
sum_value = calculate_throw_sum(throw)
is_double = throw['dice'][0] == throw['dice'][1]
unused = throw.get('unusedPoints', 0)
base_sum = (throw['dice'][0] + throw['dice'][1]) * 2 if is_double else throw['dice'][0] + throw['dice'][1]
response += f"{i+1}. {throw['dice'][0]}-{throw['dice'][1]}"
response += f" {'🎯' if is_double else ''}"
if unused > 0:
response += f" = {sum_value} (-{unused})"
else:
response += f" = {sum_value}"
response += "\n"
if total_throws > 5:
response += f"... и ещё {total_throws - 5} бросков"
await message.answer(response)
logger.info(f"Sent game statistics to user {user.id}")
except Exception as e:
logger.error(f"Error handling webapp data: {e}", exc_info=True)
await message.answer("❌ Произошла ошибка при обработке данных.")
@dp.message(Command("statistics"))
@dp.message(F.text == "Статистика 📊")
async def statistics_command(message: types.Message):
user_id = message.from_user.id
logger.info(f"User {user_id} requested statistics")
stats = db.get_statistics(user_id)
response = "📊 Подробная статистика:\n\n"
if stats['total_throws']:
total_base_sum = stats['total_base_sum'] or 0
total_final_sum = stats['total_final_sum'] or 0
total_unused = stats['total_unused'] or 0
avg_sum = total_final_sum / stats['total_throws']
response += (
f"🎲 Броски:\n"
f"Всего бросков: {stats['total_throws']}\n"
f"• Количество игр: {stats['total_games']}\n"
f"• Среднее бросков за игру: {stats['total_throws'] / stats['total_games']:.1f}\n\n"
f"🎯 Очки:\n"
f"• Общая сумма: {total_final_sum}\n"
f"• Сумма без минусов: {total_base_sum}\n"
f"• Средняя сумма за бросок: {avg_sum:.1f}\n"
f"• Эффективность: {(total_final_sum / total_base_sum * 100):.1f}%\n\n"
)
if total_unused > 0:
avg_unused = total_unused / stats['total_throws']
response += (
f"❌ Неиспользованные очки:\n"
f"Всего неиспользовано: {total_unused}\n"
f"В среднем за бросок: {avg_unused:.1f}\n"
f"• Процент потерь: {(total_unused / total_base_sum * 100):.1f}%\n"
)
else:
response += "У вас пока нет записанных бросков."
await message.answer(response)
logger.info(f"Sent statistics to user {user_id}")
# Запуск бота
async def main():
logger.info("Starting bot")
await dp.start_polling(bot)
if __name__ == '__main__':
asyncio.run(main())