ДЗ tic_tac_toy&quest

main
Сергей Ванюшкин 2024-02-23 03:51:00 +03:00
parent f33802a740
commit 49c74ea2b6
7 changed files with 536 additions and 104 deletions

20
poetry.lock generated
View File

@ -621,6 +621,24 @@ files = [
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
] ]
[[package]]
name = "networkx"
version = "3.2.1"
description = "Python package for creating and manipulating graphs and networks"
optional = false
python-versions = ">=3.9"
files = [
{file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"},
{file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"},
]
[package.extras]
default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"]
developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"]
doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"]
extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"]
test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"]
[[package]] [[package]]
name = "nodeenv" name = "nodeenv"
version = "1.8.0" version = "1.8.0"
@ -1093,4 +1111,4 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "74b5d10c672b860dada4f42ba97679cbab3b3e9b29d92a9ff7fbed7f61bfd5c5" content-hash = "cd0c5b9b5963bfaaf67b54596050f1f7d860381ae6e360dc266ad14dc186d30c"

View File

@ -13,6 +13,7 @@ requests = "^2.31.0"
types-requests = "^2.31.0.20240125" types-requests = "^2.31.0.20240125"
mypy = "^1.8.0" mypy = "^1.8.0"
pyquizapi = "^0.0.14" pyquizapi = "^0.0.14"
networkx = "^3.2.1"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]

View File

@ -16,12 +16,18 @@ from tg_bot.handlers import (
lesson_one, lesson_one,
lesson_tree, lesson_tree,
lesson_two, lesson_two,
quest,
quiz,
tic_tac_toy,
) )
TOKEN: str = getenv('BOT_TOKEN') or 'Your TG_BOT token' TOKEN: str = getenv('BOT_TOKEN') or 'Your TG_BOT token'
dp = Dispatcher() dp = Dispatcher()
dp.include_routers( dp.include_routers(
quest.router,
tic_tac_toy.router,
quiz.router,
games.router, games.router,
lesson_five.router, lesson_five.router,
lesson_four.router, lesson_four.router,

View File

@ -1,29 +1,6 @@
from os import getenv from aiogram import Router
from aiogram import Bot, F, Router
from aiogram.filters import Command from aiogram.filters import Command
from aiogram.fsm.context import FSMContext from aiogram.types import KeyboardButton, Message, ReplyKeyboardMarkup
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import (
CallbackQuery,
InlineKeyboardButton,
InlineKeyboardMarkup,
KeyboardButton,
Message,
ReplyKeyboardMarkup,
ReplyKeyboardRemove,
)
from pyquizAPI import QuizClient
async def get_question():
api = getenv('QUIZ_API')
client = QuizClient(api)
client.make_config(limit=1, difficulty='Easy')
questions = client.get_questions(use_config=True)
return questions
router = Router() router = Router()
kb = [ kb = [
@ -33,87 +10,9 @@ kb = [
] ]
class GameState(StatesGroup):
game = State()
quiz = State()
tic_tac_toy = State()
quest = State()
markup_kb = ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True) markup_kb = ReplyKeyboardMarkup(keyboard=kb, resize_keyboard=True)
@router.message(Command('games')) @router.message(Command('games'))
async def games(message: Message): async def games(message: Message):
await message.answer('Select Game:', reply_markup=markup_kb) await message.answer('Select Game:', reply_markup=markup_kb)
@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())
@router.message(F.text.lower() == 'quiz')
async def with_puree(message: Message, state: FSMContext):
quiz_kb = [
[KeyboardButton(text='Next question')],
[KeyboardButton(text='Exit Game')],
]
await state.set_state(GameState.quiz)
await message.reply('Start Quiz', reply_markup=ReplyKeyboardRemove())
await message.reply(
'First question:',
reply_markup=ReplyKeyboardMarkup(keyboard=quiz_kb, resize_keyboard=True),
)
await question(message, state)
@router.message(GameState.quiz, F.text)
async def question(message: Message, state: FSMContext):
data = await state.get_data()
question_data = await get_question()
question = question_data[0].get('question')
answers = {
question_data[0]['answers'][k]: question_data[0]['correct_answers'][
k + '_correct'
]
for k in question_data[0]['answers'].keys()
if question_data[0]['answers'][k] is not None
}
buttons = []
idx = 1
text = f'Question:\n{question}\n\nanswers:\n'
for k, v in answers.items():
buttons.append([InlineKeyboardButton(text=f'choice {idx}', callback_data=k)])
if v == 'true':
data['answer'] = k
text = text + f'{idx} - {k}\n'
idx += 1
data['question'] = question
await state.update_data(data)
await message.answer(
text=text,
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons),
)
@router.callback_query(GameState.quiz)
async def check_answer(callback: CallbackQuery, state: FSMContext, bot: Bot):
answer = (await state.get_data())['answer']
await callback.answer()
if answer == callback.data:
await callback.message.answer(text='Correct')
else:
await callback.message.answer(text='Opps. You miss')
await bot.edit_message_text(
chat_id=callback.from_user.id,
message_id=callback.message.message_id,
text=callback.message.text,
)

153
tg_bot/handlers/quest.py Normal file
View File

@ -0,0 +1,153 @@
import networkx as nx
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_list, as_marked_section
G = nx.Graph()
G.add_node('start')
G.add_node('A')
G.add_node('B')
G.add_node('C')
G.add_node('D')
G.add_node('end')
G.add_edge('start', 'A')
G.add_edge('start', 'B')
G.add_edge('A', 'C')
G.add_edge('A', 'D')
G.add_edge('D', 'end')
router = Router()
class GameState(StatesGroup):
quest = 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_content(place, backward, forward):
if forward != ['None']:
f_text = 'Можете продолжить путь'
else:
f_text = 'Вы пришли в тупик, поищите другой путь'
content = as_list(
as_marked_section(
Bold('Вы находитесь в локации:'),
place,
marker='*️⃣ ',
),
as_marked_section(
Bold(
'Вы можете вернуться назад в локацию'
if backward
else 'Вы в начале, пути назад нет'
),
backward,
marker='',
),
as_marked_section(
Bold(f_text),
*forward,
marker='',
),
sep='\n\n',
)
return content
async def get_keyboard(backward, forward):
buttons = []
if backward is not None:
buttons.append(
[
InlineKeyboardButton(
text=f'◀️◀️◀️ Вернуться в {backward}',
callback_data=f'bacward_{backward}',
)
],
)
if forward is not None:
for f in forward:
buttons.append(
[
InlineKeyboardButton(
text=f'Идти в {f} ▶️▶️▶️', callback_data=f'forward_{f}'
)
],
)
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
return keyboard
@router.message(F.text.lower() == 'quest')
async def start_quest(message: Message, state: FSMContext):
quest_kb = [
[KeyboardButton(text='Exit Game')],
]
await state.set_state(GameState.quest)
data = {'backward': None, 'place': 'start', 'forward': ['A', 'B']}
await state.set_data(data)
await message.reply('Start quest', reply_markup=ReplyKeyboardRemove())
await message.reply(
'Make your move',
reply_markup=ReplyKeyboardMarkup(keyboard=quest_kb, resize_keyboard=True),
)
await make_move(message, state)
@router.message(GameState.quest, F.text)
async def make_move(message: Message, state: FSMContext):
data = await state.get_data()
keyboard = await get_keyboard(data['backward'], data['forward'])
content = await get_content(data['place'], data['backward'], data['forward'])
await message.answer(**content.as_kwargs(), reply_markup=keyboard)
@router.callback_query(GameState.quest)
async def check_answer(callback: CallbackQuery, state: FSMContext, bot: Bot):
data = await state.get_data()
data['backward'] = data['place']
data['place'] = (callback.data.split('_'))[1]
data['forward'] = list(G.neighbors(data['place']))
data['forward'].remove(data['backward'])
await state.update_data(data)
if data['place'] == 'end':
await callback.answer(text='Вы дошли до конца!!!', show_alert=True)
await start_quest(callback.message, state)
return
content = await get_content(
data['place'], data['backward'], data['forward'] or ['None']
)
keyboard = await get_keyboard(data['backward'], data['forward'])
await bot.send_message(
**content.as_kwargs(), chat_id=callback.from_user.id, reply_markup=keyboard
)
await callback.answer()

142
tg_bot/handlers/quiz.py Normal file
View File

@ -0,0 +1,142 @@
from os import getenv
from aiogram import Bot, F, Router, html
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
from pyquizAPI import QuizClient
async def get_question():
api = getenv('QUIZ_API')
client = QuizClient(api)
client.make_config(limit=1, difficulty='Easy')
questions = client.get_questions(use_config=True)
return questions
router = Router()
class GameState(StatesGroup):
quiz = 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_formated_question(
qnt: int, correct: int, question: str, answers: list[str]
):
content = as_list(
as_marked_section(
Bold('Game summary:'),
as_key_value('Total questions', qnt),
as_key_value('Success', correct),
as_key_value('Failed', qnt - correct),
marker=' ',
),
as_marked_section(
Bold('Question:'),
html.quote(question),
marker='',
),
as_marked_section(
Bold('Answers:'),
*[html.quote(item) for item in answers],
marker=' ',
),
sep='\n\n',
)
return content
@router.message(F.text.lower() == 'quiz')
async def start_quiz(message: Message, state: FSMContext):
quiz_kb = [
[KeyboardButton(text='Next question')],
[KeyboardButton(text='Exit Game')],
]
await state.set_state(GameState.quiz)
await message.reply('Start Quiz', reply_markup=ReplyKeyboardRemove())
await message.reply(
'First question:',
reply_markup=ReplyKeyboardMarkup(keyboard=quiz_kb, resize_keyboard=True),
)
await question(message, state)
@router.message(GameState.quiz, F.text)
async def question(message: Message, state: FSMContext):
data = await state.get_data()
question_data = await get_question()
question = question_data[0].get('question')
answers = {
question_data[0]['answers'][k]: question_data[0]['correct_answers'][
k + '_correct'
]
for k in question_data[0]['answers'].keys()
if question_data[0]['answers'][k] is not None
}
buttons = []
idx = 1
for k, v in answers.items():
buttons.append([InlineKeyboardButton(text=f'choice {idx}', callback_data=k)])
if v == 'true':
data['answer'] = k
idx += 1
content = await get_formated_question(
data.get('quantity', 0), data.get('score', 0), question, list(answers.keys())
)
data['question'] = question
await state.update_data(data)
await message.answer(
**content.as_kwargs(),
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons),
)
@router.callback_query(GameState.quiz)
async def check_answer(callback: CallbackQuery, state: FSMContext, bot: Bot):
data = await state.get_data()
answer = data['answer']
score = data.get('score', 0)
qnt = data.get('quantity', 0)
await callback.answer()
if answer == callback.data:
await callback.message.answer(text='Correct')
score += 1
else:
await callback.message.answer(text='Opps. You miss')
qnt += 1
data['score'] = score
data['quantity'] = qnt
await state.update_data(data)
msg_text: str = callback.message.text
await bot.edit_message_text(
chat_id=callback.from_user.id,
message_id=callback.message.message_id,
text=msg_text,
)

View File

@ -0,0 +1,213 @@
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()