Разработка программного модуля информационной системы «Игра «Собачья академия» #3

Merged
Anymorexxx merged 16 commits from huinya-obnovi into master 2024-12-07 02:52:11 +03:00
46 changed files with 804 additions and 111 deletions
Showing only changes of commit c08cf51998 - Show all commits

Binary file not shown.

BIN
assets/background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 KiB

BIN
assets/bone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
assets/dogs/Chihuahua.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

BIN
assets/dogs/Corgi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

BIN
assets/dogs/Husky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

BIN
assets/dogs/Pomeranian.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

BIN
assets/dogs/Pug.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

103
config.py
View file

@ -6,7 +6,7 @@ ADMIN_BUTTON_TEXT_COLOR = "#ffffff"
ADMIN_FONT = ("Comic Sans MS", 25) ADMIN_FONT = ("Comic Sans MS", 25)
ADMIN_BIG_FONT = ("Comic Sans MS", 40) ADMIN_BIG_FONT = ("Comic Sans MS", 40)
# Интерфейс пользователя # Интерфейс пользователя (АВТОРИЗАЦИЯ)
BACKGROUND_COLOR = "#f8e1e1" BACKGROUND_COLOR = "#f8e1e1"
PRIMARY_COLOR = "#ff6347" PRIMARY_COLOR = "#ff6347"
BUTTON_COLOR = "#87ceeb" BUTTON_COLOR = "#87ceeb"
@ -14,6 +14,26 @@ BUTTON_TEXT_COLOR = "white"
FONT = ("Comic Sans MS", 25) FONT = ("Comic Sans MS", 25)
BIG_FONT = ("Comic Sans MS", 40) 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_LOGIN = "admin"
ADMIN_PASSWORD = "admin123" ADMIN_PASSWORD = "admin123"
@ -23,23 +43,78 @@ DATABASE_URL = "sqlite:///database/DogAcademy.db" # Обновлено на п
# Иконки # Иконки
SETTINGS_IMG = "assets/settings.png" SETTINGS_IMG = "assets/settings.png"
LOGO = "F:/Projects/Dog_Academy/assets/logo.png"
BACKGROUND_GAME = "F:/Projects/Dog_Academy/assets/background.png"
BONE = "F:/Projects/Dog_Academy/assets/bone.png"
# Собаки
CHIHUAHUA = "F:/Projects/Dog_Academy/assets/dogs/Chihuahua.png"
CORGI = "F:/Projects/Dog_Academy/assets/dogs/Corgi.png"
RETRIEVER = "F:/Projects/Dog_Academy/assets/dogs/Golden_Retriever.png"
HUSKY = "F:/Projects/Dog_Academy/assets/dogs/Husky.png"
POMERANIAN = "F:/Projects/Dog_Academy/assets/dogs/Pomeranian.png"
PUG = "F:/Projects/Dog_Academy/assets/dogs/Pug.png"
YORKSHIRE = "F:/Projects/Dog_Academy/assets/dogs/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" NOTIFICATION_LEVEL = "info" # Возможные значения: "info", "warning", "error"
USE_DATABASE_LOGS = True USE_DATABASE_LOGS = True
# ГЛАВНОЕ МЕНЮ # Игровые параметры
BACKGROUND_COLOR_USER = "#bcabe5" # Основной фон INITIAL_SCORE = 5 # Начальные очки игрока
TOP_PANEL_COLOR_USER = "#aa9bcd" # Цвет верхней панели POINTS_CORRECT_ANSWER = 2 # Очки за правильный ответ
BUTTON_COLOR_PROFILE_USER = "#a2c792" # Цвет кнопок "Профиль", "Магазин", "База знаний" POINTS_WRONG_ANSWER = -1 # Штраф за неправильный ответ
BUTTON_COLOR_PLAY_USER = "#b4e1a1" # Цвет кнопки "Играть" MAX_LEVELS = 100 # Максимальное количество уровней
BUTTON_COLOR_EXIT_USER = "#a2c792" # Цвет кнопки "Выход" INITIAL_DOG_STATUS = {"health": 100, "hunger": 0, "sleepiness": 0} # Стартовые характеристики собаки
# Текст и шрифты # Параметры карты
BUTTON_TEXT_COLOR_USER = "white" # Цвет текста на кнопках MIN_OBSTACLES = 3 # Минимум препятствий на уровне
FONT_USER = ("Comic Sans MS", 20) # Шрифт для текста кнопок MAX_OBSTACLES = 6 # Максимум препятствий на уровне
BIG_FONT_USER = ("Comic Sans MS", 30) # Большой шрифт (например, для заголовков)
# Размеры кнопок # Графика и анимация
BUTTON_RADIUS_USER = 50 # Радиус круглой кнопки COUNTDOWN_DURATION = 3 # Продолжительность обратного отсчёта в секундах
EXIT_BUTTON_SIZE_USER = (80, 40) # Размер кнопки "Выход"

View file

@ -1,12 +1,18 @@
from sqlalchemy import func
from sqlalchemy.orm import joinedload
from database.db_session import get_session from database.db_session import get_session
from database.models import Auth, Notifications, Users from database.models import Auth, Notifications, Users, GameSession, Dogs, Questions
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
def create_user(login, password): def create_user(login, password, username):
"""Создание нового пользователя в базе данных.""" """Создание нового пользователя в базе данных."""
session = get_session() session = get_session()
try: try:
new_user = Auth(login=login, password=password) new_user_auth = Auth(login=login, password=password)
session.add(new_user_auth)
session.commit()
new_user = Users(username=username, auth=new_user_auth)
session.add(new_user) session.add(new_user)
session.commit() session.commit()
except SQLAlchemyError as e: except SQLAlchemyError as e:
@ -20,9 +26,111 @@ def check_user(login, password):
session = get_session() session = get_session()
try: try:
user = session.query(Auth).filter_by(login=login, password=password).first() user = session.query(Auth).filter_by(login=login, password=password).first()
return user is not None if user:
return user.user_id
return None
except SQLAlchemyError as e: except SQLAlchemyError as e:
print(f"Ошибка при проверке пользователя: {e}") print(f"Ошибка при проверке пользователя: {e}")
return False return None
finally:
session.close()
def save_progress(user_id, level, score, duration, health, hunger, sleepiness):
"""Сохраняет прогресс пользователя в базу данных."""
session = get_session()
try:
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}")
session.rollback()
finally:
session.close()
def get_user_progress(user_id):
"""Получение прогресса пользователя по его ID."""
session = get_session()
try:
progress = session.query(GameSession).filter_by(user_id=user_id).all()
return progress
except SQLAlchemyError as e:
print(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 get_notifications(user_id):
"""Получение уведомлений для пользователя."""
session = get_session()
try:
notifications = session.query(Notifications).filter_by(user_id=user_id).all()
return notifications
except SQLAlchemyError as e:
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: finally:
session.close() session.close()

View file

@ -13,7 +13,6 @@ Session = sessionmaker(bind=engine)
# Переменная для хранения текущей сессии # Переменная для хранения текущей сессии
current_session = None current_session = None
def init_db(refresh=False): def init_db(refresh=False):
""" """
Инициализация базы данных: создание файла и таблиц. Инициализация базы данных: создание файла и таблиц.
@ -33,18 +32,14 @@ def init_db(refresh=False):
# Инициализация сессии при запуске # Инициализация сессии при запуске
current_session = get_session() current_session = get_session()
def get_session(): def get_session():
"""Возвращает сессию для работы с базой данных.""" """Возвращает сессию для работы с базой данных."""
return Session() return Session()
def close_sessions(): def close_sessions():
"""Закрытие всех сессий перед выходом из программы.""" """Закрытие всех сессий перед выходом из программы."""
global current_session if current_session:
if current_session is not None:
print("Закрытие сессии...") print("Закрытие сессии...")
current_session.close() # Закрываем текущую сессию базы данных current_session.close()
current_session = None
else: else:
print("Нет активной сессии для закрытия.") print("Нет активной сессии для закрытия.")

View file

@ -1,11 +1,10 @@
from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime from sqlalchemy import Column, Integer, String, ForeignKey, Text, DateTime, UniqueConstraint, Boolean
from sqlalchemy.orm import relationship from sqlalchemy.orm import relationship
from sqlalchemy.sql import func from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base() Base = declarative_base()
class Auth(Base): class Auth(Base):
__tablename__ = 'auth' __tablename__ = 'auth'
user_id = Column(Integer, primary_key=True) user_id = Column(Integer, primary_key=True)
@ -50,7 +49,7 @@ class Questions(Base):
__tablename__ = 'questions' __tablename__ = 'questions'
question_id = Column(Integer, primary_key=True) question_id = Column(Integer, primary_key=True)
dog_id = Column(Integer, ForeignKey('dogs.dog_id')) dog_id = Column(Integer, ForeignKey('dogs.dog_id'))
question_text = Column(Text, nullable=False) # Исправлено поле question_text = Column(Text, nullable=False)
image_url = Column(String) image_url = Column(String)
helpful_info = Column(Text) helpful_info = Column(Text)
incorrect_attempts = Column(Integer, default=0) incorrect_attempts = Column(Integer, default=0)
@ -61,24 +60,31 @@ class Questions(Base):
class GameSession(Base): class GameSession(Base):
__tablename__ = 'game_sessions' __tablename__ = 'game_sessions'
__table_args__ = (
UniqueConstraint('user_id', 'level', name='uix_user_level'),
)
session_id = Column(Integer, primary_key=True) session_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.user_id')) user_id = Column(Integer, ForeignKey('users.user_id'))
level = Column(Integer, nullable=False) level = Column(Integer, nullable=False)
score = Column(Integer, default=0) score = Column(Integer, default=0)
duration = Column(Integer) # Время игры в секундах duration = Column(Integer) # Время игры в секундах
start_time = Column(DateTime, default=func.now()) # Исправлено start_time = Column(DateTime, default=func.now())
end_time = Column(DateTime, nullable=True) end_time = Column(DateTime, nullable=True)
health = Column(Integer, default=100) # Здоровье
hunger = Column(Integer, default=0) # Голод
sleepiness = Column(Integer, default=0) # Сонливость
# Связь с таблицей Users # Связь с таблицей Users
user = relationship("Users", back_populates="game_sessions") user = relationship("Users", back_populates="game_sessions")
class Notifications(Base): class Notifications(Base):
__tablename__ = 'notifications' __tablename__ = 'notifications'
notification_id = Column(Integer, primary_key=True) notification_id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.user_id')) user_id = Column(Integer, ForeignKey('users.user_id'))
message = Column(Text, nullable=False) message = Column(Text, nullable=False)
timestamp = Column(DateTime, default=func.now()) timestamp = Column(DateTime, default=func.now())
is_read = Column(Integer, default=0) # 0 - не прочитано, 1 - прочитано is_read = Column(Boolean, default=False) # Булевый тип для read
# Связь с таблицей Users # Связь с таблицей Users
user = relationship("Users", back_populates="notifications") user = relationship("Users", back_populates="notifications")

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.

View file

@ -1343,3 +1343,128 @@ WHERE auth.login = ? AND auth.password = ?
LIMIT ? OFFSET ? LIMIT ? OFFSET ?
2024-11-25 22:36:09 - [generated in 0.00045s] ('lubluNikitu', 'meow123', 1, 0) 2024-11-25 22:36:09 - [generated in 0.00045s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-25 22:36:09 - ROLLBACK 2024-11-25 22:36:09 - ROLLBACK
2024-11-26 12:26:39 - BEGIN (implicit)
2024-11-26 12:26:39 - 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-26 12:26:39 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 12:26:39 - ROLLBACK
2024-11-26 12:33:48 - BEGIN (implicit)
2024-11-26 12:33:48 - 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-26 12:33:48 - [generated in 0.00022s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 12:33:48 - ROLLBACK
2024-11-26 12:38:38 - BEGIN (implicit)
2024-11-26 12:38:38 - 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-26 12:38:38 - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 12:38:38 - ROLLBACK
2024-11-26 17:00:02 - BEGIN (implicit)
2024-11-26 17:00:02 - 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-26 17:00:02 - [generated in 0.00024s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 17:00:02 - ROLLBACK
2024-11-26 17:01:01 - BEGIN (implicit)
2024-11-26 17:01:01 - 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-26 17:01:01 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 17:01:01 - ROLLBACK
2024-11-26 17:07:02 - BEGIN (implicit)
2024-11-26 17:07:02 - 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-26 17:07:02 - [generated in 0.00023s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 17:07:02 - ROLLBACK
2024-11-26 17:08:03 - BEGIN (implicit)
2024-11-26 17:08:03 - 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-26 17:08:03 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 17:08:03 - ROLLBACK
2024-11-26 17:27:44 - BEGIN (implicit)
2024-11-26 17:27:44 - 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-26 17:27:44 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 17:27:44 - ROLLBACK
2024-11-26 19:46:13 - BEGIN (implicit)
2024-11-26 19:46:13 - 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-26 19:46:13 - [generated in 0.00029s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 19:46:13 - ROLLBACK
2024-11-26 21:23:20 - BEGIN (implicit)
2024-11-26 21:23:20 - 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-26 21:23:20 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 21:23:20 - ROLLBACK
2024-11-26 21:31:58 - BEGIN (implicit)
2024-11-26 21:31:58 - SELECT count(*) AS count_1
FROM (SELECT users.user_id AS users_user_id, users.dog_id AS users_dog_id, users.username AS users_username, users.level AS users_level, users.achievement AS users_achievement
FROM users) AS anon_1
2024-11-26 21:31:58 - [generated in 0.00026s] ()
2024-11-26 21:31:58 - SELECT game_sessions.level AS game_sessions_level, count(game_sessions.session_id) AS count_1
FROM game_sessions GROUP BY game_sessions.level
2024-11-26 21:31:58 - [generated in 0.00022s] ()
2024-11-26 21:31:58 - SELECT questions.question_text AS questions_question_text, questions.incorrect_attempts AS questions_incorrect_attempts
FROM questions ORDER BY questions.incorrect_attempts DESC
2024-11-26 21:31:58 - [generated in 0.00019s] ()
2024-11-26 21:31:58 - SELECT avg(game_sessions.duration) AS avg_1
FROM game_sessions
2024-11-26 21:31:58 - [generated in 0.00014s] ()
2024-11-26 21:31:58 - ROLLBACK
2024-11-26 21:31:58 - BEGIN (implicit)
2024-11-26 21:31:58 - SELECT game_sessions.start_time AS game_sessions_start_time
FROM game_sessions
2024-11-26 21:31:58 - [generated in 0.00017s] ()
2024-11-26 21:31:58 - ROLLBACK
2024-11-26 21:34:57 - BEGIN (implicit)
2024-11-26 21:34:57 - 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-26 21:34:57 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 21:34:57 - ROLLBACK
2024-11-26 21:47:02 - BEGIN (implicit)
2024-11-26 21:47:02 - 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-26 21:47:02 - [generated in 0.00021s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 21:47:02 - ROLLBACK
2024-11-26 21:49:25 - BEGIN (implicit)
2024-11-26 21:49:25 - 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-26 21:49:25 - [generated in 0.00023s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 21:49:25 - ROLLBACK
2024-11-26 21:54:33 - BEGIN (implicit)
2024-11-26 21:54:33 - 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-26 21:54:33 - [generated in 0.00025s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 21:54:33 - ROLLBACK
2024-11-26 22:41:31 - BEGIN (implicit)
2024-11-26 22:41:31 - 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-26 22:41:31 - [generated in 0.00027s] ('lubluNikitu', 'meow123', 1, 0)
2024-11-26 22:41:31 - ROLLBACK

View file

@ -1,3 +1,7 @@
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
from tkinter import Tk, messagebox from tkinter import Tk, messagebox
from src.ui.auth_ui import DogAcademyApp # Путь к приложению from src.ui.auth_ui import DogAcademyApp # Путь к приложению
from database.db_session import init_db, close_sessions # Функция для закрытия сессий from database.db_session import init_db, close_sessions # Функция для закрытия сессий

View file

@ -219,4 +219,4 @@ class DogAcademyApp:
def show_user_dashboard(self): def show_user_dashboard(self):
self.clear_frame() self.clear_frame()
"""Перейти к главному меню пользователя после авторизации.""" """Перейти к главному меню пользователя после авторизации."""
UserApp(self.root, self) UserApp(self.root)

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,149 @@
import tkinter as tk
from PIL import Image, ImageTk
from src.utils import clear_frame
from config import DOG_CHARACTERS, BACKGROUND_GAME, LOGO, COUNTDOWN_DURATION
from src.user_functions.map_generator import generate_map
from src.user_functions.game_functions import handle_obstacle
class GameUI:
def __init__(self, root, user_id):
self.root = root
self.user_id = user_id
self.selected_dog = None
self.current_level = 1
self.score = 0
self.root.configure(bg="lightblue")
self.create_logo()
self.show_dog_selection()
def create_logo(self):
"""Создание логотипа."""
logo_image = Image.open(LOGO)
logo_photo = ImageTk.PhotoImage(logo_image.resize((200, 100), Image.Resampling.LANCZOS))
logo_label = tk.Label(self.root, image=logo_photo, bg="lightblue")
logo_label.image = logo_photo
logo_label.pack(pady=10)
def show_dog_selection(self):
"""Выбор собаки пользователем."""
clear_frame(self.root)
tk.Label(
self.root, text="Выберите собаку", font=("Comic Sans MS", 24), bg="lightblue"
).pack(pady=20)
dog_frame = tk.Frame(self.root, bg="lightblue")
dog_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # Центрируем фрейм
for breed, details in DOG_CHARACTERS.items():
dog_image = Image.open(details["image"])
dog_photo = ImageTk.PhotoImage(dog_image.resize((150, 150), Image.Resampling.LANCZOS))
# Фрейм для кнопки и подписи
dog_item = tk.Frame(dog_frame, bg="lightblue")
dog_item.pack(side=tk.LEFT, padx=15, pady=15)
# Кнопка с изображением
button = tk.Button(
dog_item,
image=dog_photo,
command=lambda b=breed: self.confirm_dog_selection(b),
bg="lightblue",
borderwidth=0,
)
button.image = dog_photo # Сохраняем ссылку на изображение
button.pack()
# Подпись с породой собаки
tk.Label(
dog_item,
text=breed,
font=("Comic Sans MS", 16),
bg="lightblue"
).pack(pady=5)
def confirm_dog_selection(self, breed):
"""Подтверждение выбора собаки."""
self.selected_dog = breed
self.show_level_selection()
def show_level_selection(self):
"""Отображение выбора уровня."""
clear_frame(self.root)
tk.Label(
self.root, text="Выберите уровень", font=("Comic Sans MS", 20), bg="lightblue"
).pack(pady=10)
level_frame = tk.Frame(self.root, bg="lightblue")
level_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # Центрируем фрейм
for level in range(1, 6): # Доступно 5 уровней
tk.Button(
level_frame,
text=f"Уровень {level}",
command=lambda l=level: self.start_level(l),
font=("Comic Sans MS", 16),
bg="lightgreen",
width=12,
).pack(pady=10)
def start_level(self, level):
"""Начало выбранного уровня."""
self.current_level = level
self.countdown()
def countdown(self):
"""Обратный отсчёт перед началом уровня."""
clear_frame(self.root)
countdown_label = tk.Label(
self.root, text="", font=("Comic Sans MS", 30), bg="lightblue"
)
countdown_label.pack(expand=True)
for i in range(COUNTDOWN_DURATION, 0, -1):
countdown_label.config(text=f"{i}...")
self.root.update()
self.root.after(1000)
self.start_game()
def start_game(self):
"""Запуск игрового процесса."""
clear_frame(self.root)
# Генерация карты
map_data = generate_map(self.current_level)
for obstacle in map_data:
result = handle_obstacle(obstacle, self.score, self.root)
self.score = result["new_score"]
if self.score >= 10: # Условие победы
self.show_victory_screen()
def show_victory_screen(self):
"""Экран победы."""
clear_frame(self.root)
tk.Label(
self.root, text="Ура, победа!", font=("Comic Sans MS", 30), bg="lightblue"
).pack(pady=10)
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"])
dog_photo = ImageTk.PhotoImage(dog_image.resize((150, 150), Image.Resampling.LANCZOS))
tk.Label(self.root, image=dog_photo, bg="lightblue").pack(pady=10)
tk.Label(
self.root,
text=f"Порода: {self.selected_dog}\nСобрано косточек: {self.score}",
font=("Comic Sans MS", 20),
bg="lightblue",
).pack(pady=10)
tk.Button(
self.root,
text="Вернуться в главное меню",
command=lambda: self.__init__(self.root, self.user_id),
font=("Comic Sans MS", 16),
bg="lightgreen",
).pack(pady=10)

View file

@ -0,0 +1,34 @@
import tkinter as tk
from src.utils import clear_frame
from database.db_events import get_knowledge_base
def knowledge_ui(root):
"""Интерфейс базы знаний."""
clear_frame(root)
frame = tk.Frame(root, bg="#f8e1e1")
frame.pack(fill=tk.BOTH, expand=True)
tk.Label(frame, text="База знаний", font=("Comic Sans MS", 30), bg="#f8e1e1").pack(pady=20)
articles = get_knowledge_base()
for article in articles:
article_frame = tk.Frame(frame, bg="#f8f8f8", bd=2, relief=tk.RIDGE)
article_frame.pack(pady=5, padx=10, fill=tk.X)
tk.Label(article_frame, text=article.breed, font=("Comic Sans MS", 20), bg="#f8f8f8").pack(side=tk.LEFT,
padx=10)
tk.Button(article_frame, text="Читать", command=lambda a=article: show_article(a)).pack(side=tk.RIGHT, padx=10)
tk.Button(frame, text="Назад", command=lambda: clear_frame(root), font=("Comic Sans MS", 20)).pack(pady=20)
def show_article(article):
"""Показать содержимое статьи."""
top = tk.Toplevel()
top.title(article.breed)
text = tk.Text(top, wrap=tk.WORD)
text.pack(fill=tk.BOTH, expand=True)
text.insert(tk.END, article.content)
text.config(state=tk.DISABLED)

View file

@ -1,78 +1,167 @@
import tkinter as tk import tkinter as tk
from config import ( from tkinter import Canvas
BACKGROUND_COLOR_USER, from PIL import Image, ImageTk
TOP_PANEL_COLOR_USER, import math
BUTTON_COLOR_PROFILE_USER,
BUTTON_COLOR_PLAY_USER, from config import EXIT_BUTTON_WIDTH, EXIT_BUTTON_HEIGHT, BUTTON_COLOR_EXIT
BUTTON_COLOR_EXIT_USER, from src.ui.user_ui.game_ui import GameUI
BUTTON_TEXT_COLOR_USER, from src.ui.user_ui.profile_ui import profile_ui
FONT_USER, from src.ui.user_ui.shop_ui import shop_ui
BIG_FONT_USER, from src.ui.user_ui.knowledge_ui import knowledge_ui
BUTTON_RADIUS_USER, from src.utils import clear_frame
EXIT_BUTTON_SIZE_USER,
) # Пути к изображениям собак
DOG_IMAGES = [
"F:/Projects/Dog_Academy/assets/dogs/Chihuahua.png",
"F:/Projects/Dog_Academy/assets/dogs/Corgi.png",
"F:/Projects/Dog_Academy/assets/dogs/Golden_Retriever.png",
"F:/Projects/Dog_Academy/assets/dogs/Husky.png",
"F:/Projects/Dog_Academy/assets/dogs/Pomeranian.png",
"F:/Projects/Dog_Academy/assets/dogs/Pug.png",
"F:/Projects/Dog_Academy/assets/dogs/Yorkshire_Terrier.png"
]
# Настройки
BACKGROUND_COLOR = "#E5E5E5" # Цвет фона
BUTTON_COLOR_PLAY = "#4CAF50" # Цвет кнопки играть
BUTTON_TEXT_COLOR = "white" # Цвет текста на кнопке
FONT = ("Arial", 12)
BIG_FONT = ("Arial", 24)
PLAY_BUTTON_RADIUS = 100 # Радиус кнопки "Играть"
class UserApp: class UserApp:
def __init__(self, root, auth_ui): def __init__(self, root, user_id=None):
self.root = root self.root = root
self.auth_ui = auth_ui self.user_id = user_id
self.root.configure(bg=BACKGROUND_COLOR_USER) self.root.configure(bg=BACKGROUND_COLOR)
self.root.geometry("1920x1080") # Разрешение окна self.root.geometry("1920x1080")
self.root.title("Собачья академия") self.root.title("Собачья академия")
print("Главное меню активно") # Лог при открытии меню
self.show_user_dashboard() self.show_user_dashboard()
def show_user_dashboard(self): 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=TOP_PANEL_COLOR_USER, height=100) top_panel = tk.Frame(self.root, bg="#333333", height=100)
top_panel.pack(fill=tk.X, side=tk.TOP) top_panel.pack(fill=tk.X, side=tk.TOP)
# Кнопки на верхней панели # Кнопки на верхней панели
for text, command in [("Профиль", self.show_profile), ("Магазин", self.show_shop), ("База знаний", self.show_knowledge)]: profile_button = tk.Button(
button = tk.Button(
top_panel, top_panel,
text=text, text="Профиль",
bg=BUTTON_COLOR_PROFILE_USER, bg="#555555",
fg=BUTTON_TEXT_COLOR_USER, fg="white",
font=FONT_USER, font=FONT,
relief=tk.FLAT, relief=tk.FLAT,
padx=20, padx=20,
pady=10, pady=10,
command=command, command=self.show_profile
) )
button.pack(side=tk.LEFT, padx=20) profile_button.pack(side=tk.LEFT, padx=20)
# Кнопка "Играть" в центре shop_button = tk.Button(
play_button = tk.Button( top_panel,
self.root, text="Магазин",
text="Играть", bg="#555555",
bg=BUTTON_COLOR_PLAY_USER, fg="white",
fg=BUTTON_TEXT_COLOR_USER, font=FONT,
font=BIG_FONT_USER,
relief=tk.FLAT, relief=tk.FLAT,
height=2, padx=20,
width=10, pady=10,
command=self.play_game, command=self.show_shop
) )
play_button.place(relx=0.5, rely=0.5, anchor=tk.CENTER) shop_button.pack(side=tk.LEFT, padx=20)
# Кнопка "Выход" в правом нижнем углу knowledge_button = tk.Button(
exit_button = tk.Button( top_panel,
self.root, text="База знаний",
text="Выход", bg="#555555",
bg=BUTTON_COLOR_EXIT_USER, fg="white",
fg=BUTTON_TEXT_COLOR_USER, font=FONT,
font=FONT_USER, relief=tk.FLAT,
width=EXIT_BUTTON_SIZE_USER[0] // 10, padx=20,
height=EXIT_BUTTON_SIZE_USER[1] // 10, pady=10,
command=self.exit_app, command=self.show_knowledge
) )
exit_button.place(relx=1.0, rely=1.0, x=-20, y=-20, anchor=tk.SE) 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())
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):
"""Показать экран профиля пользователя."""
self.clear_frame()
profile_ui(self.root, self.user_id) # Передаем user_id в profile_ui
def show_shop(self):
"""Показать экран магазина."""
self.clear_frame()
shop_ui(self.root)
def show_knowledge(self):
"""Показать базу знаний."""
self.clear_frame()
knowledge_ui(self.root)
def clear_frame(self):
"""Очистить текущий экран."""
for widget in self.root.winfo_children():
widget.destroy()
def play_game(self): def play_game(self):
"""Заглушка для игры.""" """Переход к игровому интерфейсу."""
clear_frame(self.root) # Очищаем главное меню
GameUI(self.root, self.user_id) # Открываем игровой интерфейс
print("Запуск игры...") print("Запуск игры...")
def exit_app(self): def exit_app(self):
@ -80,14 +169,9 @@ class UserApp:
print("Приложение закрыто") print("Приложение закрыто")
self.root.quit() self.root.quit()
def show_profile(self): # Запуск главного окна
"""Заглушка для профиля.""" if __name__ == "__main__":
print("Переход в профиль...") root = tk.Tk()
app = UserApp(root, user_id=123) # Передаем user_id (это может быть получено после авторизации)
root.mainloop()
def show_shop(self):
"""Заглушка для магазина."""
print("Переход в магазин...")
def show_knowledge(self):
"""Заглушка для базы знаний."""
print("Переход в базу знаний...")

View file

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

View file

@ -0,0 +1,24 @@
import tkinter as tk
from src.utils import clear_frame
from database.db_events import get_dogs, update_user_dog
def shop_ui(root, user_id):
"""Интерфейс магазина."""
clear_frame(root)
frame = tk.Frame(root, bg="#e5e5e5")
frame.pack(fill=tk.BOTH, expand=True)
tk.Label(frame, text="Магазин", font=("Comic Sans MS", 30), bg="#e5e5e5").pack(pady=20)
dogs = get_dogs() # Получить список собак из базы данных
for dog in dogs:
dog_frame = tk.Frame(frame, bg="#f8f8f8", bd=2, relief=tk.RIDGE)
dog_frame.pack(pady=5, padx=10, fill=tk.X)
tk.Label(dog_frame, text=dog.breed, font=("Comic Sans MS", 20), bg="#f8f8f8").pack(side=tk.LEFT, padx=10)
tk.Button(dog_frame, text="Купить", command=lambda d=dog: update_user_dog(user_id, d.dog_id)).pack(
side=tk.RIGHT, padx=10)
tk.Button(frame, text="Назад", command=lambda: clear_frame(root), font=("Comic Sans MS", 20)).pack(pady=20)

View file

@ -0,0 +1,57 @@
import time
import tkinter as tk
from src.utils import clear_frame
from database.db_events import save_progress
def start_game(root, user_id, dog_id):
"""Игровой процесс."""
clear_frame(root)
# Обратный отсчет
for i in range(3, 0, -1):
clear_frame(root)
tk.Label(root, text=f"{i}...", font=("Comic Sans MS", 30)).pack(expand=True)
root.update()
time.sleep(1)
# Начало уровня
# Здесь подключается логика работы с картой и вопросами
pass
def handle_obstacle(obstacle, current_score, root):
"""
Обработка препятствия (вопроса) с использованием окна.
Возвращает новый счёт игрока.
"""
result = {"new_score": current_score}
def submit_answer():
user_answer = answer_var.get().strip().lower()
if user_answer == "правильно": # Условие для правильного ответа
result["new_score"] += 1
else:
result["new_score"] -= 1
question_window.destroy() # Закрываем окно вопроса
# Создаём новое окно для вопроса
question_window = tk.Toplevel(root)
question_window.title("Вопрос")
question_window.geometry("400x200")
# Отображение текста вопроса
tk.Label(question_window, text=f"Вопрос сложности {obstacle['difficulty']}:", font=("Arial", 14)).pack(pady=10)
# Поле ввода ответа
answer_var = tk.StringVar()
tk.Entry(question_window, textvariable=answer_var, font=("Arial", 12)).pack(pady=10)
# Кнопка подтверждения ответа
tk.Button(question_window, text="Ответить", command=submit_answer).pack(pady=10)
# Ожидаем закрытия окна
question_window.grab_set() # Блокируем основное окно
root.wait_window(question_window) # Ждём завершения окна вопроса
return result

View file

@ -0,0 +1,13 @@
import random
def generate_map(level):
"""Генерация карты уровня."""
num_obstacles = random.randint(3, 6)
map_data = []
for i in range(num_obstacles):
map_data.append({
"type": "question",
"difficulty": level,
"position": random.randint(1, 100)
})
return map_data

View file

@ -1,4 +1,6 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox
def clear_frame(frame): def clear_frame(frame):
"""Удаление всех виджетов из фрейма.""" """Удаление всех виджетов из фрейма."""
@ -16,16 +18,10 @@ def feature_in_development(frame):
font=("Comic Sans MS", 16) font=("Comic Sans MS", 16)
).pack(expand=True) ).pack(expand=True)
def create_tooltip(widget, text): def show_message(message):
"""Создание подсказки для виджета.""" """Показать сообщение пользователю"""
tooltip = tk.Toplevel() message_window = tk.Toplevel()
tooltip.wm_overrideredirect(True) # Отключаем рамки окна message_label = tk.Label(message_window, text=message, font=("Comic Sans MS", 16))
tooltip.wm_geometry(f"+{widget.winfo_rootx() + 20}+{widget.winfo_rooty() + 20}") message_label.pack(pady=20)
label = tk.Label(tooltip, text=text, bg="#333", fg="#fff", font=("Comic Sans MS", 10), padx=5, pady=5) ok_button = tk.Button(message_window, text="OK", command=message_window.destroy)
label.pack() ok_button.pack(pady=10)
def hide_tooltip(event):
tooltip.destroy()
widget.bind("<Enter>", lambda event: tooltip.deiconify())
widget.bind("<Leave>", hide_tooltip)