tg_bot/tg_bot/handlers/tic_tac_toy.py

214 lines
5.8 KiB
Python

from random import choice
from aiogram import Bot, F, Router
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import (
CallbackQuery,
InlineKeyboardButton,
InlineKeyboardMarkup,
KeyboardButton,
Message,
ReplyKeyboardMarkup,
ReplyKeyboardRemove,
)
from aiogram.utils.formatting import Bold, as_key_value, as_list, as_marked_section
router = Router()
class GameState(StatesGroup):
tic_tac_toy = State()
@router.message(F.text.lower() == 'exit game')
async def exit_games(message: Message, state: FSMContext):
await state.clear()
await message.reply('Game is finished', reply_markup=ReplyKeyboardRemove())
async def get_keyboard(field: list):
buttons = []
for x in range(3):
row = []
for y in range(3):
callback_data = f'{x} {y}'
text = ''
match field[x][y]:
case None:
text = '⬛️'
case False:
text = '⭕️'
case True:
text = ''
row.append(
InlineKeyboardButton(text=text, callback_data=callback_data),
)
buttons.append(row)
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
return keyboard
async def get_content(bot_wins, user_wins, move):
content = as_list(
as_marked_section(
Bold('Game summary:'),
as_key_value('Total games', bot_wins + user_wins),
as_key_value('user wins', user_wins),
as_key_value('bot wins', bot_wins),
as_key_value('Move: ', move),
marker=' ',
),
sep='\n\n',
)
return content
async def check_winner(field):
winner = None
def check_equal_all_in_row(row):
if row[0] == row[1] and row[0] == row[2]:
return True
return False
for row in field:
if check_equal_all_in_row(row):
winner = row[0]
for row in zip(*field):
if check_equal_all_in_row(row):
winner = row[0]
row = []
for i in range(3):
row.append(field[i][i])
if check_equal_all_in_row(row):
winner = row[0]
row = []
for i in range(3):
row.append(field[i][2 - i])
if check_equal_all_in_row(row):
winner = row[0]
return winner
@router.message(F.text.lower() == 'tic_tac_toy')
async def start_tic_tac_toy(
message: Message, state: FSMContext, user_wins=0, bot_wins=0
):
tic_tac_toy_kb = [
[KeyboardButton(text='Exit Game')],
]
await state.clear()
await state.set_state(GameState.tic_tac_toy)
data = {
'field': [[None for _ in range(3)] for _ in range(3)],
'availible_moves': [(x, y) for x in range(3) for y in range(3)],
'user_wins': user_wins,
'bot_wins': bot_wins,
'move': 0,
}
await state.set_data(data)
await message.reply('Start Tic Tac Toy', reply_markup=ReplyKeyboardRemove())
await message.reply(
'Make your move',
reply_markup=ReplyKeyboardMarkup(keyboard=tic_tac_toy_kb, resize_keyboard=True),
)
await make_move(message, state)
@router.message(GameState.tic_tac_toy, F.text)
async def make_move(message: Message, state: FSMContext):
data = await state.get_data()
keyboard = await get_keyboard(data['field'])
await state.update_data(data)
content = await get_content(
data['bot_wins'],
data['user_wins'],
data['move'],
)
await message.answer(**content.as_kwargs(), reply_markup=keyboard)
@router.callback_query(GameState.tic_tac_toy)
async def check_answer(callback: CallbackQuery, state: FSMContext, bot: Bot):
data = await state.get_data()
x, y = map(int, callback.data.split())
if (x, y) not in data['availible_moves']:
await callback.answer(text='Cell is busy', show_alert=True)
else:
data['move'] += 1
data['field'][x][y] = True
data['availible_moves'].remove((x, y))
await state.update_data(data)
keyboard = await get_keyboard(data['field'])
content = await get_content(
data['bot_wins'],
data['user_wins'],
data['move'],
)
await bot.edit_message_text(
**content.as_kwargs(),
chat_id=callback.from_user.id,
message_id=callback.message.message_id,
reply_markup=keyboard,
)
winner = await check_winner(data['field'])
if winner is True:
await callback.answer()
await start_tic_tac_toy(
callback.message, state, data['user_wins'] + 1, data['bot_wins']
)
return
if not data['availible_moves']:
await callback.answer('A draw game')
await start_tic_tac_toy(
callback.message, state, data['user_wins'], data['bot_wins']
)
return
x, y = choice(data['availible_moves'])
data['field'][x][y] = False
data['availible_moves'].remove((x, y))
data['move'] += 1
await state.update_data(data)
keyboard = await get_keyboard(data['field'])
content = await get_content(
data['bot_wins'],
data['user_wins'],
data['move'],
)
await bot.edit_message_text(
**content.as_kwargs(),
chat_id=callback.from_user.id,
message_id=callback.message.message_id,
reply_markup=keyboard,
)
winner = await check_winner(data['field'])
if winner is False:
await callback.answer(text='Bot is WINNER')
await start_tic_tac_toy(
callback.message, state, data['user_wins'], data['bot_wins'] + 1
)
return
await callback.answer()