ДЗ 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"},
]
[[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]]
name = "nodeenv"
version = "1.8.0"
@ -1093,4 +1111,4 @@ multidict = ">=4.0"
[metadata]
lock-version = "2.0"
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"
mypy = "^1.8.0"
pyquizapi = "^0.0.14"
networkx = "^3.2.1"
[tool.poetry.group.dev.dependencies]

View File

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

View File

@ -1,29 +1,6 @@
from os import getenv
from aiogram import Bot, F, Router
from aiogram import Router
from aiogram.filters import Command
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 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
from aiogram.types import KeyboardButton, Message, ReplyKeyboardMarkup
router = Router()
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)
@router.message(Command('games'))
async def games(message: Message):
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()