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

Merged
Anymorexxx merged 16 commits from huinya-obnovi into master 2024-12-07 02:52:11 +03:00
13 changed files with 5512 additions and 234 deletions
Showing only changes of commit 5d34162267 - Show all commits

BIN
database/DogAcademy.db Normal file

Binary file not shown.

View file

@ -1,3 +1,4 @@
import logging
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from database.db_session import get_session from database.db_session import get_session
@ -6,36 +7,50 @@ from sqlalchemy.exc import SQLAlchemyError
def get_user_by_id(user_id): def get_user_by_id(user_id):
"""Получение данных пользователя по ID.""" """Получение данных пользователя по ID с предварительной загрузкой связанных данных."""
session = get_session() session = get_session()
try: try:
user = session.query(Users).filter_by(user_id=user_id).first() user = (
session.query(Users)
.options(joinedload(Users.game_sessions)) # Предзагрузка связанных игровых сессий
.filter_by(user_id=user_id)
.first()
)
return user return user
except SQLAlchemyError as e: except SQLAlchemyError as e:
print(f"Ошибка при получении пользователя: {e}") logging.error(f"Ошибка при получении пользователя: {e}")
return None return None
finally: finally:
session.close() session.close()
def create_user(login, password, username): def create_user(login, password, username):
"""Создание нового пользователя в базе данных.""" """Регистрация нового пользователя."""
session = get_session() session = get_session()
# Проверяем, есть ли уже пользователь с таким логином # Проверка, есть ли уже пользователь с таким логином
if session.query(Auth).filter_by(login=login).first(): if session.query(Auth).filter_by(login=login).first():
return False, "Логин уже используется." return False, "Логин уже используется."
# Создаем новую запись в таблице Auth # Создаём новую запись в таблице Auth
new_auth = Auth(login=login, password=password) new_auth = Auth(login=login, password=password)
session.add(new_auth) session.add(new_auth)
try: try:
session.commit() # Сохраняем изменения в таблице Auth session.commit() # Сохраняем изменения в таблице Auth
# Создаем новую запись в таблице Users, связывая с только что добавленным Auth # Создаём новую запись в таблице Users, связываем с только что добавленным Auth
new_user = Users(user_id=new_auth.user_id, username=username) new_user = Users(user_id=new_auth.user_id, username=username)
session.add(new_user) session.add(new_user)
session.commit() # Сохраняем изменения в таблице Users 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: except SQLAlchemyError as e:
session.rollback() # Откат изменений при ошибке session.rollback() # Откат изменений при ошибке
print(f"Ошибка при создании пользователя: {e}") print(f"Ошибка при создании пользователя: {e}")
@ -43,28 +58,18 @@ def create_user(login, password, username):
finally: finally:
session.close() session.close()
return True, "Регистрация успешна."
def check_user(login, password=None): def check_user(login, password=None):
"""Проверка существования пользователя по логину и паролю (если передан)."""
session = get_session() session = get_session()
try: try:
print(f"Проверяем пользователя с логином: {login}")
# Фильтрация только по логину
query = session.query(Auth).filter_by(login=login) query = session.query(Auth).filter_by(login=login)
# Если передан пароль, фильтруем и по паролю
if password: if password:
query = query.filter_by(password=password) query = query.filter_by(password=password)
user = query.first() user = query.first()
if user: if user:
print(f"Пользователь найден: {user.user_id}") return user.user_id
return user.user_id # Возвращаем user_id пользователя
else: else:
print("Пользователь не найден.")
return None return None
except SQLAlchemyError as e: except SQLAlchemyError as e:
print(f"Ошибка при проверке пользователя: {e}") print(f"Ошибка при проверке пользователя: {e}")
@ -76,6 +81,8 @@ def save_progress(user_id, level, score, duration, health, hunger, sleepiness):
"""Сохранение игрового прогресса в базу данных.""" """Сохранение игрового прогресса в базу данных."""
session = get_session() session = get_session()
try: try:
if not user_id:
raise ValueError("user_id не указан!")
session_data = GameSession( session_data = GameSession(
user_id=user_id, user_id=user_id,
level=level, level=level,
@ -89,8 +96,10 @@ def save_progress(user_id, level, score, duration, health, hunger, sleepiness):
session.add(session_data) session.add(session_data)
session.commit() session.commit()
except SQLAlchemyError as e: except SQLAlchemyError as e:
print(f"Ошибка при сохранении прогресса: {e}") logging.error(f"Ошибка при сохранении прогресса: {e}")
session.rollback() session.rollback()
except ValueError as e:
logging.error(e)
finally: finally:
session.close() session.close()
@ -100,7 +109,7 @@ def get_user_progress(user_id):
try: try:
return session.query(GameSession).filter_by(user_id=user_id).all() return session.query(GameSession).filter_by(user_id=user_id).all()
except Exception as e: except Exception as e:
print(f"Ошибка при получении прогресса пользователя: {e}") logging.error(f"Ошибка при получении прогресса пользователя: {e}")
return [] return []
finally: finally:
session.close() session.close()

View file

@ -1,3 +1,7 @@
import logging
from sqlalchemy.exc import SQLAlchemyError
from database.db_session import get_session from database.db_session import get_session
from database.models import Dogs from database.models import Dogs
@ -47,21 +51,44 @@ DOG_CHARACTERS = {
} }
def populate_dogs(): def populate_dogs():
"""
Заполнение таблицы Dogs предустановленными данными.
"""
session = get_session() session = get_session()
try: try:
logging.info("Начинается заполнение таблицы Dogs.")
for breed, data in DOG_CHARACTERS.items(): for breed, data in DOG_CHARACTERS.items():
dog = Dogs( existing_dog = session.query(Dogs).filter_by(breed=breed).first()
breed=breed, if not existing_dog:
characteristics=data['characteristics'], dog = Dogs(
behavior=data['behavior'], breed=breed,
care_info=data['care_info'], characteristics=data['characteristics'],
admin_comments=data['admin_comments'] behavior=data['behavior'],
) care_info=data['care_info'],
session.add(dog) admin_comments=data['admin_comments']
)
session.add(dog)
session.commit() session.commit()
print("Таблица Dogs успешно заполнена.") logging.info("Таблица Dogs успешно заполнена.")
except Exception as e: except SQLAlchemyError as e:
session.rollback() session.rollback()
print(f"Ошибка при заполнении Dogs: {e}") 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: finally:
session.close() session.close()

View file

@ -1,34 +1,48 @@
import logging
from sqlalchemy import func
from database.db_events import get_user_progress from database.db_events import get_user_progress
from database.db_session import get_session from database.db_session import get_session
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from database.models import GameSession from database.models import GameSession
def save_game_session(user_id, level, score, duration, health, hunger, sleepiness): def save_game_session(user_id, level, score, steps, duration=0, health=100, hunger=0, sleepiness=0):
"""Сохранение игрового процесса в таблицу GameSessions.""" """Сохранение игрового прогресса."""
session = get_session() session = get_session()
try: try:
# Создаем новый объект GameSession session.add(GameSession(
game_session = GameSession(
user_id=user_id, user_id=user_id,
level=level, level=level,
score=score, score=score,
steps=steps,
duration=duration, duration=duration,
health=health, health=health,
hunger=hunger, hunger=hunger,
sleepiness=sleepiness, sleepiness=sleepiness
) ))
session.add(game_session) session.commit()
session.commit() # Сохраняем данные в таблице logging.info(f"Сессия сохранена: user_id={user_id}, level={level}, score={score}")
print(f"Игровой процесс для пользователя {user_id} на уровне {level} успешно сохранен.") except Exception as e:
except SQLAlchemyError as e:
session.rollback() session.rollback()
print(f"Ошибка при сохранении игрового процесса: {e}") logging.error(f"Ошибка при сохранении игровой сессии: {e}")
finally: raise
session.close()
def print_user_progress(user_id): def print_user_progress(user_id):
"""Печать прогресса пользователя из таблицы GameSessions.""" """
Печать прогресса пользователя из таблицы GameSessions.
:param user_id: ID пользователя
"""
if not user_id:
logging.error("user_id отсутствует. Невозможно получить прогресс.")
return
progress = get_user_progress(user_id) 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: for session in progress:
print(f"Уровень: {session.level}, Очки: {session.score}, Время: {session.duration} секунд") print(f"- Уровень: {session.level}, Очки: {session.score}, Время: {session.duration} сек")

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
import logging
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from database.db_session import get_session from database.db_session import get_session
from database.models import Auth, Users, GameSession from database.models import Auth, Users, GameSession
@ -6,50 +8,42 @@ from database.models import Auth, Users, GameSession
def register_user(login, password, username): def register_user(login, password, username):
"""Регистрация нового пользователя.""" """Регистрация нового пользователя."""
session = get_session() 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: try:
session.commit() # Сохраняем изменения в таблице Auth if session.query(Auth).filter_by(login=login).first():
return False, "Логин уже используется."
# Создаем новую запись в таблице Users, связывая с только что добавленным Auth # Создаем новую запись в Auth
# Используем new_auth.user_id для связи 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) new_user = Users(user_id=new_auth.user_id, username=username)
session.add(new_user) session.add(new_user)
session.commit() # Сохраняем изменения в таблице Users
# Создаем новый игровой процесс в GameSession для этого пользователя # Создаем запись в GameSession
new_game_session = GameSession(user_id=new_user.user_id, level=1) # Устанавливаем уровень по умолчанию new_game_session = GameSession(user_id=new_user.user_id, level=1)
session.add(new_game_session) session.add(new_game_session)
session.commit() # Сохраняем данные в GameSession session.commit()
print(f"Пользователь {username} успешно добавлен!") return True, "Регистрация успешна."
except SQLAlchemyError as e: except SQLAlchemyError as e:
session.rollback() # Откат изменений при ошибке session.rollback()
print(f"Ошибка при создании пользователя: {e}") logging.error(f"Ошибка при регистрации: {e}")
return False, "Произошла ошибка при регистрации." return False, "Произошла ошибка при регистрации."
finally: finally:
session.close() session.close()
return True, "Регистрация успешна."
def login_user(login, password): def login_user(login, password):
"""Авторизация пользователя.""" """Авторизация пользователя."""
session = get_session() session = get_session()
try:
# Проверяем, существует ли пользователь с таким логином и паролем auth = session.query(Auth).filter_by(login=login, password=password).first()
user_auth = session.query(Auth).filter_by(login=login, password=password).first() if auth:
return True, auth.user_id
if user_auth: return False, "Неверный логин или пароль."
# Возвращаем успешный вход и ID пользователя из таблицы Users except SQLAlchemyError as e:
user = session.query(Users).filter_by(user_id=user_auth.user_id).first() return False, f"Ошибка авторизации: {e}"
return True, user.user_id finally:
session.close()
return False, "Неверный логин или пароль."

View file

@ -1,13 +1,17 @@
import logging
import tkinter as tk import tkinter as tk
from tkinter import messagebox from tkinter import messagebox
from config import BACKGROUND_COLOR, PRIMARY_COLOR, BUTTON_COLOR, BUTTON_TEXT_COLOR, FONT, BIG_FONT, ADMIN_LOGIN, ADMIN_PASSWORD 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 src.ui.admin_ui import AdminApp # Импорт интерфейса администратора
from database.db_events import create_user, check_user from database.db_events import create_user, check_user
from src.ui.user_ui.main_menu import UserApp from src.ui.user_ui.main_menu import UserApp
class DogAcademyApp: class DogAcademyApp:
def __init__(self, root): def __init__(self, root, user_id=None):
"""Инициализация приложения."""
self.root = root self.root = root
self.user_id = user_id
self.root.title("Dog Academy Game") self.root.title("Dog Academy Game")
self.root.geometry("1920x1080") self.root.geometry("1920x1080")
self.root.configure(bg=BACKGROUND_COLOR) self.root.configure(bg=BACKGROUND_COLOR)
@ -20,12 +24,11 @@ class DogAcademyApp:
self.current_frame.destroy() self.current_frame.destroy()
def show_main_menu(self): def show_main_menu(self):
"""Показать главное меню с названием игры и кнопками.""" """Показать главное меню."""
self.clear_frame() self.clear_frame()
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR) self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True) self.current_frame.pack(expand=True)
# Название игры
title = tk.Label( title = tk.Label(
self.current_frame, self.current_frame,
text="Dog Academy Game", text="Dog Academy Game",
@ -35,7 +38,6 @@ class DogAcademyApp:
) )
title.pack(pady=50) title.pack(pady=50)
# Кнопка "Войти"
login_button = tk.Button( login_button = tk.Button(
self.current_frame, self.current_frame,
text="Войти", text="Войти",
@ -46,7 +48,6 @@ class DogAcademyApp:
) )
login_button.pack(pady=20) login_button.pack(pady=20)
# Кнопка "Зарегистрироваться"
register_button = tk.Button( register_button = tk.Button(
self.current_frame, self.current_frame,
text="Зарегистрироваться", text="Зарегистрироваться",
@ -63,7 +64,6 @@ class DogAcademyApp:
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR) self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True) self.current_frame.pack(expand=True)
# Заголовок
title = tk.Label( title = tk.Label(
self.current_frame, self.current_frame,
text="Авторизация", text="Авторизация",
@ -73,19 +73,16 @@ class DogAcademyApp:
) )
title.pack(pady=50) title.pack(pady=50)
# Логин
login_label = tk.Label(self.current_frame, text="Логин:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT) login_label = tk.Label(self.current_frame, text="Логин:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
login_label.pack() login_label.pack()
self.login_entry = tk.Entry(self.current_frame, font=FONT) self.login_entry = tk.Entry(self.current_frame, font=FONT)
self.login_entry.pack(pady=10) self.login_entry.pack(pady=10)
# Пароль
password_label = tk.Label(self.current_frame, text="Пароль:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT) password_label = tk.Label(self.current_frame, text="Пароль:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
password_label.pack() password_label.pack()
self.password_entry = tk.Entry(self.current_frame, show="*", font=FONT) self.password_entry = tk.Entry(self.current_frame, show="*", font=FONT)
self.password_entry.pack(pady=10) self.password_entry.pack(pady=10)
# Кнопка "Показать пароль"
show_password_button = tk.Button( show_password_button = tk.Button(
self.current_frame, self.current_frame,
text="Показать пароль", text="Показать пароль",
@ -96,7 +93,6 @@ class DogAcademyApp:
) )
show_password_button.pack(pady=10) show_password_button.pack(pady=10)
# Кнопка "Войти"
login_button = tk.Button( login_button = tk.Button(
self.current_frame, self.current_frame,
text="Войти", text="Войти",
@ -107,7 +103,6 @@ class DogAcademyApp:
) )
login_button.pack(pady=20) login_button.pack(pady=20)
# Кнопка "Вернуться на главную"
back_button = tk.Button( back_button = tk.Button(
self.current_frame, self.current_frame,
text="Вернуться на главную", text="Вернуться на главную",
@ -132,17 +127,21 @@ class DogAcademyApp:
if login == ADMIN_LOGIN and password == ADMIN_PASSWORD: if login == ADMIN_LOGIN and password == ADMIN_PASSWORD:
messagebox.showinfo("Успех", "Вы успешно авторизованы как администратор!") messagebox.showinfo("Успех", "Вы успешно авторизованы как администратор!")
self.show_admin_panel() # Переходим к админ-панели self.user_id = None # Администратору не нужен user_id
elif check_user(login, password): self.show_admin_panel()
messagebox.showinfo("Успех", "Вы успешно авторизованы!")
self.show_user_dashboard() # Переходим к панели пользователя
else: 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): def show_admin_panel(self):
"""Отображение интерфейса администратора.""" """Отображение интерфейса администратора."""
self.clear_frame() self.clear_frame()
AdminApp(self.root) # Создаем экземпляр админ-панели AdminApp(self.root)
def show_registration_screen(self): def show_registration_screen(self):
"""Показать экран регистрации.""" """Показать экран регистрации."""
@ -150,7 +149,6 @@ class DogAcademyApp:
self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR) self.current_frame = tk.Frame(self.root, bg=BACKGROUND_COLOR)
self.current_frame.pack(expand=True) self.current_frame.pack(expand=True)
# Заголовок
title = tk.Label( title = tk.Label(
self.current_frame, self.current_frame,
text="Регистрация", text="Регистрация",
@ -160,36 +158,21 @@ class DogAcademyApp:
) )
title.pack(pady=50) title.pack(pady=50)
# Логин
login_label = tk.Label(self.current_frame, text="Логин:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT) login_label = tk.Label(self.current_frame, text="Логин:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
login_label.pack() login_label.pack()
self.reg_login_entry = tk.Entry(self.current_frame, font=FONT) self.reg_login_entry = tk.Entry(self.current_frame, font=FONT)
self.reg_login_entry.pack(pady=10) 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 = tk.Label(self.current_frame, text="Пароль:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
password_label.pack() password_label.pack()
self.reg_password_entry = tk.Entry(self.current_frame, show="*", font=FONT) self.reg_password_entry = tk.Entry(self.current_frame, show="*", font=FONT)
self.reg_password_entry.pack(pady=10) 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 = tk.Label(self.current_frame, text="Никнейм:", bg=BACKGROUND_COLOR, fg=PRIMARY_COLOR, font=FONT)
username_label.pack() username_label.pack()
self.username_entry = tk.Entry(self.current_frame, font=FONT) self.username_entry = tk.Entry(self.current_frame, font=FONT)
self.username_entry.pack(pady=10) self.username_entry.pack(pady=10)
# Кнопка "Зарегистрироваться"
register_button = tk.Button( register_button = tk.Button(
self.current_frame, self.current_frame,
text="Зарегистрироваться", text="Зарегистрироваться",
@ -200,7 +183,6 @@ class DogAcademyApp:
) )
register_button.pack(pady=20) register_button.pack(pady=20)
# Кнопка "Вернуться на главную"
back_button = tk.Button( back_button = tk.Button(
self.current_frame, self.current_frame,
text="Вернуться на главную", text="Вернуться на главную",
@ -222,19 +204,19 @@ class DogAcademyApp:
"""Регистрация нового пользователя.""" """Регистрация нового пользователя."""
login = self.reg_login_entry.get() login = self.reg_login_entry.get()
password = self.reg_password_entry.get() password = self.reg_password_entry.get()
username = self.username_entry.get() # Получаем имя пользователя username = self.username_entry.get()
if login and password and username: if login and password and username:
success, message = create_user(login, password, username) # Передаем имя пользователя success, message = create_user(login, password, username)
if success: if success:
messagebox.showinfo("Успех", message) messagebox.showinfo("Успех", message)
self.show_login_screen() self.show_login_screen()
else: else:
messagebox.showerror("Ошибка", message) messagebox.showerror("Ошибка", message)
else: else:
messagebox.showerror("Ошибка", "Пожалуйста, заполните все поля.") messagebox.showerror("Ошибка", "Заполните все поля.")
def show_user_dashboard(self): def show_user_dashboard(self):
"""Переход к пользовательскому интерфейсу."""
self.clear_frame() self.clear_frame()
"""Перейти к главному меню пользователя после авторизации.""" UserApp(self.root, self.user_id)
UserApp(self.root)

View file

@ -1,9 +1,10 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk from PIL import Image, ImageTk
import random import random
import logging import logging
from database.db_events import get_user_by_id, get_user_progress, save_progress
from database.db_events import get_user_by_id
from database.info.GameSessions_table import save_game_session from database.info.GameSessions_table import save_game_session
from src.user_functions.game_logs import setup_logging from src.user_functions.game_logs import setup_logging
from config import DOG_CHARACTERS, DONE, BONE, BACKGROUND_GAME from config import DOG_CHARACTERS, DONE, BONE, BACKGROUND_GAME
@ -12,14 +13,22 @@ from src.utils import clear_frame
# Настройка логирования # Настройка логирования
setup_logging() setup_logging()
user = get_user_by_id(user_id=1)
if user:
print(f"Данные пользователя: {user}")
else:
print("Пользователь не найден")
class GameUI: class GameUI:
def __init__(self, root, user_id, return_to_main_menu_callback): def __init__(self, root, user_id, return_to_main_menu_callback):
if not user_id:
raise ValueError("user_id отсутствует при инициализации GameUI!")
self.root = root self.root = root
self.user_id = user_id self.user_id = user_id
self.return_to_main_menu_callback = return_to_main_menu_callback self.return_to_main_menu_callback = return_to_main_menu_callback
self.selected_dog = None self.selected_dog = None
self.current_level = 1 self.current_level = 1
self.max_unlocked_level = 1
self.completed_levels = set() self.completed_levels = set()
self.total_bones = 0 self.total_bones = 0
@ -28,6 +37,11 @@ class GameUI:
self.bones_positions = [] self.bones_positions = []
self.max_bones_per_level = 10 self.max_bones_per_level = 10
self.steps_taken = 0 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
# Изображения # Изображения
self.done_image = ImageTk.PhotoImage(Image.open(DONE).resize((50, 50), Image.Resampling.LANCZOS)) self.done_image = ImageTk.PhotoImage(Image.open(DONE).resize((50, 50), Image.Resampling.LANCZOS))
@ -45,7 +59,7 @@ class GameUI:
# Флаги # Флаги
self.is_pause_menu_open = False self.is_pause_menu_open = False
self.is_victory_screen_open = False self.is_victory_screen_open = False
self.is_game_active = False # Для контроля состояния игры self.is_game_active = False
# Привязка клавиш # Привязка клавиш
self.root.bind("<KeyPress-w>", self.move_up) self.root.bind("<KeyPress-w>", self.move_up)
@ -57,6 +71,15 @@ class GameUI:
# Отображение начального экрана # Отображение начального экрана
self.show_dog_selection() self.show_dog_selection()
# Инициализация интерфейса
self.create_main_menu_button()
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): def create_background(self):
"""Создаёт фон для игры.""" """Создаёт фон для игры."""
try: try:
@ -122,62 +145,99 @@ class GameUI:
clear_frame(self.root) clear_frame(self.root)
self.create_background() self.create_background()
tk.Label( tk.Label(self.root, text="Выберите уровень", font=("Comic Sans MS", 24), bg="#E5E5E5").pack(pady=20)
self.root, text="Выберите уровень", font=("Comic Sans MS", 24), bg="#E5E5E5"
).pack(pady=20)
level_frame = tk.Frame(self.root, bg="#E5E5E5") level_frame = tk.Frame(self.root, bg="#E5E5E5")
level_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) level_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER)
for level in range(1, 6): progress = get_user_progress(self.user_id)
completed_levels = {session.level for session in progress if session.score > 0}
self.max_unlocked_level = max(completed_levels) if completed_levels else 1
for level in range(1, 101):
color = (
"#4CAF50" if level in 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( button = tk.Button(
level_frame, level_frame,
text=f"Уровень {level}", text=f"Уровень {level}",
state=tk.NORMAL if level <= self.max_unlocked_level else tk.DISABLED, bg=color,
font=("Comic Sans MS", 20), state=state,
bg="#4CAF50" if level <= self.max_unlocked_level else "#A9A9A9", font=("Comic Sans MS", 14),
width=15, command=lambda l=level: self.handle_level_selection(l)
height=2,
command=lambda l=level: self.start_level(l),
) )
button.pack(pady=10) button.grid(row=(level - 1) // 10, column=(level - 1) % 10, padx=5, pady=5)
tk.Button( tk.Button(
self.root, self.root,
text="Вернуться", text="Вернуться",
font=("Comic Sans MS", 16), font=("Comic Sans MS", 16),
bg="lightgreen", bg="lightgreen",
command=self.show_dog_selection, command=self.show_dog_selection
).place(relx=0.5, rely=0.9, anchor=tk.CENTER) ).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.current_level = level
self.total_bones = 0
self.steps_taken = 0
self.start_game()
elif level <= self.max_unlocked_level:
self.current_level = level
self.countdown()
else:
messagebox.showinfo("Недоступно", "Пройдите предыдущие уровни, чтобы разблокировать этот.")
def start_level(self, level): def start_level(self, level):
"""Начало выбранного уровня.""" """Запуск уровня."""
self.current_level = level if level in self.completed_levels:
self.countdown() 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): def countdown(self):
"""Обратный отсчёт перед началом уровня.""" """Обратный отсчёт перед началом уровня с анимацией."""
clear_frame(self.root) clear_frame(self.root) # Очищаем экран
countdown_label = tk.Label( countdown_label = tk.Label(
self.root, text="", font=("Comic Sans MS", 30), bg="#E5E5E5" self.root, text="Готовьтесь!", font=("Comic Sans MS", 40), bg="#E5E5E5"
) )
countdown_label.pack(expand=True) countdown_label.pack(expand=True)
for i in range(3, 0, -1): def update_countdown(counter):
countdown_label.config(text=f"{i}...") if counter > 0:
self.root.update() countdown_label.config(text=f"{counter}", fg=random.choice(["red", "green", "blue"]))
self.root.after(1000) 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, self.start_game)
self.start_game() update_countdown(3) # Старт обратного отсчёта с 3 секунд
def start_game(self): def start_game(self):
"""Запуск игрового процесса.""" """Запуск игрового процесса."""
clear_frame(self.root) logging.info(f"Игра начата на уровне {self.current_level}")
clear_frame(self.root) # Очищаем экран
self.map_canvas = tk.Canvas(self.root, width=1920, height=1080, bg="#E5E5E5") self.map_canvas = tk.Canvas(self.root, width=1920, height=1080, bg="#E5E5E5")
self.map_canvas.pack() self.map_canvas.pack()
self.draw_grid() self.draw_grid()
self.bones_positions = self.generate_bones() self.bones_positions = self.generate_bones() # Генерация новых косточек
# Прямоугольник и изображение косточек (создаются один раз) # Прямоугольник и изображение косточек (создаются один раз)
self.rect_x1, self.rect_y1 = 1600, 0 self.rect_x1, self.rect_y1 = 1600, 0
@ -189,11 +249,6 @@ class GameUI:
self.bones_label = tk.Label(self.root, text=f"{self.total_bones}", font=("Comic Sans MS", 16), bg="#CCCCCC") 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.bones_label.place(x=1700, y=30)
# В методе update_map (не удаляем прямоугольник):
self.map_canvas.delete("all") # Удаляем только динамичные объекты карты (косточки, собаку)
self.draw_grid()
self.collect_bones()
self.update_map() # Начальное обновление карты self.update_map() # Начальное обновление карты
def draw_grid(self): def draw_grid(self):
@ -204,11 +259,15 @@ class GameUI:
self.map_canvas.create_line(0, y, 1920, y, fill="lightgray") self.map_canvas.create_line(0, y, 1920, y, fill="lightgray")
def generate_bones(self): def generate_bones(self):
"""Генерация косточек на карте.""" """Генерация косточек на карте с увеличением их количества по геометрической прогрессии."""
return [ # Количество косточек увеличивается по геометрической прогрессии
bones_count = min(5, 10 * (2 ** (self.current_level - 1))) # Ограничение в 5 косточек на уровне
bones = [
(random.randint(0, self.cols - 1), random.randint(0, self.rows - 1)) (random.randint(0, self.cols - 1), random.randint(0, self.rows - 1))
for _ in range(2) for _ in range(bones_count)
] ]
logging.info(f"Генерация косточек: {bones}") # Логируем координаты косточек
return bones
def collect_bones(self): def collect_bones(self):
"""Проверка и сбор косточек.""" """Проверка и сбор косточек."""
@ -216,10 +275,19 @@ class GameUI:
if self.dog_position == [bone[0], bone[1]]: if self.dog_position == [bone[0], bone[1]]:
self.bones_positions.remove(bone) self.bones_positions.remove(bone)
self.total_bones += 1 self.total_bones += 1
# Сохранение прогресса
save_progress(self.user_id, self.current_level, self.total_bones, self.steps_taken, 100, 0, 0)
self.bones_label.config(text=f"{self.total_bones}") 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:
self.show_victory_screen() # Показываем экран победы
if self.steps_taken % 10 == 0 and len(self.bones_positions) < self.max_bones_per_level: if self.steps_taken % 10 == 0 and len(self.bones_positions) < self.max_bones_per_level:
self.bones_positions.extend(self.generate_bones()) self.bones_positions.extend(self.generate_bones()) # Генерация новых косточек, если нужно
def move_up(self, event): def move_up(self, event):
"""Движение вверх.""" """Движение вверх."""
@ -299,6 +367,7 @@ class GameUI:
if self.is_pause_menu_open: if self.is_pause_menu_open:
self.pause_window.destroy() # Закрываем окно паузы self.pause_window.destroy() # Закрываем окно паузы
self.is_pause_menu_open = False # Сбрасываем флаг self.is_pause_menu_open = False # Сбрасываем флаг
self.is_game_active = True # Возвращаем игру в активное состояние
def save_and_exit(self): def save_and_exit(self):
"""Сохранение данных и выход в главное меню.""" """Сохранение данных и выход в главное меню."""
@ -313,8 +382,8 @@ class GameUI:
if self.is_victory_screen_open: # Отключаем обновления, если окно победы открыто if self.is_victory_screen_open: # Отключаем обновления, если окно победы открыто
return return
self.map_canvas.delete("all") self.map_canvas.delete("all") # Удаляем старые объекты карты
self.draw_grid() self.draw_grid() # Перерисовываем сетку
# Отображение косточек # Отображение косточек
for x, y in self.bones_positions: for x, y in self.bones_positions:
@ -325,14 +394,17 @@ class GameUI:
) )
# Отображение собаки # Отображение собаки
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize((self.grid_size, self.grid_size), if self.selected_dog:
Image.Resampling.LANCZOS) dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize(
self.dog_photo = ImageTk.PhotoImage(dog_image) (self.grid_size, self.grid_size),
self.map_canvas.create_image( Image.Resampling.LANCZOS
self.dog_position[0] * self.grid_size + self.grid_size // 2, )
self.dog_position[1] * self.grid_size + self.grid_size // 2, self.dog_photo = ImageTk.PhotoImage(dog_image)
image=self.dog_photo 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() self.collect_bones()
@ -344,17 +416,17 @@ class GameUI:
def show_victory_screen(self): def show_victory_screen(self):
"""Экран победы.""" """Экран победы."""
if self.is_victory_screen_open: # Проверяем, чтобы не было второго окна if self.is_victory_screen_open:
return return
self.is_victory_screen_open = True # Устанавливаем флаг self.is_victory_screen_open = True
self.is_game_active = False # Останавливаем движение self.is_game_active = False
victory_window = tk.Toplevel(self.root) victory_window = tk.Toplevel(self.root)
victory_window.title("Ура, победа!") victory_window.title("Ура, победа!")
victory_window.geometry("800x600") victory_window.geometry("800x600")
victory_window.configure(bg="#E5E5E5") victory_window.configure(bg="#E5E5E5")
victory_window.grab_set() # Блокируем взаимодействие с основным окном victory_window.grab_set()
# Изображение собаки # Изображение собаки
dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize((200, 200), Image.Resampling.LANCZOS) dog_image = Image.open(DOG_CHARACTERS[self.selected_dog]["image"]).resize((200, 200), Image.Resampling.LANCZOS)
@ -364,26 +436,26 @@ class GameUI:
dog_label.place(x=50, y=50) dog_label.place(x=50, y=50)
# Текст победы # Текст победы
victory_label = tk.Label( victory_label = tk.Label(victory_window, text="Ура, победа!", font=("Comic Sans MS", 24), bg="#E5E5E5")
victory_window, text="Ура, победа!", font=("Comic Sans MS", 24), bg="#E5E5E5"
)
victory_label.pack(pady=20) victory_label.pack(pady=20)
# Характеристики собаки # Характеристики собаки
dog_info = f"Порода: {self.selected_dog}" dog_info = f"Порода: {self.selected_dog}"
info_label = tk.Label( info_label = tk.Label(victory_window, text=dog_info, font=("Comic Sans MS", 16), bg="#E5E5E5")
victory_window, text=dog_info, font=("Comic Sans MS", 16), bg="#E5E5E5"
)
info_label.place(x=300, y=100) info_label.place(x=300, y=100)
# Собрано косточек # Собрано косточек
target_bones = 10 * (2 ** (self.current_level - 1)) # Геометрическая прогрессия для косточек target_bones = 10 * (2 ** (self.current_level - 1)) # Геометрическая прогрессия
collected_info = f"Собрано: {self.total_bones} из {target_bones}" collected_info = f"Собрано: {self.total_bones} из {target_bones}"
score_label = tk.Label( score_label = tk.Label(victory_window, text=collected_info, font=("Comic Sans MS", 16), bg="#E5E5E5")
victory_window, text=collected_info, font=("Comic Sans MS", 16), bg="#E5E5E5"
)
score_label.place(x=300, y=150) score_label.place(x=300, y=150)
# Никнейм игрока
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=200)
# Кнопка перехода на следующий уровень # Кнопка перехода на следующий уровень
next_level_button = tk.Button( next_level_button = tk.Button(
victory_window, victory_window,
@ -404,29 +476,91 @@ class GameUI:
) )
exit_button.place(relx=0.5, rely=0.8, anchor=tk.CENTER) exit_button.place(relx=0.5, rely=0.8, anchor=tk.CENTER)
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): def return_to_main_menu(self):
"""Возврат в главное меню.""" """Возврат в главное меню."""
self.is_victory_screen_open = False # Сбрасываем флаг окна победы if self.is_pause_menu_open:
self.return_to_main_menu_callback() # Вызываем колбэк для возврата self.pause_window.destroy() # Закрываем окно паузы
self.is_pause_menu_open = False # Сбрасываем флаг
clear_frame(self.root) # Очищаем текущий экран
self.show_main_menu() # Переходим в главное меню
def start_next_level(self): def start_next_level(self):
"""Переход на следующий уровень.""" """Переход на следующий уровень."""
self.save_progress() # Сохраняем прогресс перед переходом на следующий уровень try:
# Сохранение текущего прогресса
self.save_progress()
# Переход на следующий уровень # Переход на следующий уровень
self.current_level += 1 self.current_level += 1
self.total_bones = 0 # Сбрасываем счётчик косточек self.max_unlocked_level = max(self.max_unlocked_level, self.current_level)
self.start_level(self.current_level)
# Сброс состояния игры: собака возвращается в начальную позицию
self.total_bones = 0
self.steps_taken = 0
self.dog_position = [1, 1] # Начальная позиция собаки
self.bones_positions = [] # Очищаем текущие косточки
# Генерация новых косточек с увеличением их количества по геометрической прогрессии
self.bones_positions = self.generate_bones()
# Начинаем новый уровень с обратным отсчётом
self.countdown() # Запуск обратного отсчёта
except Exception as e:
logging.error(f"Ошибка при переходе на следующий уровень: {e}")
def save_progress(self): def save_progress(self):
"""Сохранение игрового процесса в таблицу GameSessions.""" """Сохранение игрового процесса в таблицу GameSessions."""
from datetime import datetime if not self.user_id:
logging.error("Ошибка: user_id равен None. Запись невозможна.")
return
# Получаем время начала и окончания уровня try:
duration = self.steps_taken # Время можно рассчитать по шагам или в реальном времени # Рассчитываем длительность уровня и текущий счет
score = self.total_bones # Количество собранных косточек duration = self.steps_taken
score = self.total_bones
# Сохранение прогресса в базу данных # Логирование
save_game_session(self.user_id, self.current_level, score, duration, 100, 0, 0) 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

@ -1,6 +1,7 @@
import os import os
import logging import logging
import tkinter as tk import tkinter as tk
from functools import partial
from tkinter import messagebox, Canvas from tkinter import messagebox, Canvas
from PIL import Image, ImageTk from PIL import Image, ImageTk
import math import math
@ -31,10 +32,11 @@ PLAY_BUTTON_RADIUS = 100 # Радиус кнопки "Играть"
class UserApp: class UserApp:
def __init__(self, root, user_id=None): def __init__(self, root, user_id):
"""Инициализация пользовательского интерфейса."""
self.root = root self.root = root
self.user_id = user_id self.user_id = user_id
self.root.configure(bg=BACKGROUND_COLOR) self.root.configure(bg="#E5E5E5")
self.root.geometry("1920x1080") self.root.geometry("1920x1080")
self.root.title("Собачья академия") self.root.title("Собачья академия")
self.show_user_dashboard() self.show_user_dashboard()
@ -151,8 +153,12 @@ class UserApp:
def show_profile(self): def show_profile(self):
"""Показать экран профиля пользователя.""" """Показать экран профиля пользователя."""
self.clear_frame() try:
profile_ui(self.root, self.user_id, self) # Передаем сам объект self для доступа к show_user_dashboard 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): def clear_frame(self):
"""Очистить текущий экран.""" """Очистить текущий экран."""
@ -160,16 +166,17 @@ class UserApp:
widget.destroy() widget.destroy()
def play_game(self): def play_game(self):
"""Переход к игровому интерфейсу.""" """Запуск игры и передача колбэка для возврата в меню."""
print("Запуск игры...") # Передаем метод через 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(): def return_to_main_menu(self):
clear_frame(self.root) """Возврат в главное меню."""
self.show_user_dashboard() # Возврат в главное меню self.clear_frame() # Очищаем экран перед переходом
self.show_user_dashboard() # Показываем главное меню
GameUI(self.root, self.user_id, return_to_main_menu) # Передаём колбэк для возврата
def exit_app(self): def exit_app(self):
"""Подтверждение выхода из приложения.""" """Подтверждение выхода из приложения."""
if messagebox.askyesno("Выход", "Вы уверены, что хотите выйти?"): if messagebox.askyesno("Выход", "Вы уверены, что хотите выйти?"):
self.root.quit() self.root.quit()

View file

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

View file

@ -1,27 +1,9 @@
import logging
import time import time
import tkinter as tk import tkinter as tk
from src.utils import clear_frame from src.utils import clear_frame
from database.db_events import save_progress 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) # Пауза между отсчетами
# Начало уровня
print("Начало уровня") # Для отладки
# Здесь подключается логика работы с картой и вопросами
pass
def handle_checkpoint(obstacle, current_score, root): def handle_checkpoint(obstacle, current_score, root):
""" """
Обрабатывает чек-поинт (косточку). Обрабатывает чек-поинт (косточку).

View file

@ -1,12 +1,13 @@
import logging import logging
import os import os
def setup_logging(): def setup_logging():
"""Настройка логирования в файл.""" """Настройка логирования в файл."""
log_file = "logs/game.log" log_dir = "logs"
if not os.path.exists(log_file): if not os.path.exists(log_dir):
os.makedirs(log_file) os.makedirs(log_dir) # Создание директории, если она не существует
log_file = os.path.join(log_dir, "game.log")
logging.basicConfig( logging.basicConfig(
filename=log_file, filename=log_file,