Игра готова #5

Merged
Anymorexxx merged 2 commits from master into Dev 2024-12-11 20:16:27 +03:00
73 changed files with 28832 additions and 193 deletions
Showing only changes of commit da62618d95 - Show all commits

3
.idea/misc.xml generated
View file

@ -4,4 +4,7 @@
<option name="sdkName" value="Python 3.13 (Dog_Academy)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
<component name="PyPackaging">
<option name="earlyReleasesAsUpgrades" value="true" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

Binary file not shown.

BIN
assets/background.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 821 KiB

After

Width:  |  Height:  |  Size: 821 KiB

Before After
Before After

BIN
assets/bone.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

BIN
assets/dogs/Chihuahua.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 KiB

After

Width:  |  Height:  |  Size: 326 KiB

Before After
Before After

BIN
assets/dogs/Corgi.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 KiB

After

Width:  |  Height:  |  Size: 215 KiB

Before After
Before After

BIN
assets/dogs/Husky.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Before After
Before After

BIN
assets/dogs/Pomeranian.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 227 KiB

Before After
Before After

BIN
assets/dogs/Pug.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 255 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 KiB

After

Width:  |  Height:  |  Size: 341 KiB

Before After
Before After

BIN
assets/done.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before After
Before After

BIN
assets/lock.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Before After
Before After

BIN
assets/logo.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Before After
Before After

BIN
assets/settings.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Before After
Before After

BIN
assets/unlock.png Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

123
config.py
View file

@ -1,6 +1,21 @@
# config.py
import os
# Интерфейс
# Базовая директория проекта
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# Директория с ресурсами
ASSETS_DIR = os.path.join(BASE_DIR, "assets")
DOGS_DIR = os.path.join(ASSETS_DIR, "dogs")
# Админ-интерфейс (тёмные цвета)
ADMIN_BACKGROUND_COLOR = "#403d49"
ADMIN_PRIMARY_COLOR = "#ff6347"
ADMIN_BUTTON_COLOR = "#444444"
ADMIN_BUTTON_TEXT_COLOR = "#ffffff"
ADMIN_FONT = ("Comic Sans MS", 25)
ADMIN_BIG_FONT = ("Comic Sans MS", 40)
# Интерфейс пользователя (АВТОРИЗАЦИЯ)
BACKGROUND_COLOR = "#f8e1e1"
PRIMARY_COLOR = "#ff6347"
BUTTON_COLOR = "#87ceeb"
@ -8,9 +23,111 @@ BUTTON_TEXT_COLOR = "white"
FONT = ("Comic Sans MS", 25)
BIG_FONT = ("Comic Sans MS", 40)
# ГЛАВНОЕ МЕНЮ
BACKGROUND_COLOR_USER = "#bcabe5" # Основной фон
TOP_PANEL_COLOR_USER = "#aa9bcd" # Цвет верхней панели
BUTTON_COLOR_PROFILE_USER = "#a2c792" # Цвет кнопок "Профиль", "Магазин", "База знаний"
BUTTON_COLOR_PLAY_USER = "#b4e1a1" # Цвет кнопки "Играть"
BUTTON_COLOR_EXIT_USER = "#a2c792" # Цвет кнопки "Выход"
BUTTON_TEXT_COLOR_USER = "white" # Цвет текста на кнопках
FONT_USER = ("Comic Sans MS", 20) # Шрифт для текста кнопок
BIG_FONT_USER = ("Comic Sans MS", 30) # Большой шрифт (например, для заголовков)
BUTTON_RADIUS_USER = 50 # Радиус круглой кнопки
EXIT_BUTTON_SIZE_USER = (80, 40) # Размер кнопки "Выход"
TOP_PANEL_COLOR = "#BBA0D0"
BUTTON_COLOR_PROFILE = "#8FC085"
BUTTON_COLOR_PLAY = "#8FC085"
BUTTON_COLOR_EXIT = "#8FC085"
# Размеры
PLAY_BUTTON_RADIUS = 100
EXIT_BUTTON_WIDTH = 100
EXIT_BUTTON_HEIGHT = 50
# Данные для авторизации администратора
ADMIN_LOGIN = "admin"
ADMIN_PASSWORD = "admin123"
# База данных
DATABASE_URL = "sqlite:///database/DogAcademy.db" # Обновлено на правильный путь
DATABASE_URL = f"sqlite:///{os.path.join(BASE_DIR, 'database', 'DogAcademy.db')}"
# Пути к ресурсам
SETTINGS_IMG = os.path.join(ASSETS_DIR, "settings.png")
LOGO = os.path.join(ASSETS_DIR, "logo.png")
BACKGROUND_GAME = os.path.join(ASSETS_DIR, "background.png")
BONE = os.path.join(ASSETS_DIR, "bone.png")
LOCK = os.path.join(ASSETS_DIR, "lock.png")
UNLOCK = os.path.join(ASSETS_DIR, "unlock.png")
DONE = os.path.join(ASSETS_DIR, "done.png")
# Пути к изображениям собак
CHIHUAHUA = os.path.join(DOGS_DIR, "Chihuahua.png")
CORGI = os.path.join(DOGS_DIR, "Corgi.png")
RETRIEVER = os.path.join(DOGS_DIR, "Golden_Retriever.png")
HUSKY = os.path.join(DOGS_DIR, "Husky.png")
POMERANIAN = os.path.join(DOGS_DIR, "Pomeranian.png")
PUG = os.path.join(DOGS_DIR, "Pug.png")
YORKSHIRE = os.path.join(DOGS_DIR, "Yorkshire_Terrier.png")
# Данные о характерах собак
DOG_CHARACTERS = {
"Chihuahua": {
"image": CHIHUAHUA,
"speed": 8,
"endurance": 5,
"special_ability": "Fast Dodge",
},
"Corgi": {
"image": CORGI,
"speed": 6,
"endurance": 7,
"special_ability": "Extra Jump",
},
"Golden Retriever": {
"image": RETRIEVER,
"speed": 7,
"endurance": 8,
"special_ability": "Bonus Points",
},
"Husky": {
"image": HUSKY,
"speed": 9,
"endurance": 6,
"special_ability": "Speed Boost",
},
"Pomeranian": {
"image": POMERANIAN,
"speed": 7,
"endurance": 4,
"special_ability": "Charm",
},
"Pug": {
"image": PUG,
"speed": 5,
"endurance": 9,
"special_ability": "Resilience",
},
"Yorkshire Terrier": {
"image": YORKSHIRE,
"speed": 6,
"endurance": 5,
"special_ability": "Quick Recovery",
},
}
# Утилиты
NOTIFICATION_LEVEL = "info" # Возможные значения: "info", "warning", "error"
USE_DATABASE_LOGS = True
# Игровые параметры
INITIAL_SCORE = 5 # Начальные очки игрока
POINTS_CORRECT_ANSWER = 2 # Очки за правильный ответ
POINTS_WRONG_ANSWER = -1 # Штраф за неправильный ответ
MAX_LEVELS = 100 # Максимальное количество уровней
INITIAL_DOG_STATUS = {"health": 100, "hunger": 0, "sleepiness": 0} # Стартовые характеристики собаки
# Параметры карты
MIN_OBSTACLES = 3 # Минимум препятствий на уровне
MAX_OBSTACLES = 6 # Максимум препятствий на уровне
# Графика и анимация
COUNTDOWN_DURATION = 3 # Продолжительность обратного отсчёта в секундах

Binary file not shown.

View file

@ -1,28 +1,445 @@
import logging
from sqlalchemy import func
from sqlalchemy.orm import joinedload
from database.db_session import get_session
from database.models import Auth
from database.models import Auth, Notifications, Users, GameSession, Dogs, Questions
from sqlalchemy.exc import SQLAlchemyError
def create_user(login, password):
"""Создание нового пользователя в базе данных."""
def get_user_by_id(user_id):
"""Получение данных пользователя по ID с предварительной загрузкой связанных данных."""
session = get_session()
try:
new_user = Auth(login=login, password=password)
user = (
session.query(Users)
.options(joinedload(Users.game_sessions)) # Предзагрузка связанных игровых сессий
.filter_by(user_id=user_id)
.first()
)
return user
except SQLAlchemyError as e:
logging.error(f"Ошибка при получении пользователя: {e}")
return None
finally:
session.close()
def create_user(login, password, username):
"""Регистрация нового пользователя."""
session = get_session()
# Проверка, есть ли уже пользователь с таким логином
if session.query(Auth).filter_by(login=login).first():
return False, "Логин уже используется."
# Создание новой записи в таблице Auth
new_auth = Auth(login=login, password=password)
session.add(new_auth)
try:
session.commit() # Сохранение изменений в таблице Auth
# Создание новой записи в таблице Users, связываем с только что добавленным Auth
new_user = Users(user_id=new_auth.user_id, username=username)
session.add(new_user)
session.commit() # Сохраняем изменения в таблице Users
# Создаём новый игровой процесс для этого пользователя
new_game_session = GameSession(user_id=new_user.user_id, level=1) # Устанавливаем уровень по умолчанию
session.add(new_game_session)
session.commit() # Сохраняем данные в GameSession
print(f"Пользователь {username} успешно добавлен!")
return True, "Регистрация успешна."
except SQLAlchemyError as e:
session.rollback() # Откат изменений при ошибке
print(f"Ошибка при создании пользователя: {e}")
return False, "Произошла ошибка при регистрации."
finally:
session.close()
def check_user(login, password=None):
session = get_session()
try:
query = session.query(Auth).filter_by(login=login)
if password:
query = query.filter_by(password=password)
user = query.first()
if user:
return user.user_id
else:
return None
except SQLAlchemyError as e:
print(f"Ошибка при проверке пользователя: {e}")
return None
finally:
session.close()
def save_progress(user_id, level, score, duration, health, hunger, sleepiness):
"""Сохранение игрового прогресса в базу данных."""
session = get_session()
try:
if not user_id:
raise ValueError("user_id не указан!")
session_data = GameSession(
user_id=user_id,
level=level,
score=score,
duration=duration,
health=health,
hunger=hunger,
sleepiness=sleepiness,
end_time=func.now()
)
session.add(session_data)
session.commit()
except SQLAlchemyError as e:
print(f"Ошибка при создании пользователя: {e}")
logging.error(f"Ошибка при сохранении прогресса: {e}")
session.rollback()
except ValueError as e:
logging.error(e)
finally:
session.close()
def get_user_progress(user_id):
"""Получение игрового прогресса пользователя."""
session = get_session()
try:
return session.query(GameSession).filter_by(user_id=user_id).all()
except Exception as e:
logging.error(f"Ошибка при получении прогресса пользователя: {e}")
return []
finally:
session.close()
def create_notification(user_id, message):
"""Создание уведомления для пользователя."""
session = get_session()
try:
notification = Notifications(user_id=user_id, message=message)
session.add(notification)
session.commit()
except SQLAlchemyError as e:
print(f"Ошибка при создании уведомления: {e}")
session.rollback()
finally:
session.close()
def check_user(login, password):
"""Проверка данных пользователя для авторизации."""
def get_notifications(user_id):
"""Получение уведомлений для пользователя."""
session = get_session()
try:
user = session.query(Auth).filter_by(login=login, password=password).first()
return user is not None
notifications = session.query(Notifications).filter_by(user_id=user_id).all()
return notifications
except SQLAlchemyError as e:
print(f"Ошибка при проверке пользователя: {e}")
return False
print(f"Ошибка при получении уведомлений: {e}")
return []
finally:
session.close()
def get_knowledge_base():
"""Получение базы знаний (статей о собаках)."""
session = get_session()
try:
dogs = session.query(Dogs).all()
return dogs # Список объектов Dogs
except SQLAlchemyError as e:
print(f"Ошибка при получении базы знаний: {e}")
return []
finally:
session.close()
def get_dogs():
"""Получение списка пород собак."""
session = get_session()
try:
dogs = session.query(Dogs).all()
return dogs # Список объектов Dogs
except SQLAlchemyError as e:
print(f"Ошибка при получении списка собак: {e}")
return []
finally:
session.close()
def update_user_dog(user_id, dog_id):
"""Обновление выбранной пользователем породы собаки."""
session = get_session()
try:
user = session.query(Users).filter_by(user_id=user_id).first()
if user:
user.dog_id = dog_id
session.commit()
print(f"Порода пользователя обновлена на {dog_id}")
else:
print("Пользователь не найден.")
except SQLAlchemyError as e:
print(f"Ошибка при обновлении породы собаки: {e}")
session.rollback()
finally:
session.close()
def debug_list_users():
"""Отладочный вывод всех пользователей."""
session = get_session()
try:
users = session.query(Auth).all()
for user in users:
print(f"User ID: {user.user_id}, Login: {user.login}, Password: {user.password}")
except SQLAlchemyError as e:
print(f"Ошибка при получении списка пользователей: {e}")
finally:
session.close()
def get_all_users():
"""Получить всех пользователей с предварительной загрузкой данных."""
session = get_session()
try:
users = session.query(Users).options(joinedload(Users.auth)).all()
return users
except SQLAlchemyError as e:
print(f"Ошибка при получении пользователей: {e}")
return [] # Возвращаем пустой список, если ошибка
finally:
session.close()
def get_all_questions():
"""Получить все вопросы."""
session = get_session()
try:
questions = session.query(Questions).all()
return questions
except SQLAlchemyError as e:
print(f"Ошибка при получении вопросов: {e}")
return []
finally:
session.close()
def get_all_dogs():
"""Получить все записи о собаках."""
session = get_session()
try:
dogs = session.query(Dogs).all() # Запрос к базе данных для получения всех собак
return dogs
except SQLAlchemyError as e:
print(f"Ошибка при получении собак: {e}")
return []
finally:
session.close()
def get_user_by_username(username):
"""Получить пользователя по логину."""
session = get_session()
try:
user = session.query(Users).join(Auth).filter(Auth.login == username).first()
return user
except SQLAlchemyError as e:
print(f"Ошибка при получении пользователя: {e}")
return None
finally:
session.close()
def update_user(user_id, new_login, new_password):
"""Обновить данные пользователя."""
session = get_session()
try:
user = session.query(Users).filter_by(user_id=user_id).first()
if user:
auth = user.auth
auth.login = new_login
auth.password = new_password
session.commit()
except SQLAlchemyError as e:
print(f"Ошибка при обновлении пользователя: {e}")
session.rollback()
finally:
session.close()
def update_user_info(user_id, new_login, new_username):
"""Обновление данных пользователя."""
session = get_session()
try:
user = session.query(Users).filter_by(user_id=user_id).first()
if user:
user.auth.login = new_login
user.username = new_username
session.commit()
return True, "Данные пользователя обновлены."
return False, "Пользователь не найден."
except SQLAlchemyError as e:
session.rollback()
return False, f"Ошибка при обновлении: {e}"
finally:
session.close()
def delete_user(user_id):
"""Удаление пользователя по ID, включая связанные записи."""
session = get_session()
try:
# Находим пользователя
user = session.query(Users).filter_by(user_id=user_id).first()
if not user:
return False, "Пользователь не найден."
# Удаляем запись из Auth
auth = user.auth
if auth:
session.delete(auth)
# Удаляем запись из Users
session.delete(user)
# Фиксируем изменения
session.commit()
return True, "Пользователь успешно удалён."
except SQLAlchemyError as e:
session.rollback()
return False, f"Ошибка при удалении пользователя: {e}"
finally:
session.close()
def update_dog_info(dog_id, breed, characteristics):
"""Обновление информации о собаке."""
session = get_session()
try:
dog = session.query(Dogs).filter_by(dog_id=dog_id).first()
if dog:
dog.breed = breed
dog.characteristics = characteristics
session.commit()
return True, "Информация о собаке обновлена."
return False, "Собака не найдена."
except SQLAlchemyError as e:
session.rollback()
return False, f"Ошибка при обновлении: {e}"
finally:
session.close()
def update_question(question_id, text, helpful_info):
"""Обновление вопроса."""
session = get_session()
try:
question = session.query(Questions).filter_by(question_id=question_id).first()
if question:
question.question_text = text
question.helpful_info = helpful_info
session.commit()
return True, "Вопрос обновлён."
return False, "Вопрос не найден."
except SQLAlchemyError as e:
session.rollback()
return False, f"Ошибка при обновлении: {e}"
finally:
session.close()
def update_user_level(user_id, new_level):
"""Обновляет уровень пользователя в базе данных."""
session = get_session()
try:
user = session.query(Users).filter_by(user_id=user_id).first()
if user and user.level < new_level:
user.level = new_level
session.commit()
except Exception as e:
session.rollback()
logging.error(f"Ошибка при обновлении уровня пользователя: {e}")
finally:
session.close()
def add_user_to_db(user_data):
"""
Добавление нового пользователя в базу данных.
Создаёт записи в таблицах Auth и Users.
"""
session = get_session()
try:
# Создание записи в таблице Auth
new_auth = Auth(
login=user_data['login'],
password=user_data['password']
)
session.add(new_auth)
session.flush() # Сохраняем, чтобы получить user_id для Users
# Создание записи в таблице Users, связываем с Auth
new_user = Users(
user_id=new_auth.user_id, # Используем внешний ключ
username=user_data['username'],
level=user_data.get('level', 1), # Уровень по умолчанию 1
achievement=user_data.get('achievement', None) # По умолчанию пусто
)
session.add(new_user)
session.commit()
print(f"Пользователь {user_data['username']} успешно добавлен.")
except SQLAlchemyError as e:
session.rollback()
print(f"Ошибка при добавлении пользователя: {e}")
raise # Пробрасываем исключение для обработки
finally:
session.close()
def add_question_to_db(question_data):
session = get_session()
try:
new_question = Questions(**question_data)
session.add(new_question)
session.commit()
print(f"Вопрос успешно добавлен: {question_data['question_text']}")
except SQLAlchemyError as e:
print(f"Ошибка при добавлении вопроса: {e}")
session.rollback()
finally:
session.close()
def add_dog_to_db(dog_data):
session = get_session()
try:
new_dog = Dogs(**dog_data)
session.add(new_dog)
session.commit()
print(f"Собака успешно добавлена: {dog_data['breed']}")
except SQLAlchemyError as e:
print(f"Ошибка при добавлении собаки: {e}")
session.rollback()
finally:
session.close()
def delete_dog(dog_id):
"""Удаление породы собак по ID."""
session = get_session()
try:
dog = session.query(Dogs).filter_by(dog_id=dog_id).first()
if dog:
session.delete(dog)
session.commit()
print(f"Порода с ID {dog_id} успешно удалена.")
return True, "Порода успешно удалена."
return False, "Порода не найдена."
except SQLAlchemyError as e:
session.rollback()
return False, f"Ошибка при удалении: {e}"
finally:
session.close()
def delete_question(question_id):
"""Удаление вопроса по ID."""
session = get_session()
try:
question = session.query(Questions).filter_by(question_id=question_id).first()
if question:
session.delete(question)
session.commit()
return True, "Вопрос успешно удалён."
return False, "Вопрос не найден."
except SQLAlchemyError as e:
session.rollback()
return False, f"Ошибка при удалении: {e}"
finally:
session.close()

View file

@ -1,4 +1,3 @@
# database/db_session.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from config import DATABASE_URL
@ -9,16 +8,42 @@ import os
engine = create_engine(DATABASE_URL, echo=True)
# Создание фабрики сессий
Session = sessionmaker(bind=engine)
Session = sessionmaker(bind=engine, autoflush=True)
def init_db():
"""Инициализация базы данных: создание файла и таблиц."""
if not os.path.exists("database/DogAcademy.db"):
print("База данных не найдена. Создаём новую...")
Base.metadata.create_all(bind=engine)
# Переменная для хранения текущей сессии
current_session = None
def create_session():
"""Создание сессии для работы с базой данных."""
return Session()
def init_db(refresh=False):
"""
Инициализация базы данных: создание файла и таблиц.
Если `refresh` равно True, удаляет и пересоздаёт таблицы.
"""
global current_session
if not os.path.exists("database/DogAcademy.db") or refresh:
if refresh:
print("Обновление базы данных: удаление старых таблиц...")
Base.metadata.drop_all(bind=engine) # Удалить все таблицы
print("Создание базы данных и таблиц...")
Base.metadata.create_all(bind=engine) # Создать таблицы заново
else:
print("База данных уже существует.")
print("База данных уже существует. Обновление не требуется.")
# Инициализация сессии при запуске
current_session = get_session()
def get_session():
"""Возвращает сессию для работы с базой данных."""
return Session()
def close_sessions():
"""Закрытие всех сессий перед выходом из программы."""
if current_session:
print("Закрытие сессии...")
current_session.close()
else:
print("Нет активной сессии для закрытия.")

View file

@ -0,0 +1,94 @@
import logging
from sqlalchemy.exc import SQLAlchemyError
from database.db_session import get_session
from database.models import Dogs
DOG_CHARACTERS = {
"Chihuahua": {
"characteristics": "Скорость: 8, Выносливость: 5, Умение: Быстрое уклонение.",
"behavior": "Энергичный, часто лайливый.",
"care_info": "Нуждается в регулярной чистке зубов и когтей.",
"admin_comments": "Идеален для активных владельцев."
},
"Corgi": {
"characteristics": "Скорость: 6, Выносливость: 7, Умение: Дополнительный прыжок.",
"behavior": "Дружелюбный, легко обучаемый.",
"care_info": "Важно контролировать вес из-за коротких лап.",
"admin_comments": "Подходит для семей с детьми."
},
"Golden Retriever": {
"characteristics": "Скорость: 7, Выносливость: 8, Умение: Увеличенные очки за правильные ответы.",
"behavior": "Очень умный и добрый.",
"care_info": "Требует регулярной чистки шерсти.",
"admin_comments": "Идеален для владельцев, ищущих верного друга."
},
"Husky": {
"characteristics": "Скорость: 9, Выносливость: 6, Умение: Ускорение.",
"behavior": "Независимый, требует много активности.",
"care_info": "Плохо переносит жару, требует частых прогулок.",
"admin_comments": "Для опытных владельцев."
},
"Pomeranian": {
"characteristics": "Скорость: 7, Выносливость: 4, Умение: Уменьшение штрафа за ошибки.",
"behavior": "Веселый, преданный.",
"care_info": "Шерсть требует ежедневного ухода.",
"admin_comments": "Идеален для жизни в квартире."
},
"Pug": {
"characteristics": "Скорость: 5, Выносливость: 9, Умение: Сохраняет здоровье при столкновениях.",
"behavior": "Ласковый, склонен к перееданию.",
"care_info": "Внимание к дыханию и физической активности.",
"admin_comments": "Для спокойного образа жизни."
},
"Yorkshire Terrier": {
"characteristics": "Скорость: 6, Выносливость: 5, Умение: Быстрое восстановление характеристик.",
"behavior": "Компактный, умный.",
"care_info": "Требует профессиональной стрижки.",
"admin_comments": "Подходит для маленьких пространств."
}
}
def populate_dogs():
"""
Заполнение таблицы Dogs предустановленными данными.
"""
session = get_session()
try:
logging.info("Начинается заполнение таблицы Dogs.")
for breed, data in DOG_CHARACTERS.items():
existing_dog = session.query(Dogs).filter_by(breed=breed).first()
if not existing_dog:
dog = Dogs(
breed=breed,
characteristics=data['characteristics'],
behavior=data['behavior'],
care_info=data['care_info'],
admin_comments=data['admin_comments']
)
session.add(dog)
session.commit()
logging.info("Таблица Dogs успешно заполнена.")
except SQLAlchemyError as e:
session.rollback()
logging.error(f"Ошибка при заполнении Dogs: {e}")
finally:
session.close()
def get_all_dogs():
"""
Получение списка всех пород собак из базы данных.
:return: Список объектов Dogs.
"""
session = get_session()
try:
dogs = session.query(Dogs).all()
return dogs
except SQLAlchemyError as e:
logging.error(f"Ошибка при получении списка собак: {e}")
return []
finally:
session.close()

View file

@ -0,0 +1,61 @@
import logging
from database.db_events import get_user_progress
from database.db_session import get_session
from database.models import GameSession
def save_game_session(user_id, level, score, duration, steps, health, hunger, sleepiness):
"""Сохранение игрового прогресса с обновлением существующей записи."""
session = get_session() # Получаем сессию для работы с базой данных
try:
# Проверяем, существует ли уже запись для данного пользователя и уровня
existing_session = session.query(GameSession).filter_by(user_id=user_id, level=level).first()
if existing_session:
logging.info(f"Обновление прогресса для user_id={user_id}, level={level}.")
existing_session.score = score
existing_session.duration = duration
existing_session.steps = steps
existing_session.health = health
existing_session.hunger = hunger
existing_session.sleepiness = sleepiness
else:
# Если записи нет, создаем новую
new_session = GameSession(
user_id=user_id,
level=level,
score=score,
duration=duration,
steps=steps,
health=health,
hunger=hunger,
sleepiness=sleepiness
)
session.add(new_session) # Добавляем в сессию
session.commit() # Сохраняем изменения в базе данных
logging.info(f"Прогресс успешно сохранён: user_id={user_id}, level={level}, score={score}")
except Exception as e:
session.rollback() # Откатываем изменения в случае ошибки
logging.error(f"Ошибка при сохранении прогресса: {e}")
finally:
session.close() # Закрываем сессию
def print_user_progress(user_id):
"""
Печать прогресса пользователя из таблицы GameSessions.
:param user_id: ID пользователя
"""
if not user_id:
logging.error("user_id отсутствует. Невозможно получить прогресс.")
return
progress = get_user_progress(user_id)
if not progress:
print(f"У пользователя с ID {user_id} нет сохраненного прогресса.")
return
print(f"Прогресс пользователя (user_id={user_id}):")
for session in progress:
print(f"- Уровень: {session.level}, Очки: {session.score}, Время: {session.duration} сек")

View file

@ -0,0 +1,99 @@
from database.db_session import get_session
from database.models import Dogs, Questions
DOG_QUESTIONS = {
"Chihuahua": [
{
"question_text": "Почему у Чихуахуа часто возникают проблемы с зубами?",
"helpful_info": "Миниатюрный размер приводит к скоплению налета и зубных отложений.",
},
{
"question_text": "Какая активность лучше всего подходит для Чихуахуа?",
"helpful_info": "Легкие прогулки и домашние игры.",
}
],
"Corgi": [
{
"question_text": "Почему важно контролировать вес Корги?",
"helpful_info": "Избыточный вес может негативно повлиять на суставы.",
},
{
"question_text": "Как можно поддерживать здоровье суставов у Корги?",
"helpful_info": "Обеспечьте умеренную активность и сбалансированное питание.",
}
],
"Golden Retriever": [
{
"question_text": "Почему важно регулярно вычесывать шерсть Голден Ретривера?",
"helpful_info": "Это предотвращает образование колтунов.",
},
{
"question_text": "Какое питание подходит для Голден Ретриверов?",
"helpful_info": "Сбалансированное питание с учетом активности и возраста.",
}
],
"Husky": [
{
"question_text": "Какой климат подходит для Хаски?",
"helpful_info": "Они комфортнее чувствуют себя в холодном климате.",
},
{
"question_text": "Почему Хаски требуют много физической активности?",
"helpful_info": "Эта порода обладает высокой энергией и выносливостью.",
}
],
"Pomeranian": [
{
"question_text": "Как правильно ухаживать за шерстью Померанского шпица?",
"helpful_info": "Ежедневно расчесывать шерсть, чтобы избежать колтунов.",
},
{
"question_text": "Почему важно следить за зубами Померанского шпица?",
"helpful_info": "Они склонны к зубному налету, что может привести к проблемам.",
}
],
"Pug": [
{
"question_text": "Почему мопсы склонны к ожирению?",
"helpful_info": "Их низкая активность и любовь к еде требуют контроля рациона.",
},
{
"question_text": "Какие проблемы с дыханием могут возникнуть у мопсов?",
"helpful_info": "Из-за их плоской морды дыхание может быть затруднено.",
}
],
"Yorkshire Terrier": [
{
"question_text": "Как часто нужно стричь шерсть Йоркширского терьера?",
"helpful_info": "Примерно раз в 4-6 недель для поддержания аккуратного вида.",
},
{
"question_text": "Как ухаживать за шерстью Йоркширского терьера?",
"helpful_info": "Регулярно расчесывать и использовать специальные средства.",
}
]
}
def populate_questions():
session = get_session()
try:
dogs = {dog.breed: dog.dog_id for dog in session.query(Dogs).all()}
for breed, questions in DOG_QUESTIONS.items():
dog_id = dogs.get(breed)
if not dog_id:
print(f"Порода '{breed}' отсутствует.")
continue
for question_data in questions:
question = Questions(
dog_id=dog_id,
question_text=question_data["question_text"],
helpful_info=question_data["helpful_info"]
)
session.add(question)
session.commit()
print("Таблица Questions успешно заполнена.")
except Exception as e:
session.rollback()
print(f"Ошибка при заполнении Questions: {e}")
finally:
session.close()

View file

View file

@ -1,18 +1,18 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Text
from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, UniqueConstraint, Boolean
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Auth(Base):
__tablename__ = 'auth'
user_id = Column(Integer, primary_key=True)
login = Column(String, unique=True, nullable=False)
password = Column(String, nullable=False)
# Связь с таблицей Users
user = relationship("Users", back_populates="auth", uselist=False)
user = relationship("Users", back_populates="auth", cascade="all, delete-orphan", uselist=False)
class Users(Base):
@ -26,6 +26,8 @@ class Users(Base):
# Связи
auth = relationship("Auth", back_populates="user") # Обратная связь с Auth
dog = relationship("Dogs", back_populates="users") # Связь с таблицей Dogs
game_sessions = relationship("GameSession", back_populates="user") # Связь с таблицей GameSession
notifications = relationship("Notifications", back_populates="user") # Связь с уведомлениями
class Dogs(Base):
@ -50,6 +52,40 @@ class Questions(Base):
question_text = Column(Text, nullable=False)
image_url = Column(String)
helpful_info = Column(Text)
incorrect_attempts = Column(Integer, default=0)
# Связь с таблицей Dogs
dog = relationship("Dogs", back_populates="questions")
class GameSession(Base):
__tablename__ = 'game_sessions'
__table_args__ = (
UniqueConstraint('user_id', 'level', name='uix_user_level'),
)
session_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.user_id'))
level = Column(Integer, nullable=False)
score = Column(Integer, default=0)
duration = Column(Integer) # Время игры в секундах
steps = Column(Integer, default=0) # Количество шагов
start_time = Column(DateTime, default=func.now())
end_time = Column(DateTime, nullable=True)
health = Column(Integer, default=100) # Здоровье
hunger = Column(Integer, default=0) # Голод
sleepiness = Column(Integer, default=0) # Сонливость
# Связь с таблицей Users
user = relationship("Users", back_populates="game_sessions")
class Notifications(Base):
__tablename__ = 'notifications'
notification_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.user_id'))
message = Column(Text, nullable=False)
timestamp = Column(DateTime, default=func.now())
is_read = Column(Boolean, default=False) # Булевый тип для read
# Связь с таблицей Users
user = relationship("Users", back_populates="notifications")

BIN
ishodniki/admin_panel.psd Normal file

Binary file not shown.

Binary file not shown.

BIN
ishodniki/dogs.psd Normal file

Binary file not shown.

BIN
ishodniki/user_ui.psd Normal file

Binary file not shown.

0
logs/database.log Normal file
View file

919
logs/game.log Normal file
View file

@ -0,0 +1,919 @@
2024-11-27 04:01:47,401 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:01:47,941 - ERROR - Îøèáêà ïðè âçàèìîäåéñòâèè ñ áàçîé äàííûõ: Entity namespace for "users" has no property "login"
2024-11-27 04:05:26,240 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:05:26,795 - ERROR - Îøèáêà ïðè âçàèìîäåéñòâèè ñ áàçîé äàííûõ: (sqlite3.OperationalError) unable to open database file
(Background on this error at: https://sqlalche.me/e/20/e3q8)
2024-11-27 04:08:19,488 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:08:19,922 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:08:20,024 - INFO - BEGIN (implicit)
2024-11-27 04:08:20,028 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:08:20,028 - INFO - [generated in 0.00061s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:08:20,030 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:08:20,047 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,048 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,048 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:20,071 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,072 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,072 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:08:20,087 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,088 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,088 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:08:20,101 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,102 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,102 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:08:20,112 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,112 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,112 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:08:20,124 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,124 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,124 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:08:20,139 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:20,139 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:20,139 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:08:21,407 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,408 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,408 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:08:21,408 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:08:21,415 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,415 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,415 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:08:21,432 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,432 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,432 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:08:21,503 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,504 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,504 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:21,518 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,518 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,518 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:08:21,532 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,532 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,532 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:08:21,545 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,546 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,546 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:08:21,555 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,555 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,556 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:08:21,567 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,567 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,567 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:08:21,579 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:21,579 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:21,579 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:08:26,316 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,316 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,317 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:26,333 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,333 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,333 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:08:26,347 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,347 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,348 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:08:26,360 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,360 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,360 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:08:26,370 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,370 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,370 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:08:26,381 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,381 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,381 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:08:26,393 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:26,394 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:26,394 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:08:27,162 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,162 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,162 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:08:27,162 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:08:27,169 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,169 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,169 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:08:27,185 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,185 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,185 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:08:27,256 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,256 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,256 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:27,271 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,271 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,271 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:08:27,285 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,285 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,285 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:08:27,298 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,299 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,299 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:08:27,308 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,309 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,309 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:08:27,320 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,320 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,320 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:08:27,333 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:27,333 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:27,333 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:08:28,177 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:28,177 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:28,177 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:08:32,088 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:32,088 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:32,088 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:32,537 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:32,537 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:32,538 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:32,942 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:32,942 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:32,942 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:33,187 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:33,187 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:33,187 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:33,380 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:33,380 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:33,380 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:33,735 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:33,735 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:33,735 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,247 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,247 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,247 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,277 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,277 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,277 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,308 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,308 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,308 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,339 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,339 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,339 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,370 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,370 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,370 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,402 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,402 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,402 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,448 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,448 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,448 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,479 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,479 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,479 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,510 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,510 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,510 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,541 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,541 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,541 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,571 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,572 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,572 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,603 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,603 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,603 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,634 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,634 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,634 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,664 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,665 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,665 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,711 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,711 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,711 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,742 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,742 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,742 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,772 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,772 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,772 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,803 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,803 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,803 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,833 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,833 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,833 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:34,864 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:34,864 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:34,865 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,170 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,170 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,170 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,672 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,672 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,673 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,704 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,704 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,704 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,750 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,750 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,750 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,781 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,781 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,781 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,813 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,813 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,813 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,843 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,844 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,844 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,875 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,875 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,875 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,907 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,907 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,907 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,937 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,937 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,937 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:35,968 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:35,968 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:35,969 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,015 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,015 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,015 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,046 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,046 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,046 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,077 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,077 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,078 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,109 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,109 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,109 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,140 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,140 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,140 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,170 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,171 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,171 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,201 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,201 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,201 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,496 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,496 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,496 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:36,934 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:36,934 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:36,935 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,444 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,444 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,444 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,475 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,475 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,475 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,506 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,506 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,506 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,537 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,537 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,537 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,569 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,569 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,569 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,614 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,614 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,614 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,645 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,645 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,645 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,676 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,676 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,676 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,707 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,707 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,707 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:37,956 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:37,956 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:37,956 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:38,682 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:38,682 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:38,682 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,181 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,182 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,182 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,228 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,228 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,228 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,258 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,258 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,258 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,289 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,289 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,289 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,321 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,321 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,321 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,352 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,352 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,352 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:39,383 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:08:39,384 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:08:39,384 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:08:41,418 - INFO - ROLLBACK
2024-11-27 04:09:26,353 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:09:26,804 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:09:26,901 - INFO - BEGIN (implicit)
2024-11-27 04:09:26,904 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:09:26,904 - INFO - [generated in 0.00028s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:09:26,905 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:09:26,920 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:26,920 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:26,920 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:09:26,942 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:26,942 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:26,943 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:09:26,958 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:26,958 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:26,958 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:09:26,972 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:26,972 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:26,972 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:09:26,984 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:26,985 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:26,985 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:09:26,996 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:26,996 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:26,996 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:09:27,010 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:27,010 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:27,010 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:09:28,434 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,435 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,435 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:09:28,435 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:09:28,442 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,442 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,442 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:09:28,459 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,459 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,459 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:09:28,530 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,530 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,530 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:09:28,545 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,545 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,545 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:09:28,559 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,560 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,560 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:09:28,573 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,573 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,573 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:09:28,583 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,583 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,583 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:09:28,594 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,594 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,594 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:09:28,607 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:09:28,607 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:09:28,607 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:11:03,632 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:11:03,632 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:11:03,632 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:11:26,828 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:11:26,828 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:11:26,828 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:12:26,226 - INFO - ROLLBACK
2024-11-27 04:12:28,471 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:12:28,899 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:12:28,997 - INFO - BEGIN (implicit)
2024-11-27 04:12:29,000 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:12:29,000 - INFO - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:12:29,001 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:12:29,015 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,015 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,015 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:12:29,038 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,038 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,038 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:12:29,053 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,053 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,054 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:12:29,068 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,068 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,068 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:12:29,078 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,078 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,079 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:12:29,090 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,090 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,090 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:12:29,103 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,104 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,104 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:12:29,841 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,841 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,841 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:12:29,841 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:12:29,848 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,849 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,849 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:12:29,865 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,865 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,865 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:12:29,934 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,935 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,935 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:12:29,949 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,950 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,950 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:12:29,965 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,965 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,965 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:12:29,979 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,980 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,980 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:12:29,990 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:29,990 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:29,990 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:12:30,002 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:30,002 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:30,002 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:12:30,016 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:30,016 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:30,016 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:12:30,808 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:30,808 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:30,808 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:12:34,561 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:12:34,561 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:12:34,561 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:17:58,361 - INFO - ROLLBACK
2024-11-27 04:18:49,054 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:18:49,525 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:18:49,627 - INFO - BEGIN (implicit)
2024-11-27 04:18:49,629 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:18:49,630 - INFO - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:18:49,630 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:18:49,647 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,647 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,647 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:18:49,670 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,670 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,670 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:18:49,686 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,686 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,686 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:18:49,701 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,701 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,701 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:18:49,711 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,712 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,712 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:18:49,723 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,724 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,724 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:18:49,737 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:49,737 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:49,738 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:18:50,592 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,593 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,593 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:18:50,593 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:18:50,600 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,600 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,600 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:18:50,617 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,618 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,618 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:18:50,685 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,686 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,686 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:18:50,702 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,702 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,702 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:18:50,720 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,720 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,720 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:18:50,737 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,737 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,737 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:18:50,748 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,748 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,748 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:18:50,761 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,761 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,761 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:18:50,775 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:50,775 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:50,775 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:18:52,809 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:52,810 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:52,810 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:18:56,823 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:18:56,823 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:18:56,823 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:19:14,325 - INFO - ROLLBACK
2024-11-27 04:20:41,642 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:20:42,172 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:20:42,283 - INFO - BEGIN (implicit)
2024-11-27 04:20:42,285 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:20:42,285 - INFO - [generated in 0.00028s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:20:42,286 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:20:42,307 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,307 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,307 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:20:42,330 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,331 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,331 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:20:42,346 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,346 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,346 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:20:42,362 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,362 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,362 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:20:42,373 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,373 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,373 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:20:42,387 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,387 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,387 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:20:42,401 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:42,401 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:42,402 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:20:43,204 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,204 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,204 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:20:43,204 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:20:43,211 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,212 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,212 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:20:43,229 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,229 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,229 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:20:43,304 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,304 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,305 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:20:43,320 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,320 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,320 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:20:43,337 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,337 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,337 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:20:43,352 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,353 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,353 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:20:43,363 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,363 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,363 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:20:43,375 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,375 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,375 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:20:43,389 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:20:43,389 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:20:43,389 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:21:16,405 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:16,405 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:16,405 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:21:20,530 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:20,530 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:20,530 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:21:27,458 - INFO - ROLLBACK
2024-11-27 04:21:39,761 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:21:40,188 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:21:40,294 - INFO - BEGIN (implicit)
2024-11-27 04:21:40,296 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:21:40,296 - INFO - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:21:40,297 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:21:40,312 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,312 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,312 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:21:40,334 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,334 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,334 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:21:40,350 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,350 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,350 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:21:40,363 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,364 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,364 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:21:40,375 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,375 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,375 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:21:40,387 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,387 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,387 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:21:40,400 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:40,401 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:40,401 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:21:41,365 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,365 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,365 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:21:41,365 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:21:41,372 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,372 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,372 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:21:41,389 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,390 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,390 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:21:41,463 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,463 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,463 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:21:41,481 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,481 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,482 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:21:41,503 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,504 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,504 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:21:41,525 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,525 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,525 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:21:41,538 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,538 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,538 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:21:41,552 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,552 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,552 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:21:41,568 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:41,569 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:41,569 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:21:44,529 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:44,529 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:44,529 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:21:48,501 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:21:48,501 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:21:48,501 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:21:58,037 - INFO - ROLLBACK
2024-11-27 04:23:20,095 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:23:20,529 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:23:20,637 - INFO - BEGIN (implicit)
2024-11-27 04:23:20,639 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:23:20,640 - INFO - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:23:20,640 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:23:20,655 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,655 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,655 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:23:20,678 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,678 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,678 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:23:20,693 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,693 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,693 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:23:20,707 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,707 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,707 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:23:20,718 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,718 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,718 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:23:20,730 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,730 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,730 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:23:20,743 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:20,743 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:20,743 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:23:21,610 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,610 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,610 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:23:21,610 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:23:21,617 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,618 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,618 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:23:21,634 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,634 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,635 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:23:21,707 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,707 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,707 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:23:21,724 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,724 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,724 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:23:21,745 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,745 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,745 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:23:21,765 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,765 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,765 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:23:21,776 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,777 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,777 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:23:21,790 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,790 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,790 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:23:21,805 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:21,805 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:21,805 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:23:22,532 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:22,532 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:22,532 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:23:26,429 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:23:26,429 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:23:26,429 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:23:31,839 - INFO - ROLLBACK
2024-11-27 04:26:48,168 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:26:48,266 - INFO - BEGIN (implicit)
2024-11-27 04:26:48,269 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:26:48,269 - INFO - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:26:48,269 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:26:48,284 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,284 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,284 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:26:48,307 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,307 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,307 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:26:48,322 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,323 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,323 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:26:48,337 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,337 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,337 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:26:48,347 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,347 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,347 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:26:48,359 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,359 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,359 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:26:48,373 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:26:48,373 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:26:48,373 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:26:56,174 - INFO - ROLLBACK
2024-11-27 04:28:00,201 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:28:00,689 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:28:00,802 - INFO - BEGIN (implicit)
2024-11-27 04:28:00,805 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:28:00,805 - INFO - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:28:00,806 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:28:00,823 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,823 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,823 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:28:00,848 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,848 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,849 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:28:00,864 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,865 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,865 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:28:00,879 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,879 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,879 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:28:00,890 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,890 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,890 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:28:00,903 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,903 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,903 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:28:00,918 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:00,918 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:00,918 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:28:01,704 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,704 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,704 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:28:01,704 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:28:01,712 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,712 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,712 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:28:01,729 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,729 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,729 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:28:01,809 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,809 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,809 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:28:01,828 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,829 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,829 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:28:01,851 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,851 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,852 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:28:01,874 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,874 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,874 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:28:01,887 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,887 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,887 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:28:01,902 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,902 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,902 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:28:01,918 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:01,918 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:01,919 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:28:03,370 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:03,370 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:03,370 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:28:07,271 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:07,271 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:07,272 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:28:11,499 - INFO - ROLLBACK
2024-11-27 04:28:25,505 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:28:25,929 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:28:26,029 - INFO - BEGIN (implicit)
2024-11-27 04:28:26,031 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:28:26,031 - INFO - [generated in 0.00023s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:28:26,032 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:28:26,047 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,047 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,047 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:28:26,070 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,070 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,070 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:28:26,087 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,087 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,087 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:28:26,101 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,101 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,102 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:28:26,112 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,113 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,113 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:28:26,126 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,126 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,126 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:28:26,140 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,140 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,140 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:28:26,992 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:26,992 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:26,992 - DEBUG - STREAM b'tEXt' 62 25
2024-11-27 04:28:26,993 - DEBUG - STREAM b'IDAT' 99 8192
2024-11-27 04:28:26,999 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,000 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,000 - DEBUG - STREAM b'IDAT' 62 29837
2024-11-27 04:28:27,016 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,016 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,016 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:28:27,088 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,088 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,088 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:28:27,107 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,107 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,107 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:28:27,129 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,129 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,129 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:28:27,151 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,151 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,151 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:28:27,163 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,163 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,164 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:28:27,177 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,178 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,178 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:28:27,194 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:27,194 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:27,194 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:28:28,409 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:28,409 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:28,409 - DEBUG - STREAM b'IDAT' 62 840969
2024-11-27 04:28:32,335 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:28:32,336 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:28:32,336 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:28:38,371 - INFO - ROLLBACK
2024-11-27 04:32:09,489 - INFO - Ëîãèðîâàíèå èãðû íà÷àòî.
2024-11-27 04:32:09,948 - INFO - Ïîäêëþ÷åíèå ê áàçå äàííûõ óñïåøíî.
2024-11-27 04:32:10,049 - INFO - BEGIN (implicit)
2024-11-27 04:32:10,052 - INFO - SELECT auth.user_id AS auth_user_id, auth.login AS auth_login, auth.password AS auth_password
FROM auth
WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ?
2024-11-27 04:32:10,052 - INFO - [generated in 0.00023s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-27 04:32:10,053 - INFO - Ïîëüçîâàòåëü íàéäåí: lubluNikitu
2024-11-27 04:32:10,068 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,068 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,068 - DEBUG - STREAM b'IDAT' 62 333841
2024-11-27 04:32:10,091 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,092 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,092 - DEBUG - STREAM b'IDAT' 62 259015
2024-11-27 04:32:10,107 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,107 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,107 - DEBUG - STREAM b'IDAT' 62 220337
2024-11-27 04:32:10,121 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,121 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,121 - DEBUG - STREAM b'IDAT' 62 177624
2024-11-27 04:32:10,131 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,132 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,132 - DEBUG - STREAM b'IDAT' 62 232384
2024-11-27 04:32:10,143 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,143 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,144 - DEBUG - STREAM b'IDAT' 62 261264
2024-11-27 04:32:10,157 - DEBUG - STREAM b'IHDR' 16 13
2024-11-27 04:32:10,157 - DEBUG - STREAM b'pHYs' 41 9
2024-11-27 04:32:10,157 - DEBUG - STREAM b'IDAT' 62 348922
2024-11-27 04:32:12,820 - INFO - ROLLBACK

24814
logs/logfile.log Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
sqlalchemy
tk

Binary file not shown.

View file

@ -0,0 +1,54 @@
import tkinter as tk
from tkinter import ttk
import csv
from src.utils import clear_frame
import logging
from datetime import datetime
BACKGROUND_COLOR = "#403d49"
TEXT_COLOR = "#b2acc0"
HEADER_COLOR = "#2f2b38"
BUTTON_COLOR = "#444444"
logging.basicConfig(
filename="logs/logfile.log",
level=logging.INFO,
format="%(asctime)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
def log_action(action, user):
logging.info(f"{action} - Пользователь: {user}")
def show_logs(frame):
"""Отображение логов действий пользователей в тёмной теме."""
clear_frame(frame)
tk.Label(frame, text="Логи действий", font=("Comic Sans MS", 16), bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
# Настройка таблицы с логами
table = ttk.Treeview(frame, columns=("Время", "Действие", "Пользователь"), show="headings", style="Dark.Treeview")
table.heading("Время", text="Время")
table.heading("Действие", text="Действие")
table.heading("Пользователь", text="Пользователь")
table.pack(fill="both", expand=True)
# Добавление логов для примера
table.insert("", "end", values=("2024-11-19 12:30", "Добавление вопроса", "admin"))
table.insert("", "end", values=("2024-11-19 13:00", "Удаление пользователя", "moderator"))
# Применение стиля к таблице
style = ttk.Style()
style.configure("Dark.Treeview", background=BACKGROUND_COLOR, foreground=TEXT_COLOR, fieldbackground=BACKGROUND_COLOR)
style.configure("Dark.Treeview.Heading", background=HEADER_COLOR, foreground=TEXT_COLOR)
def export_logs():
data = [
("2024-11-19 12:30", "Добавление вопроса", "admin"),
("2024-11-19 13:00", "Удаление пользователя", "moderator"),
]
with open("logs.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["Время", "Действие", "Пользователь"])
writer.writerows(data)
print("Логи успешно экспортированы в logs.csv")

View file

@ -0,0 +1,17 @@
import tkinter as tk
from src.utils import clear_frame
def manage_levels(frame):
"""Создание и настройка уровней."""
clear_frame(frame)
tk.Label(frame, text="Создание и настройка уровней", font=("Comic Sans MS", 16)).pack()
# Добавить интерфейс для добавления уровней
def manage_dog_params(frame):
"""Настройка параметров собаки."""
clear_frame(frame)
tk.Label(frame, text="Настройка параметров собаки", font=("Comic Sans MS", 16)).pack()
# Добавить поля для параметров, например, здоровье, голод, сонливость

View file

@ -0,0 +1,51 @@
from tkinter import ttk
import tkinter as tk
from src.utils import clear_frame
def add_info(frame):
"""Добавление информации о породах собак."""
clear_frame(frame)
tk.Label(frame, text="Добавление информации", font=("Comic Sans MS", 16)).pack()
# Реализовать интерфейс для добавления данных
def edit_records(frame):
"""Редактирование записей в базе знаний."""
clear_frame(frame)
tk.Label(frame, text="Редактирование записей", font=("Comic Sans MS", 16)).pack()
# Реализовать интерфейс для редактирования записей
def delete_records(frame):
"""Удаление записей из базы знаний."""
clear_frame(frame)
tk.Label(frame, text="Удаление записей", font=("Comic Sans MS", 16)).pack()
# Реализовать интерфейс для удаления данных
def view_knowledge_base(frame):
"""Просмотр базы знаний."""
clear_frame(frame)
tk.Label(frame, text="База знаний", font=("Comic Sans MS", 16)).pack()
table = ttk.Treeview(frame, columns=("Порода", "Описание"), show="headings")
table.heading("Порода", text="Порода")
table.heading("Описание", text="Описание")
table.pack(fill="both", expand=True)
# Пример данных
table.insert("", "end", values=("Лабрадор", "Дружелюбная порода"))
table.insert("", "end", values=("Доберман", "Отличный сторож"))
def generate_questions(frame):
print("Я по приколу вызвался")
"""Генерация вопросов на основе текстов."""
clear_frame(frame)
tk.Label(frame, text="Генерация вопросов", font=("Comic Sans MS", 16)).pack()
# Реализовать генерацию вопросов

View file

@ -0,0 +1,17 @@
import tkinter as tk
from datetime import datetime
class Notification:
def __init__(self, parent, message, timestamp):
self.frame = tk.Frame(parent, bg="#2f2b38", pady=5)
self.frame.pack(fill="x", pady=5)
self.message_label = tk.Label(self.frame, text=message, bg="#2f2b38", fg="#b2acc0", font=("Comic Sans MS", 12))
self.message_label.pack(side="left", padx=10)
self.timestamp_label = tk.Label(self.frame, text=self.format_timestamp(timestamp), bg="#2f2b38", fg="#b2acc0", font=("Comic Sans MS", 10))
self.timestamp_label.pack(side="right", padx=10)
def format_timestamp(self, timestamp):
"""Форматирование метки времени."""
return datetime.strptime(str(timestamp), "%Y-%m-%d %H:%M:%S").strftime("%d-%m-%Y %H:%M:%S")

View file

View file

@ -0,0 +1,98 @@
import tkinter as tk
from tkinter import ttk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from src.utils import clear_frame
from database.db_session import get_session
from sqlalchemy.sql import func
from database.models import Users, GameSession, Questions # Пример моделей
def show_statistics(frame):
"""Отображение статистики."""
clear_frame(frame)
tk.Label(frame, text="Статистика", font=("Comic Sans MS", 16), bg="#403d49", fg="#b2acc0").pack(pady=10)
# Таблица с общей статистикой
table = ttk.Treeview(frame, columns=("Metric", "Value"), show="headings", height=5)
table.heading("Metric", text="Параметр")
table.heading("Value", text="Значение")
table.pack(pady=10, padx=20, fill="x", expand=True)
# Получение данных для таблицы
stats = gather_statistics()
for metric, value in stats.items():
table.insert("", tk.END, values=(metric, value))
# График активности пользователей
tk.Label(frame, text="Активность пользователей", font=("Comic Sans MS", 14), bg="#403d49", fg="#b2acc0").pack(pady=10)
fig, ax = plt.subplots(figsize=(6, 4))
time_labels, activity_values = get_user_activity()
ax.plot(time_labels, activity_values, marker="o")
ax.set_title("Активность пользователей по времени")
ax.set_xlabel("Время")
ax.set_ylabel("Количество действий")
ax.grid()
canvas = FigureCanvasTkAgg(fig, master=frame)
canvas.get_tk_widget().pack(fill="both", expand=True)
canvas.draw()
def gather_statistics():
"""Собирает основные метрики для таблицы статистики."""
session = get_session()
# Количество зарегистрированных пользователей
user_count = session.query(Users).count()
# Популярные уровни
level_data = session.query(GameSession.level, func.count(GameSession.session_id)).group_by(GameSession.level).all()
popular_levels = sorted(level_data, key=lambda x: x[1], reverse=True)[:3]
# Трудные вопросы
question_data = session.query(Questions.question_text, Questions.incorrect_attempts).order_by(Questions.incorrect_attempts.desc()).all()
hardest_questions = question_data[:3]
# Средняя продолжительность игры
avg_duration = session.query(func.avg(GameSession.duration)).scalar() or 0
# Состояние базы данных
db_size = get_database_size()
session.close()
return {
"Количество пользователей": user_count,
"Популярные уровни": ", ".join([f"Уровень {lvl} ({cnt} раз)" for lvl, cnt in popular_levels]),
"Трудные вопросы": ", ".join([f"'{text}' ({cnt} ошибок)" for text, cnt in hardest_questions]),
"Средняя продолжительность игры": f"{avg_duration:.2f} секунд",
"Объем базы данных": f"{db_size} КБ"
}
def get_user_activity():
"""Генерирует данные для графика активности пользователей."""
session = get_session()
activity_data = session.query(GameSession.start_time).all()
activity_by_hour = {}
for time in activity_data:
hour = time.start_time.hour
activity_by_hour[hour] = activity_by_hour.get(hour, 0) + 1
session.close()
if not activity_by_hour:
return ["Нет данных"], [0]
hours = sorted(activity_by_hour.keys())
activity = [activity_by_hour[hour] for hour in hours]
hours = [f"{hour}:00" for hour in hours]
return hours, activity
def get_database_size():
"""Возвращает размер базы данных в КБ."""
import os
db_path = "database/db.sqlite"
if os.path.exists(db_path):
return round(os.path.getsize(db_path) / 1024, 2)
return 0

View file

@ -1,19 +1,49 @@
from database.db_session import session
from database.models import Auth, Users
import logging
from sqlalchemy.exc import SQLAlchemyError
from database.db_session import get_session
from database.models import Auth, Users, GameSession
def register_user(login, password, username):
if session.query(Auth).filter_by(login=login).first():
return False, "Логин уже используется."
new_auth = Auth(login=login, password=password)
session.add(new_auth)
session.commit()
new_user = Users(user_id=new_auth.user_id, username=username)
session.add(new_user)
session.commit()
return True, "Регистрация успешна."
"""Регистрация нового пользователя."""
session = get_session()
try:
if session.query(Auth).filter_by(login=login).first():
return False, "Логин уже используется."
# Создаем новую запись в Auth
new_auth = Auth(login=login, password=password)
session.add(new_auth)
session.commit()
# Создаем запись в Users
new_user = Users(user_id=new_auth.user_id, username=username)
session.add(new_user)
# Создаем запись в GameSession
new_game_session = GameSession(user_id=new_user.user_id, level=1)
session.add(new_game_session)
session.commit()
return True, "Регистрация успешна."
except SQLAlchemyError as e:
session.rollback()
logging.error(f"Ошибка при регистрации: {e}")
return False, "Произошла ошибка при регистрации."
finally:
session.close()
def login_user(login, password):
user = session.query(Auth).filter_by(login=login, password=password).first()
if user:
return True, user.user_id
return False, "Неверный логин или пароль."
"""Авторизация пользователя."""
session = get_session()
try:
auth = session.query(Auth).filter_by(login=login, password=password).first()
if auth:
return True, auth.user_id
return False, "Неверный логин или пароль."
except SQLAlchemyError as e:
return False, f"Ошибка авторизации: {e}"
finally:
session.close()

View file

@ -1,16 +1,32 @@
from tkinter import Tk
from src.ui.auth_ui import DogAcademyApp # Изменил на правильный путь
from database.db_session import init_db
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from tkinter import Tk, messagebox
from src.ui.auth_ui import DogAcademyApp # Путь к приложению
from database.db_session import init_db, close_sessions # Функция для закрытия сессий
def on_close():
"""Обработчик закрытия окна."""
if messagebox.askokcancel("Выход", "Вы действительно хотите выйти?"):
print("Закрытие игры...")
close_sessions() # Закрытие всех сессий перед выходом
root.quit() # Завершаем главный цикл приложения
root.destroy() # Закрытие окна
def main():
"""Основной запуск приложения."""
# Инициализируем базу данных
global root
# Инициализация базы данных
init_db()
# Запускаем графический интерфейс
root = Tk()
# Создаем экземпляр приложения
app = DogAcademyApp(root)
root.mainloop()
root.protocol("WM_DELETE_WINDOW", on_close) # Перехват события закрытия окна
root.mainloop() # Запуск основного цикла обработки событий
if __name__ == "__main__":
root = Tk() # Создание корневого окна
root.overrideredirect(True) # Убираем рамки окна
root.geometry("1920x1080") # Устанавливаем размер окна
main()

View file

@ -0,0 +1,39 @@
from database.db_session import get_session, init_db
from database.info.Dogs_table import populate_dogs
from database.info.Questions_table import populate_questions
from database.models import Dogs, Questions
def test_data_integrity():
session = get_session()
try:
# Проверяем, есть ли собаки
dogs = session.query(Dogs).all()
assert len(dogs) > 0, "Таблица Dogs пуста!"
# Проверяем, есть ли вопросы
questions = session.query(Questions).all()
assert len(questions) > 0, "Таблица Questions пуста!"
# Проверяем связь вопросов с породами
for question in questions:
assert question.dog_id is not None, f"У вопроса {question.question_id} отсутствует dog_id"
dog = session.query(Dogs).filter_by(dog_id=question.dog_id).first()
assert dog is not None, f"Ссылка на несуществующую собаку в вопросе {question.question_id}"
print("Все тесты успешно пройдены.")
except AssertionError as e:
print(f"Ошибка теста: {e}")
finally:
session.close()
if __name__ == "__main__":
# Инициализируем базу данных (пересоздаём таблицы для чистого теста)
init_db(refresh=True)
# Заполняем таблицы
populate_dogs()
populate_questions()
# Запускаем тесты
test_data_integrity()

67
src/tests/game_test.py Normal file
View file

@ -0,0 +1,67 @@
import tkinter as tk
from src.ui.user_ui.main_menu import UserApp
from database.db_session import create_session
from database.models import Auth, Users
import logging
from config import DATABASE_URL
from sqlalchemy import create_engine
def test_user_interface():
"""Тестовый запуск пользовательского интерфейса с обходом авторизации."""
logging.basicConfig(level=logging.INFO)
# Проверка пути к базе данных
engine = create_engine(DATABASE_URL)
try:
with engine.connect() as connection:
logging.info("Подключение к базе данных успешно.")
except Exception as e:
logging.error(f"Не удалось подключиться к базе данных: {e}")
return
# Настройка окна
root = tk.Tk()
root.geometry("1920x1080")
root.title("Dog Academy Game - Тестовый режим")
# Данные для авторизации
test_login = "lubluNikitu"
test_password = "meow123"
# Проверка авторизации или создание пользователя напрямую
try:
session = create_session()
# Проверяем, существует ли пользователь в таблице Auth
user_auth = session.query(Auth).filter_by(login=test_login, password=test_password).first()
if not user_auth:
logging.warning("Пользователь не найден или пароль неверный. Создаём тестового пользователя.")
# Создаём нового пользователя в таблице Auth и Users
new_user_auth = Auth(login=test_login, password=test_password)
session.add(new_user_auth)
session.commit()
new_user = Users(username="Test User", auth=new_user_auth)
session.add(new_user)
session.commit()
user_id = new_user.user_id
else:
# Получаем user_id пользователя из таблицы Users, связанного с Auth
user_id = user_auth.user_id
logging.info(f"Пользователь найден: {test_login}")
# Запуск главного меню для пользователя
app = UserApp(root, user_id=user_id)
root.mainloop()
except Exception as e:
logging.error(f"Ошибка при взаимодействии с базой данных: {e}")
session.rollback()
finally:
session.close()
if __name__ == "__main__":
test_user_interface()

View file

@ -1,59 +1,750 @@
# admin_ui.py
import tkinter as tk
from config import BACKGROUND_COLOR, PRIMARY_COLOR, BUTTON_COLOR, BUTTON_TEXT_COLOR, FONT
from tkinter import messagebox, ttk
from PIL import Image, ImageTk
from sqlalchemy.exc import SQLAlchemyError
from config import SETTINGS_IMG
from database.db_session import get_session
from database.models import Dogs, Questions, Users
from src.admin_functions import admin_logging, statistics
from src.utils import clear_frame, feature_in_development_admin # Импортируем общую функцию для очистки фрейма
from database.db_events import check_user, get_all_users, get_all_questions, get_all_dogs, delete_dog, update_dog_info, \
add_question_to_db, add_user_to_db, add_dog_to_db, delete_question, delete_user
# Конфигурация цветов из config.py
BACKGROUND_COLOR = "#403d49"
TOP_BAR_COLOR = "#383441"
TEXT_COLOR = "#b2acc0"
BUTTON_COLOR = "#403d49"
MENU_COLOR = "#2f2b38"
MENU_OPACITY = 0.9 # Прозрачность меню
class AdminApp:
def __init__(self, root):
self.root = root
self.show_admin_dashboard()
self.root.title("Админ-Панель")
self.root.geometry("1920x1080")
self.root.config(bg=BACKGROUND_COLOR)
def show_admin_dashboard(self):
"""Показать интерфейс администратора."""
self.clear_frame()
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True)
# Верхняя панель
self.top_bar = tk.Frame(self.root, bg=TOP_BAR_COLOR, height=60)
self.top_bar.pack(side="top", fill="x")
# Заголовок
title = tk.Label(
self.current_frame,
text="Админ-Панель",
# Кнопка настроек
settings_img = Image.open(SETTINGS_IMG)
settings_img = settings_img.resize((40, 40), Image.Resampling.LANCZOS)
settings_icon = ImageTk.PhotoImage(settings_img)
self.settings_button = tk.Button(
self.top_bar,
image=settings_icon,
bg=TOP_BAR_COLOR,
activebackground=TOP_BAR_COLOR,
bd=0
)
self.settings_button.image = settings_icon # Сохраняем ссылку на изображение
self.settings_button.pack(side="left", padx=10, pady=10)
# Кнопки навигации
self.create_nav_button("Логирование", lambda: admin_logging.show_logs(self.main_frame))
self.create_nav_button("Статистика", lambda: statistics.show_statistics(self.main_frame))
self.create_nav_button("Уведомления", lambda: self.show_notifications(self.main_frame))
self.create_nav_button("Безопасность", lambda: self.show_security(self.main_frame))
self.create_nav_button("Открыть сессию пользователя", self.open_user_session)
# Бургер-меню
self.menu_button = tk.Button(
self.top_bar,
text="☰ Меню",
bg=BUTTON_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 14),
activebackground=BUTTON_COLOR,
activeforeground=TEXT_COLOR,
bd=0,
command=self.toggle_menu
)
self.menu_button.pack(side="right", padx=10, pady=10)
# Основное окно
self.main_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.main_frame.pack(fill="both", expand=True)
# Бургер-меню (скрытое по умолчанию)
self.menu_frame = tk.Frame(self.root, bg=MENU_COLOR, width=300)
self.menu_frame.place(x=1620, y=60, width=300, height=1020)
self.menu_frame.lower()
self.menu_visible = False
def toggle_menu(self):
"""Показ или скрытие меню."""
if self.menu_visible:
self.menu_frame.lower()
self.menu_visible = False
else:
self.menu_frame.lift()
self.menu_visible = True
self.populate_menu()
def populate_menu(self):
# Очистка меню
for widget in self.menu_frame.winfo_children():
widget.destroy()
# Список разделов и их элементов
menu_sections = [
("Работа с базой данных", [
("Редактирование пользователей", self.manage_users),
("Управление вопросами", self.manage_questions),
("Управление собаками", self.manage_dogs),
("Просмотр таблиц", self.view_tables),
]),
("Управление игровым контентом", [
("Создание и настройка уровней", lambda: feature_in_development_admin(self.main_frame)),
("Настройка параметров собаки", lambda: feature_in_development_admin(self.main_frame)),
]),
("Управление интерфейсом пользователя", [
("Добавление подсказок в интерфейс", lambda: feature_in_development_admin(self.main_frame)),
])
]
# Определяем максимальную ширину текста для настройки ширины меню и кнопок
max_text_length = max(
len(title) for title, items in menu_sections
) + max(
max(len(text) for text, _ in items) for _, items in menu_sections
)
menu_width = max(300, max_text_length * 10) # Устанавливаем минимальную ширину
# Обновляем ширину меню
self.menu_frame.config(width=menu_width)
# Высота одной кнопки и отступов
button_height = 40
button_spacing = 10
section_spacing = 15
total_height = 0
for title, items in menu_sections:
section_label = tk.Label(
self.menu_frame,
text=title,
bg=MENU_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 14, "bold"),
)
section_label.pack(fill="x", padx=10, pady=5)
for text, command in items:
item_button = tk.Button(
self.menu_frame,
text=text,
bg=BUTTON_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 12),
activebackground=BUTTON_COLOR,
activeforeground=TEXT_COLOR,
bd=0,
command=command # Используем lambda, чтобы передать команду без аргументов
)
item_button.pack(fill="x", padx=20, pady=5)
# Кнопка "Выйти" внизу меню
exit_button = tk.Button(
self.menu_frame,
text="Выйти",
bg=BUTTON_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 12),
activebackground=BUTTON_COLOR,
activeforeground=TEXT_COLOR,
bd=0,
command=self.exit_app
)
exit_button.pack(side="bottom", padx=10, pady=20) # Размещение внизу
def create_nav_button(self, text, command):
"""Создание кнопки навигации."""
button = tk.Button(
self.top_bar,
text=text,
bg=BUTTON_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 14),
activebackground=BUTTON_COLOR,
activeforeground=TEXT_COLOR,
bd=0,
padx=10,
pady=5,
command=command # Передаем функцию напрямую
)
button.pack(side="left", padx=10, pady=10)
def open_manage_dogs_window(self, frame):
"""Открыть окно для управления собаками."""
self.manage_dogs()
def manage_ui_tips(self, frame):
# Пример логики для управления подсказками
print("Управление подсказками интерфейса.")
# Код для управления подсказками (например, скрытие или показ подсказок)
tk.Label(frame, text="Здесь будут подсказки для интерфейса", bg=BACKGROUND_COLOR, fg=TEXT_COLOR, font=("Comic Sans MS", 16)).pack()
def show_notifications(self, frame):
"""Отображение экрана уведомлений"""
clear_frame(frame) # Очищаем текущий экран
tk.Label(
frame,
text="Модуль <Уведомления> в разработке.\nВ планах реализовать: создание оповещений для пользователей (обновления, новости), сообщения от БД (корректность работы)",
bg=BACKGROUND_COLOR,
fg=PRIMARY_COLOR,
font=FONT,
)
title.pack(pady=50)
fg=TEXT_COLOR,
font=("Comic Sans MS", 16)
).pack(expand=True)
# Кнопка для управления вопросами
manage_questions_button = tk.Button(
self.current_frame,
text="Управление вопросами",
def show_security(self, frame):
"""Отображение экрана безопасности"""
clear_frame(frame) # Очищаем текущий экран
tk.Label(
frame,
text="Модуль <Безопасность> в разработке.\nВ планах реализовать: управление доступом (создание других админов, смена пароля администратора).",
bg=BACKGROUND_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 16)
).pack(expand=True)
def change_ui_settings(self, frame):
clear_frame(frame)
"""Метод для изменения цветовой схемы, фона и логотипа"""
print("Изменение UI настроек") # Пока просто тестовый вывод
def exit_app(self):
"""Закрыть приложение."""
self.root.quit()
# Метод для авторизации под пользователем
def open_user_session(self):
"""Открыть новую сессию пользователя."""
user_login_window = tk.Toplevel(self.root)
user_login_window.title("Авторизация пользователя")
user_login_window.geometry("400x300")
user_login_window.configure(bg=BACKGROUND_COLOR)
tk.Label(
user_login_window,
text="Введите логин пользователя:",
bg=BACKGROUND_COLOR,
fg=TEXT_COLOR,
font=("Comic Sans MS", 12)
).pack(pady=20)
user_login_entry = tk.Entry(user_login_window, font=("Comic Sans MS", 12))
user_login_entry.pack(pady=10)
def open_user_interface():
login = user_login_entry.get() # Получаем логин из поля ввода
user_id = check_user(login) # Передаем логин для проверки
if user_id:
user_login_window.destroy()
user_window = tk.Toplevel(self.root)
from src.ui.user_ui.main_menu import UserApp
UserApp(user_window, user_id=user_id)
else:
messagebox.showerror("Ошибка", "Пользователь не найден.")
tk.Button(
user_login_window,
text="Открыть сессию",
bg=BUTTON_COLOR,
fg=BUTTON_TEXT_COLOR,
font=FONT,
command=self.manage_questions,
)
manage_questions_button.pack(pady=20)
fg=TEXT_COLOR,
font=("Comic Sans MS", 12),
command=open_user_interface
).pack(pady=20)
# Кнопка для управления пользователями
manage_users_button = tk.Button(
self.current_frame,
text="Управление пользователями",
tk.Button(
user_login_window,
text="Отмена",
bg=BUTTON_COLOR,
fg=BUTTON_TEXT_COLOR,
font=FONT,
command=self.manage_users,
)
manage_users_button.pack(pady=20)
def manage_questions(self):
"""Управление вопросами в игре."""
pass
fg=TEXT_COLOR,
font=("Comic Sans MS", 12),
command=user_login_window.destroy
).pack(pady=10)
def manage_users(self):
"""Управление пользователями игры."""
pass
"""Управление пользователями."""
clear_frame(self.main_frame)
tk.Label(self.main_frame, text="Управление пользователями", font=("Comic Sans MS", 16), bg=BACKGROUND_COLOR,
fg=TEXT_COLOR).pack()
# Кнопка добавления нового пользователя
tk.Button(
self.main_frame,
text="Добавить пользователя",
command=self.open_add_user_window,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
# Кнопка обновления списка
tk.Button(
self.main_frame,
text="Обновить список",
command=self.manage_users, # Перезагрузка данных
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
users = get_all_users() # Получение списка пользователей
if not users:
tk.Label(self.main_frame, text="Нет пользователей в базе данных.", bg=BACKGROUND_COLOR,
fg=TEXT_COLOR).pack()
return
# Отображение данных в таблице
table = ttk.Treeview(self.main_frame, columns=("ID", "Логин", "Имя пользователя", "Уровень"), show="headings")
table.heading("ID", text="ID")
table.heading("Логин", text="Логин")
table.heading("Имя пользователя", text="Имя пользователя")
table.heading("Уровень", text="Уровень")
table.pack(fill="both", expand=True, pady=10)
# Очистка старых записей из таблицы
for row in table.get_children():
table.delete(row)
# Добавление данных из базы
for user in users:
table.insert("", "end", values=(user.user_id, user.auth.login, user.username, user.level))
def delete_selected():
selected_item = table.selection()
if not selected_item:
messagebox.showwarning("Удаление", "Выберите пользователя для удаления.")
return
user_id = table.item(selected_item, "values")[0]
success, message = delete_user(user_id)
if success:
messagebox.showinfo("Успех", message)
self.manage_users() # Обновление списка
else:
messagebox.showerror("Ошибка", message)
# Кнопка удаления
tk.Button(
self.main_frame,
text="Удалить выбранного пользователя",
command=delete_selected,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
def manage_questions(self):
"""Управление вопросами."""
clear_frame(self.main_frame)
tk.Label(self.main_frame, text="Управление вопросами", font=("Comic Sans MS", 16), bg=BACKGROUND_COLOR,
fg=TEXT_COLOR).pack()
# Кнопка добавления нового вопроса
tk.Button(
self.main_frame,
text="Добавить вопрос",
command=self.open_add_question_window,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
# Кнопка обновления списка
tk.Button(
self.main_frame,
text="Обновить список",
command=self.manage_questions, # Перезагрузка данных
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
questions = get_all_questions() # Получение списка вопросов
if not questions:
tk.Label(self.main_frame, text="Нет вопросов в базе данных.", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack()
return
# Отображение данных в таблице
table = ttk.Treeview(self.main_frame, columns=("ID", "Вопрос", "Полезная информация"), show="headings")
table.heading("ID", text="ID")
table.heading("Вопрос", text="Вопрос")
table.heading("Полезная информация", text="Полезная информация")
table.pack(fill="both", expand=True, pady=10)
# Очистка таблицы перед заполнением новыми данными
for row in table.get_children():
table.delete(row)
for question in questions:
table.insert("", "end", values=(question.question_id, question.question_text, question.helpful_info))
def delete_selected():
selected_item = table.selection()
if not selected_item:
messagebox.showwarning("Удаление", "Выберите вопрос для удаления.")
return
question_id = table.item(selected_item, "values")[0] # Получение ID вопроса
success, message = delete_question(question_id) # Вызов метода для удаления вопроса
if success:
messagebox.showinfo("Успех", message)
self.manage_questions() # Обновление списка вопросов
else:
messagebox.showerror("Ошибка", message)
# Кнопка удаления
tk.Button(
self.main_frame,
text="Удалить выбранный вопрос",
command=delete_selected,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
def manage_dogs(self):
"""Управление породами собак."""
clear_frame(self.main_frame)
# Заголовок
tk.Label(self.main_frame, text="Управление породами собак", font=("Comic Sans MS", 16), bg=BACKGROUND_COLOR,
fg=TEXT_COLOR).pack()
# Функция удаления выбранной породы
def delete_selected():
selected_item = table.selection()
if not selected_item:
messagebox.showwarning("Удаление", "Выберите породу для удаления.")
return
dog_id = table.item(selected_item, "values")[0] # ID породы
success, message = delete_dog(dog_id)
if success:
messagebox.showinfo("Успех", message)
self.manage_dogs() # Обновление списка
else:
messagebox.showerror("Ошибка", message)
# Функция редактирования выбранной породы
def edit_selected():
selected_item = table.selection()
if not selected_item:
messagebox.showwarning("Редактирование", "Выберите породу для редактирования.")
return
# Получение данных выбранной породы
dog_data = table.item(selected_item, "values")
# Пример dog_data: ('dog_id', 'breed', 'characteristics', 'behavior', 'care_info', 'admin_comments')
if len(dog_data) < 6:
messagebox.showwarning("Ошибка", "Недостаточно данных для редактирования.")
return
dog_id = dog_data[0]
breed = dog_data[1]
characteristics = dog_data[2]
behavior = dog_data[3]
care_info = dog_data[4] # Дополнительная информация о породе
admin_comments = dog_data[5] # Комментарии администратора
# Вызов функции открытия окна редактирования породы, передавая все необходимые данные
self.open_edit_dog_window(dog_id, breed, characteristics, behavior, care_info, admin_comments)
# Кнопка добавления новой породы
tk.Button(
self.main_frame,
text="Добавить породу",
command=self.open_add_dog_window,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
# Кнопка обновления списка
tk.Button(
self.main_frame,
text="Обновить список",
command=self.manage_dogs, # Повторный вызов для обновления данных
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
# Кнопка удаления
tk.Button(
self.main_frame,
text="Удалить выбранную породу",
command=delete_selected,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
# Кнопка редактирования
tk.Button(
self.main_frame,
text="Редактировать выбранную породу",
command=edit_selected,
bg=BUTTON_COLOR,
fg=TEXT_COLOR
).pack(pady=10)
# Получение данных из базы
dogs = get_all_dogs()
if not dogs:
tk.Label(self.main_frame, text="Нет записей о породах в базе данных.", bg=BACKGROUND_COLOR,
fg=TEXT_COLOR).pack()
return
# Создание таблицы
table = ttk.Treeview(self.main_frame, columns=(
"ID", "Порода", "Характеристики", "Поведение", "Информация по уходу", "Комментарии"), show="headings")
table.heading("ID", text="ID")
table.heading("Порода", text="Порода")
table.heading("Характеристики", text="Характеристики")
table.heading("Поведение", text="Поведение")
table.heading("Информация по уходу", text="Информация по уходу")
table.heading("Комментарии", text="Комментарии")
table.pack(fill="both", expand=True, pady=10)
# Заполнение таблицы данными о породах
for dog in dogs:
table.insert("", "end", values=(
dog.dog_id, dog.breed, dog.characteristics, dog.behavior, dog.care_info, dog.admin_comments))
def open_edit_dog_window(self, dog_id, breed, characteristics, behavior, care_info, admin_comments):
"""Открыть окно редактирования данных о породе собак."""
edit_dog_window = tk.Toplevel(self.root)
edit_dog_window.title("Редактировать данные породы")
edit_dog_window.geometry("500x400")
edit_dog_window.configure(bg=BACKGROUND_COLOR)
fields = {
"Порода": (breed, tk.Entry(edit_dog_window, font=("Comic Sans MS", 12))),
"Характеристики": (characteristics, tk.Entry(edit_dog_window, font=("Comic Sans MS", 12))),
"Поведение": (behavior, tk.Entry(edit_dog_window, font=("Comic Sans MS", 12))),
"Уход": (care_info, tk.Entry(edit_dog_window, font=("Comic Sans MS", 12))),
"Комментарии администратора": (admin_comments, tk.Entry(edit_dog_window, font=("Comic Sans MS", 12))),
}
for idx, (label_text, (value, entry)) in enumerate(fields.items()):
tk.Label(edit_dog_window, text=label_text, bg=BACKGROUND_COLOR, fg=TEXT_COLOR,
font=("Comic Sans MS", 12)).grid(row=idx, column=0, pady=10, padx=10)
entry.insert(0, value)
entry.grid(row=idx, column=1, pady=10, padx=10)
def save_changes():
updated_data = {key: entry.get() for key, (_, entry) in fields.items()}
success, message = update_dog_info(dog_id, updated_data["Порода"], updated_data["Характеристики"])
if success:
messagebox.showinfo("Успех", message)
edit_dog_window.destroy()
self.manage_dogs() # Обновление списка пород
else:
messagebox.showerror("Ошибка", message)
tk.Button(edit_dog_window, text="Сохранить", command=save_changes, bg=BUTTON_COLOR, fg=TEXT_COLOR).grid(
row=len(fields), column=0, pady=20)
tk.Button(edit_dog_window, text="Отмена", command=edit_dog_window.destroy, bg=BUTTON_COLOR, fg=TEXT_COLOR).grid(
row=len(fields), column=1, pady=20)
def view_tables(self):
"""Просмотр всех таблиц."""
clear_frame(self.main_frame)
tk.Label(self.main_frame, text="Просмотр всех таблиц", font=("Comic Sans MS", 16), bg=BACKGROUND_COLOR,
fg=TEXT_COLOR).pack()
# Создаём вкладки для отображения таблиц
tab_control = ttk.Notebook(self.main_frame)
# Таблица пользователей
users_frame = ttk.Frame(tab_control)
tab_control.add(users_frame, text="Пользователи")
users_data = get_all_users()
if users_data:
self.create_table_view(users_frame, users_data, ["user_id", "login", "username", "level"])
else:
tk.Label(users_frame, text="Нет данных о пользователях.", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack()
# Таблица собак
dogs_frame = ttk.Frame(tab_control)
tab_control.add(dogs_frame, text="Породы собак")
dogs_data = get_all_dogs()
if dogs_data:
self.create_table_view(dogs_frame, dogs_data, ["dog_id", "breed", "characteristics", "behavior"])
else:
tk.Label(dogs_frame, text="Нет данных о породах собак.", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack()
# Таблица вопросов
questions_frame = ttk.Frame(tab_control)
tab_control.add(questions_frame, text="Вопросы")
questions_data = get_all_questions()
if questions_data:
self.create_table_view(questions_frame, questions_data, ["question_id", "question_text", "helpful_info"])
else:
tk.Label(questions_frame, text="Нет данных о вопросах.", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack()
tab_control.pack(expand=True, fill="both")
def create_table_view(self, frame, data, columns):
"""Создание и отображение таблицы на основе данных и столбцов."""
# Создаём таблицу
table = ttk.Treeview(frame, columns=columns, show="headings")
# Заголовки таблицы
for col in columns:
table.heading(col, text=col)
table.column(col, anchor="center") # Выравнивание заголовков по центру
# Заполнение таблицы данными
for row in data:
if isinstance(row, dict): # Если данные представлены в виде словаря
values = [row.get(col, "") for col in columns]
elif hasattr(row, "__dict__"): # Если данные — это объект SQLAlchemy
values = [getattr(row, col, "") for col in columns]
else:
values = row if isinstance(row, (list, tuple)) else []
table.insert("", "end", values=values)
# Устанавливаем таблицу в интерфейс
table.pack(fill="both", expand=True, pady=10)
def open_add_dog_window(self):
"""Открыть окно для добавления новой собаки."""
add_dog_window = tk.Toplevel(self.root)
add_dog_window.title("Добавить новую собаку")
add_dog_window.geometry("400x300")
add_dog_window.configure(bg=BACKGROUND_COLOR)
tk.Label(add_dog_window, text="Порода", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
breed_entry = tk.Entry(add_dog_window, font=("Comic Sans MS", 12))
breed_entry.pack(pady=5)
tk.Label(add_dog_window, text="Характеристики", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
characteristics_entry = tk.Entry(add_dog_window, font=("Comic Sans MS", 12))
characteristics_entry.pack(pady=5)
tk.Label(add_dog_window, text="Поведение", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
behavior_entry = tk.Entry(add_dog_window, font=("Comic Sans MS", 12))
behavior_entry.pack(pady=5)
tk.Label(add_dog_window, text="Уход", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
care_info_entry = tk.Entry(add_dog_window, font=("Comic Sans MS", 12))
care_info_entry.pack(pady=5)
tk.Label(add_dog_window, text="Комментарии администратора", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
admin_comments_entry = tk.Entry(add_dog_window, font=("Comic Sans MS", 12))
admin_comments_entry.pack(pady=5)
def save_dog():
dog_data = {
'breed': breed_entry.get(),
'characteristics': characteristics_entry.get(),
'behavior': behavior_entry.get(),
'care_info': care_info_entry.get(),
'admin_comments': admin_comments_entry.get()
}
add_dog_to_db(dog_data)
add_dog_window.destroy()
def cancel_add():
add_dog_window.destroy()
save_button = tk.Button(add_dog_window, text="Сохранить", command=save_dog, bg=BUTTON_COLOR, fg=TEXT_COLOR)
save_button.pack(pady=20)
cancel_button = tk.Button(add_dog_window, text="Отменить", command=cancel_add, bg=BUTTON_COLOR, fg=TEXT_COLOR)
cancel_button.pack(pady=10)
def open_add_user_window(self):
"""Открыть окно для добавления нового пользователя."""
add_user_window = tk.Toplevel(self.root)
add_user_window.title("Добавить нового пользователя")
add_user_window.geometry("400x300")
add_user_window.configure(bg=BACKGROUND_COLOR)
tk.Label(add_user_window, text="Логин", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
login_entry = tk.Entry(add_user_window, font=("Comic Sans MS", 12))
login_entry.pack(pady=5)
tk.Label(add_user_window, text="Пароль", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
password_entry = tk.Entry(add_user_window, font=("Comic Sans MS", 12), show="*")
password_entry.pack(pady=5)
tk.Label(add_user_window, text="Имя пользователя", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
username_entry = tk.Entry(add_user_window, font=("Comic Sans MS", 12))
username_entry.pack(pady=5)
def save_user():
user_data = {
'login': login_entry.get(),
'password': password_entry.get(),
'username': username_entry.get(),
}
try:
add_user_to_db(user_data)
messagebox.showinfo("Успех", "Пользователь успешно добавлен.")
add_user_window.destroy()
self.manage_users() # Обновить список пользователей
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось добавить пользователя: {e}")
def cancel_add():
add_user_window.destroy()
save_button = tk.Button(add_user_window, text="Сохранить", command=save_user, bg=BUTTON_COLOR, fg=TEXT_COLOR)
save_button.pack(pady=20)
cancel_button = tk.Button(add_user_window, text="Отменить", command=cancel_add, bg=BUTTON_COLOR, fg=TEXT_COLOR)
cancel_button.pack(pady=10)
def open_add_question_window(self):
"""Открыть окно для добавления нового вопроса."""
add_question_window = tk.Toplevel(self.root)
add_question_window.title("Добавить новый вопрос")
add_question_window.geometry("400x300")
add_question_window.configure(bg=BACKGROUND_COLOR)
tk.Label(add_question_window, text="ID собаки", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
dog_id_entry = tk.Entry(add_question_window, font=("Comic Sans MS", 12))
dog_id_entry.pack(pady=5)
tk.Label(add_question_window, text="Вопрос", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
question_text_entry = tk.Entry(add_question_window, font=("Comic Sans MS", 12))
question_text_entry.pack(pady=5)
tk.Label(add_question_window, text="Изображение URL", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
image_url_entry = tk.Entry(add_question_window, font=("Comic Sans MS", 12))
image_url_entry.pack(pady=5)
tk.Label(add_question_window, text="Полезная информация", bg=BACKGROUND_COLOR, fg=TEXT_COLOR).pack(pady=10)
helpful_info_entry = tk.Entry(add_question_window, font=("Comic Sans MS", 12))
helpful_info_entry.pack(pady=5)
def save_question():
question_data = {
'dog_id': int(dog_id_entry.get()),
'question_text': question_text_entry.get(),
'image_url': image_url_entry.get(),
'helpful_info': helpful_info_entry.get()
}
add_question_to_db(question_data)
add_question_window.destroy()
def cancel_add():
add_question_window.destroy()
save_button = tk.Button(add_question_window, text="Сохранить", command=save_question, bg=BUTTON_COLOR, fg=TEXT_COLOR)
save_button.pack(pady=20)
cancel_button = tk.Button(add_question_window, text="Отменить", command=cancel_add, bg=BUTTON_COLOR, fg=TEXT_COLOR)
cancel_button.pack(pady=10)
def clear_frame(self):
"""Очистить текущий фрейм."""
if hasattr(self, 'current_frame') and self.current_frame:
self.current_frame.destroy()

View file

@ -1,13 +1,16 @@
import tkinter as tk
from tkinter import messagebox
from config import BACKGROUND_COLOR, PRIMARY_COLOR, BUTTON_COLOR, BUTTON_TEXT_COLOR, FONT, BIG_FONT, ADMIN_LOGIN, ADMIN_PASSWORD
from src.auth import login_user
from src.ui.admin_ui import AdminApp # Импорт интерфейса администратора
from database.db_events import create_user, check_user
from src.ui.user_ui import UserApp
from database.db_events import create_user
from src.ui.user_ui.main_menu import UserApp
class DogAcademyApp:
def __init__(self, root):
def __init__(self, root, user_id=None):
"""Инициализация приложения."""
self.root = root
self.user_id = user_id
self.root.title("Dog Academy Game")
self.root.geometry("1920x1080")
self.root.configure(bg=BACKGROUND_COLOR)
@ -20,12 +23,11 @@ class DogAcademyApp:
self.current_frame.destroy()
def show_main_menu(self):
"""Показать главное меню с названием игры и кнопками."""
"""Показать главное меню."""
self.clear_frame()
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True)
# Название игры
title = tk.Label(
self.current_frame,
text="Dog Academy Game",
@ -35,7 +37,6 @@ class DogAcademyApp:
)
title.pack(pady=50)
# Кнопка "Войти"
login_button = tk.Button(
self.current_frame,
text="Войти",
@ -46,7 +47,6 @@ class DogAcademyApp:
)
login_button.pack(pady=20)
# Кнопка "Зарегистрироваться"
register_button = tk.Button(
self.current_frame,
text="Зарегистрироваться",
@ -63,7 +63,6 @@ class DogAcademyApp:
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True)
# Заголовок
title = tk.Label(
self.current_frame,
text="Авторизация",
@ -73,15 +72,16 @@ class DogAcademyApp:
)
title.pack(pady=50)
# Логин
login_label = tk.Label(self.current_frame, text="Логин:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
login_label.pack()
self.login_entry = tk.Entry(self.current_frame, font=FONT)
self.login_entry.pack(pady=10)
# Пароль
password_label = tk.Label(self.current_frame, text="Пароль:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
password_label.pack()
self.password_entry = tk.Entry(self.current_frame, show="*", font=FONT)
self.password_entry.pack(pady=10)
# Кнопка "Показать пароль"
show_password_button = tk.Button(
self.current_frame,
text="Показать пароль",
@ -92,7 +92,6 @@ class DogAcademyApp:
)
show_password_button.pack(pady=10)
# Кнопка "Войти"
login_button = tk.Button(
self.current_frame,
text="Войти",
@ -103,7 +102,6 @@ class DogAcademyApp:
)
login_button.pack(pady=20)
# Кнопка "Вернуться на главную"
back_button = tk.Button(
self.current_frame,
text="Вернуться на главную",
@ -128,17 +126,21 @@ class DogAcademyApp:
if login == ADMIN_LOGIN and password == ADMIN_PASSWORD:
messagebox.showinfo("Успех", "Вы успешно авторизованы как администратор!")
self.show_admin_panel() # Переходим к админ-панели
elif check_user(login, password):
messagebox.showinfo("Успех", "Вы успешно авторизованы!")
self.show_user_dashboard() # Переходим к панели пользователя
self.user_id = None # Администратору не нужен user_id
self.show_admin_panel()
else:
messagebox.showerror("Ошибка", "Неверные данные. Попробуйте снова.")
success, user_id = login_user(login, password)
if success:
messagebox.showinfo("Успех", "Вы успешно авторизованы!")
self.user_id = user_id # Сохраняем user_id
self.show_user_dashboard()
else:
messagebox.showerror("Ошибка", "Неверный логин или пароль.")
def show_admin_panel(self):
"""Отображение интерфейса администратора."""
self.clear_frame()
AdminApp(self.root) # Создаем экземпляр админ-панели
AdminApp(self.root)
def show_registration_screen(self):
"""Показать экран регистрации."""
@ -146,7 +148,6 @@ class DogAcademyApp:
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True)
# Заголовок
title = tk.Label(
self.current_frame,
text="Регистрация",
@ -156,26 +157,21 @@ class DogAcademyApp:
)
title.pack(pady=50)
# Логин
login_label = tk.Label(self.current_frame, text="Логин:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
login_label.pack()
self.reg_login_entry = tk.Entry(self.current_frame, font=FONT)
self.reg_login_entry.pack(pady=10)
# Пароль
password_label = tk.Label(self.current_frame, text="Пароль:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
password_label.pack()
self.reg_password_entry = tk.Entry(self.current_frame, show="*", font=FONT)
self.reg_password_entry.pack(pady=10)
# Кнопка "Показать пароль"
show_password_button = tk.Button(
self.current_frame,
text="Показать пароль",
bg=BUTTON_COLOR,
fg=BUTTON_TEXT_COLOR,
font=FONT,
command=self.toggle_registration_password,
)
show_password_button.pack(pady=10)
username_label = tk.Label(self.current_frame, text="Никнейм:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
username_label.pack()
self.username_entry = tk.Entry(self.current_frame, font=FONT)
self.username_entry.pack(pady=10)
# Кнопка "Зарегистрироваться"
register_button = tk.Button(
self.current_frame,
text="Зарегистрироваться",
@ -186,7 +182,6 @@ class DogAcademyApp:
)
register_button.pack(pady=20)
# Кнопка "Вернуться на главную"
back_button = tk.Button(
self.current_frame,
text="Вернуться на главную",
@ -208,15 +203,19 @@ class DogAcademyApp:
"""Регистрация нового пользователя."""
login = self.reg_login_entry.get()
password = self.reg_password_entry.get()
username = self.username_entry.get()
if login and password:
create_user(login, password)
messagebox.showinfo("Успех", "Вы успешно зарегистрированы!")
self.show_login_screen()
if login and password and username:
success, message = create_user(login, password, username)
if success:
messagebox.showinfo("Успех", message)
self.show_login_screen()
else:
messagebox.showerror("Ошибка", message)
else:
messagebox.showerror("Ошибка", "Пожалуйста, заполните все поля.")
messagebox.showerror("Ошибка", "Заполните все поля.")
def show_user_dashboard(self):
"""Перейти к главному меню пользователя после авторизации."""
UserApp(self.root, self)
"""Переход к пользовательскому интерфейсу."""
self.clear_frame()
UserApp(self.root, self.user_id)

View file

@ -1,56 +0,0 @@
import tkinter as tk
from config import BACKGROUND_COLOR, PRIMARY_COLOR, BUTTON_COLOR, BUTTON_TEXT_COLOR, FONT
class UserApp:
def __init__(self, root, dog_academy_app):
self.root = root
self.dog_academy_app = dog_academy_app # Сохраняем ссылку на DogAcademyApp
self.show_user_dashboard()
def show_user_dashboard(self):
"""Показать интерфейс пользователя."""
self.clear_frame()
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True)
# Заголовок
title = tk.Label(
self.current_frame,
text="Главное меню",
bg=BACKGROUND_COLOR,
fg=PRIMARY_COLOR,
font=FONT,
)
title.pack(pady=50)
# Кнопка "Играть"
play_button = tk.Button(
self.current_frame,
text="Играть",
bg=BUTTON_COLOR,
fg=BUTTON_TEXT_COLOR,
font=FONT,
command=self.play_game,
)
play_button.pack(pady=20)
# Кнопка "Выход"
logout_button = tk.Button(
self.current_frame,
text="Выход",
bg=BUTTON_COLOR,
fg=BUTTON_TEXT_COLOR,
font=FONT,
command=self.dog_academy_app.show_main_menu, # Вызываем метод из DogAcademyApp
)
logout_button.pack(pady=20)
def play_game(self):
"""Запуск игры."""
# TODO: Логика игры
pass
def clear_frame(self):
"""Очистить текущий фрейм."""
if hasattr(self, 'current_frame') and self.current_frame:
self.current_frame.destroy()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

649
src/ui/user_ui/game_ui.py Normal file
View file

@ -0,0 +1,649 @@
import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk
import random
import logging
from database.db_events import get_user_by_id, get_user_progress
from database.info.GameSessions_table import save_game_session
from src.user_functions.game_logs import setup_logging
from config import DOG_CHARACTERS, DONE, BONE, BACKGROUND_GAME
from src.utils import clear_frame
# Настройка логирования
setup_logging()
user = get_user_by_id(user_id=1)
if user:
print(f"Данные пользователя: {user}")
else:
print("Пользователь не найден")
class GameUI:
def __init__(self, root, user_id, return_to_main_menu_callback):
if not user_id:
raise ValueError("user_id отсутствует при инициализации GameUI!")
self.root = root
self.user_id = user_id
self.return_to_main_menu_callback = return_to_main_menu_callback
self.selected_dog = None
self.current_level = 1
self.completed_levels = set()
self.total_bones = 0
self.dog_position = [1, 1]
self.map_canvas = None
self.bones_positions = []
self.max_bones_per_level = 10
self.steps_taken = 0
self.user_data = get_user_by_id(self.user_id)
# Получаем прогресс пользователя
self.user_progress = get_user_progress(user_id)
self.max_unlocked_level = max([session.level for session in self.user_progress]) if self.user_progress else 1
# Добавляем атрибут is_replay
self.is_replay = False # По умолчанию нет повторного прохождения
# Изображения
self.done_image = ImageTk.PhotoImage(Image.open(DONE).resize((50, 50), Image.Resampling.LANCZOS))
self.bones_photo = ImageTk.PhotoImage(Image.open(BONE).resize((50, 50), Image.Resampling.LANCZOS))
# Размер сетки
self.grid_size = 60
self.cols = 32
self.rows = 18
# Настройки окна
self.root.geometry("1920x1080")
self.root.configure(bg="#E5E5E5")
# Флаги
self.is_pause_menu_open = False
self.is_victory_screen_open = False
self.is_game_active = False
# Привязка клавиш
self.root.bind("<KeyPress-w>", self.move_up)
self.root.bind("<KeyPress-s>", self.move_down)
self.root.bind("<KeyPress-a>", self.move_left)
self.root.bind("<KeyPress-d>", self.move_right)
self.root.bind("<Escape>", self.on_escape)
# Отображение начального экрана
self.show_dog_selection()
if self.user_data:
self.max_unlocked_level = self.user_data.level or 1
self.total_bones = sum([session.score for session in get_user_progress(self.user_id)])
else:
logging.warning("Данные пользователя не найдены")
def create_background(self):
"""Создаёт фон для игры."""
try:
bg_image = Image.open(BACKGROUND_GAME)
bg_photo = ImageTk.PhotoImage(bg_image.resize((1920, 1080), Image.Resampling.LANCZOS))
bg_label = tk.Label(self.root, image=bg_photo)
bg_label.image = bg_photo
bg_label.place(x=0, y=0, relwidth=1, relheight=1)
except Exception as e:
logging.error(f"Ошибка загрузки фона: {e}")
def show_dog_selection(self):
"""Отображение выбора собаки пользователем."""
clear_frame(self.root)
self.create_background()
tk.Label(
self.root, text="Выберите собаку", font=("Comic Sans MS", 24), bg="#E5E5E5"
).pack(pady=20)
dog_frame = tk.Frame(self.root, bg="#E5E5E5")
dog_frame.pack(pady=50)
dog_size = 150
for breed, details in DOG_CHARACTERS.items():
try:
dog_image = Image.open(details["image"]).resize((dog_size, dog_size), Image.Resampling.LANCZOS)
dog_photo = ImageTk.PhotoImage(dog_image)
dog_container = tk.Frame(dog_frame, bg="#E5E5E5")
dog_container.pack(side=tk.LEFT, padx=15)
button = tk.Button(
dog_container,
image=dog_photo,
command=lambda b=breed: self.confirm_dog_selection(b),
bg="#E5E5E5",
borderwidth=0,
)
button.image = dog_photo
button.pack()
tk.Label(dog_container, text=breed, font=("Comic Sans MS", 14), bg="#E5E5E5").pack()
except Exception as e:
logging.error(f"Ошибка загрузки изображения для собаки {breed}: {e}")
tk.Button(
self.root,
text="Вернуться",
font=("Comic Sans MS", 16),
bg="lightgreen",
command=self.return_to_main_menu_callback,
).place(relx=0.5, rely=0.9, anchor=tk.CENTER)
def confirm_dog_selection(self, breed):
"""Подтверждение выбора собаки."""
self.selected_dog = breed
self.show_level_selection()
def show_level_selection(self):
"""Отображение выбора уровня."""
clear_frame(self.root)
self.create_background()
tk.Label(self.root, text="Выберите уровень", font=("Comic Sans MS", 24), bg="#E5E5E5").pack(pady=20)
self.level_frame = tk.Frame(self.root, bg="#E5E5E5")
self.level_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
progress = get_user_progress(self.user_id)
self.completed_levels = {session.level for session in progress if session.score > 0}
self.max_unlocked_level = max(self.completed_levels) + 1 if self.completed_levels else 1
for level in range(1, 101):
color = (
"#4CAF50" if level in self.completed_levels else
"#FFEB3B" if level == self.max_unlocked_level else
"#A9A9A9"
)
state = tk.NORMAL if level <= self.max_unlocked_level else tk.DISABLED
button = tk.Button(
self.level_frame,
text=f"Уровень {level}",
bg=color,
state=state,
font=("Comic Sans MS", 14),
command=lambda l=level: self.handle_level_selection(l)
)
button.grid(row=(level - 1) // 10, column=(level - 1) % 10, padx=5, pady=5)
self.update_level_buttons() # Обновляем кнопки уровней
tk.Button(
self.root,
text="Вернуться",
font=("Comic Sans MS", 16),
bg="lightgreen",
command=self.show_dog_selection
).place(relx=0.5, rely=0.9, anchor=tk.CENTER)
def handle_level_selection(self, level):
"""Обработка выбора уровня."""
if level in self.completed_levels:
if messagebox.askyesno("Повторить уровень", f"Вы уже прошли уровень {level}. Хотите пройти его заново?"):
self.is_replay = True
self.current_level = level
self.countdown() # Обратный отсчёт перед началом уровня
elif level <= self.max_unlocked_level:
self.current_level = level
self.is_replay = False
self.countdown() # Запуск обратного отсчёта перед началом игры
else:
messagebox.showinfo("Недоступно", "Пройдите предыдущие уровни, чтобы разблокировать этот.")
def update_level_buttons(self):
"""Обновление цветов и состояния кнопок уровней."""
if not hasattr(self, 'level_frame') or not self.level_frame.winfo_exists():
return
for widget in self.level_frame.winfo_children():
if isinstance(widget, tk.Button):
level = int(widget['text'].split()[-1]) # Получаем номер уровня из текста кнопки
# Определяем цвет и состояние кнопки
if level in self.completed_levels:
color = "#4CAF50" # Зелёный - завершённый уровень
state = tk.NORMAL
elif level == self.max_unlocked_level:
color = "#FFEB3B" # Жёлтый - текущий открытый уровень
state = tk.NORMAL
else:
color = "#A9A9A9" # Серый - заблокированный уровень
state = tk.DISABLED
widget.config(bg=color, state=state)
def start_level(self, level):
"""Запуск уровня."""
if level in self.completed_levels:
if messagebox.askyesno("Повторить уровень", f"Вы уже прошли уровень {level}. Хотите пройти его заново?"):
self.current_level = level
self.total_bones = 0
self.steps_taken = 0
self.start_game() # Запускаем уровень заново
return
elif level <= self.max_unlocked_level:
self.current_level = level
self.countdown() # Запуск обратного отсчёта перед началом игры
else:
messagebox.showinfo("Недоступно", "Этот уровень заблокирован.")
def countdown(self):
"""Обратный отсчёт перед началом уровня с анимацией."""
clear_frame(self.root) # Очищаем экран
countdown_label = tk.Label(
self.root, text="Готовьтесь!", font=("Comic Sans MS", 40), bg="#E5E5E5"
)
countdown_label.pack(expand=True)
def update_countdown(counter):
if counter > 0:
countdown_label.config(text=f"{counter}", fg=random.choice(["red", "green", "blue"]))
self.root.update()
self.root.after(1000, update_countdown, counter - 1)
else:
countdown_label.config(text="Вперёд!", fg="orange")
self.root.update()
self.root.after(1000, lambda: self.start_game(is_replay=self.is_replay))
update_countdown(3) # Старт обратного отсчёта с 3 секунд
def start_game(self, is_replay=False):
"""Запуск игрового процесса."""
self.is_replay = is_replay
logging.info(f"Игра начата на уровне {self.current_level}, повторное прохождение: {self.is_replay}")
clear_frame(self.root)
self.map_canvas = tk.Canvas(self.root, width=1920, height=1080, bg="#E5E5E5")
self.map_canvas.pack()
self.draw_grid()
# Сбрасываем состояние уровня
self.total_bones = 0
self.steps_taken = 0
self.dog_position = [1, 1]
# Генерация косточек, идентично первому запуску
self.bones_positions = self.generate_bones()
# Обновление интерфейса
self.rect_x1, self.rect_y1 = 1600, 0
self.rect_x2, self.rect_y2 = self.rect_x1 + 180, 100
self.map_canvas.create_rectangle(
self.rect_x1, self.rect_y1, self.rect_x2, self.rect_y2, fill="#CCCCCC", outline="#CCCCCC", tags="rect"
)
self.map_canvas.create_image(1650, 50, image=self.bones_photo, tags="rect")
self.bones_label = tk.Label(self.root, text=f"{self.total_bones}", font=("Comic Sans MS", 16), bg="#CCCCCC")
self.bones_label.place(x=1700, y=30)
self.update_map()
def draw_grid(self):
"""Рисует сетку для движения."""
for x in range(0, 1920, self.grid_size):
self.map_canvas.create_line(x, 0, x, 1080, fill="lightgray")
for y in range(0, 1080, self.grid_size):
self.map_canvas.create_line(0, y, 1920, y, fill="lightgray")
def generate_bones(self):
"""Генерация косточек на карте."""
bones_count = min(self.max_bones_per_level,
10 * (2 ** (self.current_level - 1))) # Ограничиваем количество косточек
bones = set() # Используем set для предотвращения дублирования косточек
while len(bones) < bones_count:
x = random.randint(0, self.cols - 1)
y = random.randint(0, self.rows - 1)
if (x, y) != tuple(self.dog_position): # Исключаем начальную позицию собаки
bones.add((x, y)) # Добавляем уникальную координату
logging.info(f"Сгенерировано косточек: {bones}")
return list(bones) # Преобразуем в список для дальнейшей обработки
def collect_bones(self):
"""Проверка и сбор косточек."""
for bone in self.bones_positions[:]:
if self.dog_position == [bone[0], bone[1]]:
self.bones_positions.remove(bone)
self.total_bones += 1
# Сохраняем прогресс только при первом прохождении
if not self.is_replay:
save_game_session(
user_id=self.user_id,
level=self.current_level,
score=self.total_bones,
duration=self.steps_taken,
steps=self.steps_taken,
health=100,
hunger=0,
sleepiness=0
)
self.bones_label.config(text=f"{self.total_bones}")
# Проверка на завершение уровня
target_bones = 10 * (2 ** (self.current_level - 1)) # Целевое количество косточек
if self.total_bones >= target_bones and not self.is_victory_screen_open:
if not self.is_replay:
self.show_victory_screen()
else:
self.start_game(is_replay=True)
# Генерация новых косточек каждые 10 шагов
if self.steps_taken % 10 == 0 and len(self.bones_positions) < self.max_bones_per_level:
new_bones = self.generate_bones()
for bone in new_bones:
if bone not in self.bones_positions:
self.bones_positions.append(bone) # Добавляем только уникальные косточки
logging.info(f"Добавлены косточки: {new_bones}")
def move_up(self, event):
"""Движение вверх."""
self.root.focus_force()
if self.dog_position[1] > 0:
self.dog_position[1] -= 1
self.steps_taken += 1
self.update_map()
def move_down(self, event):
"""Движение вниз."""
self.root.focus_force()
if self.dog_position[1] < self.rows - 1:
self.dog_position[1] += 1
self.steps_taken += 1
self.update_map()
def move_left(self, event):
"""Движение влево."""
self.root.focus_force()
if self.dog_position[0] > 0:
self.dog_position[0] -= 1
self.steps_taken += 1
self.update_map()
def move_right(self, event):
"""Движение вправо."""
self.root.focus_force()
if self.dog_position[0] < self.cols - 1:
self.dog_position[0] += 1
self.steps_taken += 1
self.update_map()
def on_escape(self, event):
"""Обработчик для клавиши ESC."""
if self.map_canvas: # Проверяем, что игрок находится на карте
if self.is_pause_menu_open:
self.resume_game() # Закрываем окно паузы и продолжаем игру
else:
self.show_pause_menu() # Открываем окно паузы
def show_pause_menu(self):
"""Создание окна паузы."""
if self.is_pause_menu_open:
return # Если окно паузы уже открыто, ничего не делаем
self.is_pause_menu_open = True # Устанавливаем флаг
self.pause_window = tk.Toplevel(self.root)
self.pause_window.title("Пауза")
self.pause_window.geometry("400x200")
self.pause_window.configure(bg="#E5E5E5")
self.pause_window.grab_set() # Блокируем взаимодействие с основным окном
# Кнопка "Сохранить и выйти"
save_exit_button = tk.Button(
self.pause_window,
text="Сохранить и выйти",
font=("Comic Sans MS", 16),
bg="#FF6347",
command=self.save_and_exit
)
save_exit_button.pack(pady=20)
# Кнопка "Продолжить"
continue_button = tk.Button(
self.pause_window,
text="Продолжить",
font=("Comic Sans MS", 16),
bg="#4CAF50",
command=self.resume_game
)
continue_button.pack(pady=20)
def resume_game(self):
"""Закрытие окна паузы и продолжение игры."""
if self.is_pause_menu_open:
self.pause_window.destroy() # Закрываем окно паузы
self.is_pause_menu_open = False # Сбрасываем флаг
self.is_game_active = True # Возвращаем игру в активное состояние
def save_and_exit(self):
"""Сохранение данных и выход в главное меню."""
logging.info("Сохранение прогресса: уровень %d, собрано косточек %d.", self.current_level, self.total_bones)
# Дополнительно можно добавить сохранение прогресса в базу данных.
# Пример:
# save_progress_to_database(user_id=self.user_id, level=self.current_level, bones=self.total_bones)
self.return_to_main_menu_callback() # Возврат в главное меню
def update_map(self):
"""Обновление карты."""
if self.is_victory_screen_open: # Отключаем обновления, если окно победы открыто
return
self.map_canvas.delete("all") # Удаляем старые объекты карты
self.draw_grid() # Перерисовываем сетку
# Отображение косточек
for x, y in self.bones_positions:
self.map_canvas.create_image(
x * self.grid_size + self.grid_size // 2,
y * self.grid_size + self.grid_size // 2,
image=self.bones_photo
)
# Отображение собаки
if self.selected_dog:
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize(
(self.grid_size, self.grid_size),
Image.Resampling.LANCZOS
)
self.dog_photo = ImageTk.PhotoImage(dog_image)
self.map_canvas.create_image(
self.dog_position[0] * self.grid_size + self.grid_size // 2,
self.dog_position[1] * self.grid_size + self.grid_size // 2,
image=self.dog_photo
)
# Проверка сбора косточек
self.collect_bones()
# Условие перехода на следующий уровень
target_bones = 10 * (2 ** (self.current_level - 1)) # Геометрическая прогрессия
if self.total_bones >= target_bones and not self.is_victory_screen_open:
self.show_victory_screen()
def show_victory_screen(self):
"""Экран победы."""
if self.is_victory_screen_open:
return
self.is_victory_screen_open = True
self.is_game_active = False
if not self.is_replay:
# Сохранение прогресса при первом прохождении
save_game_session(
user_id=self.user_id,
level=self.current_level,
score=self.total_bones,
duration=self.steps_taken,
steps=self.steps_taken,
health=100,
hunger=0,
sleepiness=0
)
self.completed_levels.add(self.current_level)
self.max_unlocked_level = max(self.max_unlocked_level, self.current_level + 1)
self.update_level_buttons()
# Открываем окно победы
victory_window = tk.Toplevel(self.root)
victory_window.title("Уровень завершён!")
victory_window.geometry("800x400")
victory_window.configure(bg="#E5E5E5")
victory_window.grab_set()
# Текст победы
victory_label = tk.Label(victory_window, text=f"Поздравляем! Уровень {self.current_level} завершён!",
font=("Comic Sans MS", 24), bg="#E5E5E5")
victory_label.place(x=200, y=20) # Устанавливаем верхнюю позицию текста победы
# Изображение собаки
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize((200, 200), Image.Resampling.LANCZOS)
dog_photo = ImageTk.PhotoImage(dog_image)
dog_label = tk.Label(victory_window, image=dog_photo, bg="#E5E5E5")
dog_label.image = dog_photo
dog_label.place(x=50, y=120) # Сдвигаем изображение собаки вниз
# Характеристики собаки
dog_info = f"Порода: {self.selected_dog}"
info_label = tk.Label(victory_window, text=dog_info, font=("Comic Sans MS", 16), bg="#E5E5E5")
info_label.place(x=300, y=120) # Размещаем характеристики собаки ниже текста победы и изображения собаки
# Собрано косточек
target_bones = 10 * (2 ** (self.current_level - 1)) # Геометрическая прогрессия
collected_info = f"Собрано: {self.total_bones} из {target_bones}"
score_label = tk.Label(victory_window, text=collected_info, font=("Comic Sans MS", 16), bg="#E5E5E5")
score_label.place(x=300, y=170) # Размещаем информацию о собранных косточках ниже характеристик собаки
# Никнейм игрока
user_info = get_user_by_id(self.user_id)
username_label = tk.Label(victory_window, text=f"Никнейм: {user_info.username}", font=("Comic Sans MS", 16),
bg="#E5E5E5")
username_label.place(x=300, y=220) # Размещаем никнейм игрока ниже собранных косточек
# Кнопки управления
button_frame = tk.Frame(victory_window, bg="#E5E5E5")
button_frame.pack(side=tk.BOTTOM, pady=20)
next_level_button = tk.Button(
button_frame,
text="Следующий уровень",
font=("Comic Sans MS", 14),
bg="#4CAF50",
command=lambda: [victory_window.destroy(), self.start_next_level()]
)
next_level_button.pack(side=tk.LEFT, padx=10)
"""
replay_button = tk.Button(
button_frame,
text="Пройти уровень снова",
font=("Comic Sans MS", 14),
bg="#FFEB3B",
command=lambda: [victory_window.destroy(), self.start_game(is_replay=True)] # Перезапуск уровня
)
replay_button.pack(side=tk.LEFT, padx=10)
"""
exit_button = tk.Button(
button_frame,
text="Выйти в главное меню",
font=("Comic Sans MS", 14),
bg="#FF6347",
command=lambda: [victory_window.destroy(), self.return_to_main_menu()]
)
exit_button.pack(side=tk.LEFT, padx=10)
def close_victory_window(self):
"""Закрытие окна победы и сброс флага."""
self.is_victory_screen_open = False
self.is_game_active = True
self.return_to_main_menu() # Возвращаем в меню
def return_to_main_menu(self):
"""Возврат в главное меню."""
if self.is_pause_menu_open:
self.pause_window.destroy() # Закрываем окно паузы
self.is_pause_menu_open = False # Сбрасываем флаг
clear_frame(self.root) # Очищаем текущий экран
self.show_main_menu() # Переходим в главное меню
def start_next_level(self):
"""Запуск следующего уровня."""
self.current_level += 1 # Переход на следующий уровень
self.total_bones = 0 # Сброс собранных косточек
self.steps_taken = 0 # Сброс количества шагов
self.dog_position = [1, 1] # Возвращаем собаку в начальную позицию
self.bones_positions = [] # Очищаем косточки
self.is_victory_screen_open = False # Закрываем экран победы, если он был открыт
# Сохраняем новый прогресс в базу данных
save_game_session(
user_id=self.user_id,
level=self.current_level,
score=0,
duration=0,
steps=0,
health=100,
hunger=0,
sleepiness=0
)
logging.info(f"Запуск уровня {self.current_level}.")
self.countdown() # Запускаем обратный отсчёт перед началом уровня
def save_progress(self):
"""Сохранение игрового процесса в таблицу GameSessions."""
if not self.user_id:
logging.error("Ошибка: user_id равен None. Запись невозможна.")
return
try:
# Рассчитываем длительность уровня и текущий счет
duration = self.steps_taken
score = self.total_bones
# Логирование
logging.info(
f"Сохранение сессии: user_id={self.user_id}, level={self.current_level}, score={score}, duration={duration}")
# Сохранение данных в базу
save_game_session(
user_id=self.user_id,
level=self.current_level,
score=self.total_bones,
steps=self.steps_taken, # Используйте количество шагов или время
duration=self.steps_taken, # Если 'steps' отражают время, используйте их
health=100, # Примерное значение
hunger=0, # Примерное значение
sleepiness=0 # Примерное значение
)
logging.info("Прогресс успешно сохранен.")
except Exception as e:
logging.error(f"Ошибка при сохранении прогресса: {e}")
raise
def create_main_menu_button(self):
"""Создаём кнопку для возврата в главное меню."""
main_menu_button = tk.Button(
self.root,
text="Главное меню",
font=("Comic Sans MS", 16),
bg="lightgreen",
command=self.show_main_menu, # Вызов нового метода
)
main_menu_button.pack()
def show_main_menu(self):
"""Переход в главное меню."""
self.is_game_active = False # Останавливаем игру, если мы возвращаемся в меню
clear_frame(self.root) # Очищаем текущий экран
self.return_to_main_menu_callback() # Вызов колбэка для возврата в главное меню

View file

@ -0,0 +1,107 @@
import os
import tkinter as tk
from PIL import Image, ImageTk
from config import DOG_CHARACTERS, BASE_DIR
from src.utils import clear_frame
from database.info.Dogs_table import get_all_dogs
def knowledge_ui(root, user_app):
"""Интерфейс базы знаний о породах собак."""
clear_frame(root)
# Загружаем данные о породах собак из базы данных
dog_data = get_all_dogs()
if not dog_data:
tk.Label(root, text="Не удалось загрузить данные о породах.", font=("Arial", 20)).pack()
return
index = {"current": 0} # Индекс текущей породы
def update_content():
"""Обновляет содержимое для текущей породы."""
current_dog = dog_data[index["current"]]
breed = current_dog.breed
# Загружаем информацию из DOG_CHARACTERS
dog_info = DOG_CHARACTERS.get(breed)
if not dog_info:
title_label.config(text="Нет данных о породе.")
image_label.config(image=None)
image_label.image = None
characteristics_label.config(text="")
behavior_label.config(text="")
care_label.config(text="")
admin_comments_label.config(text="")
return
# Загружаем изображение
image_path = dog_info["image"]
if os.path.exists(image_path):
image = Image.open(image_path)
image = image.resize((200, 200), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(image)
image_label.config(image=photo)
image_label.image = photo
else:
image_label.config(image=None)
image_label.image = None
# Обновляем текст
title_label.config(text=breed)
characteristics_label.config(text=f"Характеристики: {current_dog.characteristics}")
behavior_label.config(text=f"Поведение: {current_dog.behavior}")
care_label.config(text=f"Уход: {current_dog.care_info}")
admin_comments_label.config(text=f"Комментарии: {current_dog.admin_comments}")
def next_breed():
"""Переход к следующей породе."""
index["current"] = (index["current"] + 1) % len(dog_data)
update_content()
def previous_breed():
"""Переход к предыдущей породе."""
index["current"] = (index["current"] - 1) % len(dog_data)
update_content()
# Основной интерфейс
frame = tk.Frame(root, bg="#f0f0f0")
frame.pack(fill=tk.BOTH, expand=True)
title_label = tk.Label(frame, text="", font=("Arial", 20), bg="#f0f0f0")
title_label.pack(pady=10)
image_label = tk.Label(frame, bg="#f0f0f0")
image_label.pack(pady=10)
characteristics_label = tk.Label(frame, text="", font=("Arial", 14), bg="#f0f0f0", wraplength=600)
characteristics_label.pack(pady=5)
behavior_label = tk.Label(frame, text="", font=("Arial", 14), bg="#f0f0f0", wraplength=600)
behavior_label.pack(pady=5)
care_label = tk.Label(frame, text="", font=("Arial", 14), bg="#f0f0f0", wraplength=600)
care_label.pack(pady=5)
admin_comments_label = tk.Label(frame, text="", font=("Arial", 14), bg="#f0f0f0", wraplength=600)
admin_comments_label.pack(pady=5)
# Кнопки навигации
btn_frame = tk.Frame(frame, bg="#f0f0f0")
btn_frame.pack(pady=20)
back_button = tk.Button(
btn_frame,
text="Назад",
font=("Arial", 14),
command=lambda: [clear_frame(root), user_app.show_user_dashboard()]
)
back_button.pack(side=tk.LEFT, padx=5)
prev_button = tk.Button(btn_frame, text="Предыдущая", font=("Arial", 14), command=previous_breed)
prev_button.pack(side=tk.LEFT, padx=5)
next_button = tk.Button(btn_frame, text="Следующая", font=("Arial", 14), command=next_breed)
next_button.pack(side=tk.LEFT, padx=5)
update_content() # Инициализация первого отображения

182
src/ui/user_ui/main_menu.py Normal file
View file

@ -0,0 +1,182 @@
import logging
import tkinter as tk
from functools import partial
from tkinter import messagebox, Canvas
from PIL import Image, ImageTk
import math
from config import BUTTON_COLOR_EXIT, CHIHUAHUA, CORGI, RETRIEVER, HUSKY, POMERANIAN, PUG, YORKSHIRE
from src.ui.user_ui.game_ui import GameUI
from src.ui.user_ui.knowledge_ui import knowledge_ui
from src.ui.user_ui.profile_ui import profile_ui
# Пути к изображениям собак
DOG_IMAGES = [
CHIHUAHUA,
CORGI,
RETRIEVER,
HUSKY,
POMERANIAN,
PUG,
YORKSHIRE
]
# Настройки
BACKGROUND_COLOR = "#E5E5E5" # Цвет фона
BUTTON_COLOR_PLAY = "#4CAF50" # Цвет кнопки играть
BUTTON_TEXT_COLOR = "white" # Цвет текста на кнопке
FONT = ("Arial", 12)
BIG_FONT = ("Arial", 24)
PLAY_BUTTON_RADIUS = 100 # Радиус кнопки "Играть"
class UserApp:
def __init__(self, root, user_id):
"""Инициализация пользовательского интерфейса."""
self.root = root
self.user_id = user_id
self.root.configure(bg="#E5E5E5")
self.root.geometry("1920x1080")
self.root.title("Собачья академия")
self.show_user_dashboard()
def show_user_dashboard(self):
"""Показать интерфейс пользователя."""
center_x, center_y = 960, 540 # Центр экрана
radius = 300 # Радиус круга для размещения собак
num_dogs = len(DOG_IMAGES)
# Верхняя панель
top_panel = tk.Frame(self.root, bg="#333333", height=100)
top_panel.pack(fill=tk.X, side=tk.TOP)
# Кнопки на верхней панели
profile_button = tk.Button(
top_panel,
text="Профиль",
bg="#555555",
fg="white",
font=FONT,
relief=tk.FLAT,
padx=20,
pady=10,
command=self.show_profile
)
profile_button.pack(side=tk.LEFT, padx=20)
shop_button = tk.Button(
top_panel,
text="Магазин",
bg="#555555",
fg="white",
font=FONT,
relief=tk.FLAT,
padx=20,
pady=10,
state=tk.DISABLED # Делаем кнопку некликабельной
)
shop_button.pack(side=tk.LEFT, padx=20)
knowledge_button = tk.Button(
top_panel,
text="База знаний",
bg="#555555",
fg="white",
font=FONT,
relief=tk.FLAT,
padx=20,
pady=10,
state=tk.NORMAL, # Делаем кнопку активной
command=lambda: knowledge_ui(self.root, self) # Подключаем knowledge_ui
)
knowledge_button.pack(side=tk.LEFT, padx=20)
# Размещение собак по кругу
self.place_dog_images(center_x, center_y, radius, num_dogs)
# Кнопка "Играть" (увеличенная)
play_button_canvas = tk.Canvas(
self.root,
width=PLAY_BUTTON_RADIUS * 2,
height=PLAY_BUTTON_RADIUS * 2,
bg=BACKGROUND_COLOR,
highlightthickness=0,
)
play_button_canvas.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
play_button_canvas.create_oval(
0, 0, PLAY_BUTTON_RADIUS * 2, PLAY_BUTTON_RADIUS * 2,
fill=BUTTON_COLOR_PLAY,
outline=BUTTON_COLOR_PLAY,
)
play_button_canvas.create_text(
PLAY_BUTTON_RADIUS,
PLAY_BUTTON_RADIUS,
text="Играть",
fill=BUTTON_TEXT_COLOR,
font=BIG_FONT,
)
play_button_canvas.tag_bind("all", "<Button-1>", lambda e: self.play_game())
# Кнопка выхода
exit_button = tk.Button(
self.root,
text="Выйти",
bg=BUTTON_COLOR_EXIT,
fg="white",
font=FONT,
command=self.exit_app
)
exit_button.place(relx=0.9, rely=0.95, anchor=tk.CENTER)
def place_dog_images(self, center_x, center_y, radius, num_dogs):
"""Размещает изображения собак по кругу."""
angle_step = 2 * math.pi / num_dogs # Шаг угла для размещения собак
for i in range(num_dogs):
angle = i * angle_step
x = center_x + radius * math.cos(angle)
y = center_y + radius * math.sin(angle)
# Загрузка изображения собаки
image_path = DOG_IMAGES[i]
try:
dog_image = Image.open(image_path)
dog_image = dog_image.resize((100, 100), Image.Resampling.LANCZOS)
dog_photo = ImageTk.PhotoImage(dog_image)
# Создание метки с изображением
dog_label = tk.Label(self.root, image=dog_photo, bg=BACKGROUND_COLOR)
dog_label.image = dog_photo # Сохраняем ссылку на изображение
dog_label.place(x=x - 50, y=y - 50) # Центрируем метку относительно позиции
except Exception as e:
print(f"Ошибка загрузки изображения {image_path}: {e}")
def show_profile(self):
"""Показать экран профиля пользователя."""
try:
self.clear_frame()
profile_ui(self.root, self.user_id, self)
except Exception as e:
logging.error(f"Ошибка при отображении профиля: {e}")
messagebox.showerror("Ошибка", "Не удалось открыть профиль.")
def clear_frame(self):
"""Очистить текущий экран."""
for widget in self.root.winfo_children():
widget.destroy()
def play_game(self):
"""Запуск игры и передача колбэка для возврата в меню."""
# Передаем метод через partial для корректной передачи self
return_to_main_menu = partial(self.return_to_main_menu)
GameUI(self.root, self.user_id, return_to_main_menu)
def return_to_main_menu(self):
"""Возврат в главное меню."""
self.clear_frame() # Очищаем экран перед переходом
self.show_user_dashboard() # Показываем главное меню
def exit_app(self):
"""Подтверждение выхода из приложения."""
if messagebox.askyesno("Выход", "Вы уверены, что хотите выйти?"):
self.root.quit()

View file

@ -0,0 +1,43 @@
import tkinter as tk
from src.utils import clear_frame
from database.db_events import get_user_progress, get_user_by_id
def profile_ui(root, user_id, user_app):
"""Интерфейс профиля пользователя."""
clear_frame(root)
frame = tk.Frame(root, bg="#f8e1e1")
frame.pack(fill=tk.BOTH, expand=True)
# Обновляем данные пользователя из базы
user = get_user_by_id(user_id)
if not user:
username = "Неизвестный пользователь"
levels_completed = 0
bones_collected = 0
else:
username = user.username
progress = get_user_progress(user_id)
levels_completed = len({session.level for session in progress if session.score > 0})
bones_collected = sum(session.score for session in progress)
tk.Label(
frame,
text=f"Профиль: {username}",
font=("Comic Sans MS", 30),
bg="#f8e1e1",
).pack(pady=20)
stats_text = f"Пройдено уровней: {levels_completed}\nСобрано косточек: {bones_collected}"
tk.Label(frame, text=stats_text, font=("Comic Sans MS", 20), bg="#f8e1e1").pack(pady=10)
# Кнопка "Назад"
back_button = tk.Button(
frame,
text="Назад",
command=lambda: [clear_frame(root), user_app.show_user_dashboard()],
font=("Comic Sans MS", 20)
)
back_button.pack(pady=20)

View file

@ -0,0 +1,18 @@
import logging
import os
def setup_logging():
"""Настройка логирования в файл."""
log_dir = "logs"
if not os.path.exists(log_dir):
os.makedirs(log_dir) # Создание директории, если она не существует
log_file = os.path.join(log_dir, "game.log")
logging.basicConfig(
filename=log_file,
level=logging.DEBUG,
format="%(asctime)s - %(levelname)s - %(message)s"
)
logging.info("Логирование игры начато.")

28
src/utils.py Normal file
View file

@ -0,0 +1,28 @@
import tkinter as tk
def clear_frame(frame):
"""Очистить все виджеты в frame"""
for widget in frame.winfo_children():
widget.destroy()
def feature_in_development_admin(frame):
"""Сообщение о том, что функционал недоступен."""
clear_frame(frame) # Очистка фрейма перед выводом сообщения
tk.Label(
frame,
text="Этот функционал пока что недоступен, в разработке.",
bg="#403d49", # Фон сообщения
fg="#b2acc0", # Цвет текста
font=("Comic Sans MS", 16)
).pack(expand=True)
def show_message(message):
"""Показать сообщение пользователю"""
message_window = tk.Toplevel()
message_label = tk.Label(message_window, text=message, font=("Comic Sans MS", 16))
message_label.pack(pady=20)
ok_button = tk.Button(message_window, text="OK", command=message_window.destroy)
ok_button.pack(pady=10)