Загрузка данных


importtkinter as tk
from tkinter import messagebox, ttk
import random
import json
import os


WINDOW_TITLE = "Батискаф — сборресурсов"

CELL_SIZE = 42
GRID_COLS = 15
GRID_ROWS = 12

COLOR_BG = "#0b1d33"
COLOR_GRID = "#1e3a5f"
COLOR_PANEL = "#11294a"
COLOR_TEXT = "#e6f0ff"

COLOR_WATER = "#12335a"
COLOR_ROCK = "#555f6a"
COLOR_SEAWEED = "#2f7a52"
COLOR_CRYSTAL = "#00d8ff"
COLOR_PEARL = "#f5f0d6"
COLOR_GOLD = "#f2c94c"
COLOR_MINE = "#b03a2e"
COLOR_OXYGEN = "#7ed3f7"
COLOR_SURFACE = "#98e37e"
COLOR_BATHYSCAPHE = "#ffb84d"

START_OXYGEN = 100
START_BATTERY = 100
OXYGEN_COST = 2
BATTERY_COST = 1

RESOURCE_SCORES = {"crystal": 10, "pearl": 20, "gold": 35}
OBSTACLE_PENALTIES = {"mine": -15}

LEVELS = [
    {"name": "Мелководье", "obstacles": 12, "resources": 10, "mines": 0},
    {"name": "Подводныерифы", "obstacles": 22, "resources": 12, "mines": 2},
    {"name": "Глубина", "obstacles": 30, "resources": 14, "mines": 4},
    {"name": "Затонувшийгород", "obstacles": 38, "resources": 16, "mines": 6},
]




class World:

    def __init__(self, cols, rows, obstacles_count, resources_count,
mines_count):
self.cols = cols
self.rows = rows
self.obstacles_count = obstacles_count
self.resources_count = resources_count
self.mines_count = mines_count
self.grid = [["empty"] * cols for _ in range(rows)]
self.start_position = (1, 1)
self.surface_position = (cols - 2, rows - 2)

    def generate(self):
self.grid = [["empty"] * self.cols for _ in range(self.rows)]
self.start_position = (1, 1)
self.surface_position = (self.cols - 2, self.rows - 2)
sx, sy = self.surface_position
self.grid[sy][sx] = "surface"
        self._place_obstacles()
self._place_resources()
self._place_mines()
self._place_oxygen_stations(2)

    def get_cell(self, x, y):
        return self.grid[y][x]

    def set_cell(self, x, y, value):
self.grid[y][x] = value

    def is_inside(self, x, y):
        return 0 <= x <self.cols and 0 <= y <self.rows

    def _is_protected(self, x, y, radius=1):
sx, sy = self.start_position
fx, fy = self.surface_position
near_start = abs(x - sx) <= radius and abs(y - sy) <= radius
near_finish = abs(x - fx) <= radius and abs(y - fy) <= radius
        return near_start or near_finish

    def _place_obstacles(self):
        placed = 0
        attempts = 0
        while placed <self.obstacles_count and attempts < 1000:
            attempts += 1
            x = random.randint(0, self.cols - 1)
            y = random.randint(0, self.rows - 1)
            if self._is_protected(x, y) or self.grid[y][x] != "empty":
continue
self.grid[y][x] = random.choice(["rock", "rock", "seaweed"])
            placed += 1

    def _place_resources(self):
        pool = ["crystal"] * 5 + ["pearl"] * 3 + ["gold"] * 2
        placed = 0
        attempts = 0
        while placed <self.resources_count and attempts < 1000:
            attempts += 1
            x = random.randint(0, self.cols - 1)
            y = random.randint(0, self.rows - 1)
            if self._is_protected(x, y) or self.grid[y][x] != "empty":
continue
self.grid[y][x] = random.choice(pool)
            placed += 1

    def _place_mines(self):
        placed = 0
        attempts = 0
        while placed <self.mines_count and attempts < 1000:
            attempts += 1
            x = random.randint(0, self.cols - 1)
            y = random.randint(0, self.rows - 1)
            if self._is_protected(x, y, radius=2) or \
self.grid[y][x] != "empty":
continue
self.grid[y][x] = "mine"
placed += 1

    def _place_oxygen_stations(self, count):
        placed = 0
        attempts = 0
        while placed < count and attempts < 1000:
            attempts += 1
            x = random.randint(0, self.cols - 1)
            y = random.randint(0, self.rows - 1)
            if self._is_protected(x, y) or self.grid[y][x] != "empty":
continue
self.grid[y][x] = "oxygen_station"
            placed += 1




class Bathyscaphe:

    def __init__(self, x, y, oxygen, battery):
self.x = x
self.y = y
self.oxygen = oxygen
self.battery = battery
self.inventory = {}

    def move_to(self, new_x, new_y):
self.x = new_x
self.y = new_y

    def is_alive(self):
        return self.oxygen> 0 and self.battery> 0




class Renderer:

    def __init__(self, canvas, world, bathyscaphe):
self.canvas = canvas
self.world = world
self.bathyscaphe = bathyscaphe

    def draw_world(self):
self.canvas.delete("all")
        for y in range(self.world.rows):
            for x in range(self.world.cols):
                self._draw_cell(x, y, self.world.get_cell(x, y))

    def draw_bathyscaphe(self):
        x = self.bathyscaphe.x
        y = self.bathyscaphe.y
px, py = x * CELL_SIZE, y * CELL_SIZE
        pad = 4
        # Корпус
self.canvas.create_oval(
px + pad, py + pad + 4,
px + CELL_SIZE - pad, py + CELL_SIZE - pad - 4,
            fill=COLOR_BATHYSCAPHE, outline="#a65a00", width=2
        )
        # Иллюминатор
        cx = px + CELL_SIZE // 2
        cy = py + CELL_SIZE // 2
        r = 6
self.canvas.create_oval(
cx - r, cy - r, cx + r, cy + r,
fill="#0b1d33", outline="#cceeff", width=1
        )
        # Пропеллеры
self.canvas.create_line(
px + 2, cy, px + pad, cy, fill="#a65a00", width=2
        )
self.canvas.create_line(
px + CELL_SIZE - pad, cy, px + CELL_SIZE - 2, cy,
            fill="#a65a00", width=2
        )

    def _draw_cell(self, x, y, cell_type):
        self._draw_water(x, y)
        if cell_type == "rock":
            self._draw_rock(x, y)
elifcell_type == "seaweed":
            self._draw_seaweed(x, y)
elifcell_type == "crystal":
            self._draw_crystal(x, y)
elifcell_type == "pearl":
            self._draw_pearl(x, y)
elifcell_type == "gold":
            self._draw_gold(x, y)
elifcell_type == "mine":
            self._draw_mine(x, y)
elifcell_type == "oxygen_station":
            self._draw_oxygen_station(x, y)
elifcell_type == "surface":
            self._draw_surface(x, y)

    def _draw_water(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
self.canvas.create_rectangle(
px, py, px + CELL_SIZE, py + CELL_SIZE,
            fill=COLOR_WATER, outline=COLOR_GRID
        )

    def _draw_rock(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        points = [
px + 6, py + CELL_SIZE - 6,
px + 12, py + 10,
px + CELL_SIZE // 2, py + 6,
px + CELL_SIZE - 10, py + 14,
px + CELL_SIZE - 4, py + CELL_SIZE - 6,
        ]
self.canvas.create_polygon(
            points, fill=COLOR_ROCK, outline="#2a3138", width=2
        )

    def _draw_seaweed(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        for offset in (10, CELL_SIZE // 2, CELL_SIZE - 10):
self.canvas.create_line(
px + offset, py + CELL_SIZE - 4,
px + offset - 3, py + CELL_SIZE // 2,
px + offset + 2, py + 10,
                fill=COLOR_SEAWEED, width=3, smooth=True
            )

    def _draw_crystal(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        cx = px + CELL_SIZE // 2
        cy = py + CELL_SIZE // 2
        s = 12
self.canvas.create_polygon(
            cx, cy - s, cx + s, cy, cx, cy + s, cx - s, cy,
            fill=COLOR_CRYSTAL, outline="#ffffff", width=2
        )

    def _draw_pearl(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        cx = px + CELL_SIZE // 2
        cy = py + CELL_SIZE // 2
        r = 12
self.canvas.create_oval(
cx - r, cy - r, cx + r, cy + r,
fill=COLOR_PEARL, outline="#888", width=1
        )
self.canvas.create_oval(
            cx - 5, cy - 6, cx - 1, cy - 2,
            fill="#ffffff", outline=""
        )

    def _draw_gold(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        pad = 8
self.canvas.create_rectangle(
px + pad, py + pad + 4,
px + CELL_SIZE - pad, py + CELL_SIZE - pad - 4,
            fill=COLOR_GOLD, outline="#a07a00", width=2
        )
self.canvas.create_line(
px + pad + 2, py + pad + 7,
px + CELL_SIZE - pad - 2, py + pad + 7,
            fill="#fff3a0", width=2
        )

    def _draw_mine(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        cx = px + CELL_SIZE // 2
        cy = py + CELL_SIZE // 2
        r = 10
        for dx, dy in [(-14, 0), (14, 0), (0, -14), (0, 14),
                       (-10, -10), (10, -10), (-10, 10), (10, 10)]:
self.canvas.create_line(
                cx, cy, cx + dx, cy + dy,
                fill=COLOR_MINE, width=3
            )
self.canvas.create_oval(
cx - r, cy - r, cx + r, cy + r,
fill=COLOR_MINE, outline="#5f0e0e", width=2
        )

    def _draw_oxygen_station(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        cx = px + CELL_SIZE // 2
        cy = py + CELL_SIZE // 2
        r = 14
self.canvas.create_oval(
cx - r, cy - r, cx + r, cy + r,
fill=COLOR_OXYGEN, outline="#1a6a94", width=2
        )
self.canvas.create_text(
            cx, cy, text="O2",
            font=("Arial", 10, "bold"), fill="#0b1d33"
        )

    def _draw_surface(self, x, y):
px, py = x * CELL_SIZE, y * CELL_SIZE
        pad = 5
self.canvas.create_rectangle(
px + pad, py + pad,
px + CELL_SIZE - pad, py + CELL_SIZE - pad,
            fill=COLOR_SURFACE, outline="#2a6e1a", width=2
        )
        cx = px + CELL_SIZE // 2
        cy = py + CELL_SIZE // 2
self.canvas.create_polygon(
            cx, cy - 8, cx + 7, cy + 2, cx - 7, cy + 2,
            fill="#2a6e1a"
        )
self.canvas.create_rectangle(
            cx - 2, cy + 2, cx + 2, cy + 10,
            fill="#2a6e1a", outline=""
        )




class StatsPanel(tk.Frame):

    def __init__(self, parent):
super().__init__(parent, bg=COLOR_PANEL)

        title = tk.Label(self, text="Панельуправления",
bg=COLOR_PANEL, fg=COLOR_TEXT,
                         font=("Arial", 13, "bold"))
title.pack(anchor="w")

self.level_label = tk.Label(self, text="Уровень: —",
bg=COLOR_PANEL, fg=COLOR_TEXT,
                                    font=("Arial", 11), anchor="w")
self.level_label.pack(fill="x", pady=(8, 2))

self.score_label = tk.Label(self, text="Очки: 0",
bg=COLOR_PANEL, fg="#ffd17a",
                                    font=("Arial", 14, "bold"), anchor="w")
self.score_label.pack(fill="x", pady=2)

self.moves_label = tk.Label(self, text="Ходов: 0",
bg=COLOR_PANEL, fg=COLOR_TEXT,
                                    font=("Arial", 11), anchor="w")
self.moves_label.pack(fill="x", pady=2)

tk.Label(self, text="Кислород:",
bg=COLOR_PANEL, fg=COLOR_TEXT,
                 font=("Arial", 10), anchor="w").pack(fill="x", pady=(10, 0))
self.oxygen_bar = ttk.Progressbar(self, orient="horizontal",
                                          length=180, maximum=START_OXYGEN)
self.oxygen_bar.pack(fill="x")
self.oxygen_value = tk.Label(self,
                                     text=f"{START_OXYGEN}/{START_OXYGEN}",
bg=COLOR_PANEL, fg="#7ed3f7",
                                     font=("Arial", 10), anchor="e")
self.oxygen_value.pack(fill="x")

tk.Label(self, text="Батарея:",
bg=COLOR_PANEL, fg=COLOR_TEXT,
                 font=("Arial", 10), anchor="w").pack(fill="x", pady=(8, 0))
self.battery_bar = ttk.Progressbar(self, orient="horizontal",
                                           length=180, maximum=START_BATTERY)
self.battery_bar.pack(fill="x")
self.battery_value = tk.Label(self,
                                      text=f"{START_BATTERY}/{START_BATTERY}",
bg=COLOR_PANEL, fg="#f5d97a",
                                      font=("Arial", 10), anchor="e")
self.battery_value.pack(fill="x")

tk.Label(self, text="Инвентарь:",
bg=COLOR_PANEL, fg=COLOR_TEXT,
                 font=("Arial", 11, "bold"),
                 anchor="w").pack(fill="x", pady=(10, 2))
self.inventory_label = tk.Label(self, text="— пусто —",
bg=COLOR_PANEL, fg="#d7e6ff",
                                        font=("Arial", 10),
                                        anchor="w", justify="left")
self.inventory_label.pack(fill="x")

self.message_label = tk.Label(self, text="",
bg=COLOR_PANEL, fg="#b5d9ff",
                                      font=("Arial", 10, "italic"),
                                      anchor="w", wraplength=200,
                                      justify="left")
self.message_label.pack(fill="x", pady=(10, 0))

    def update_values(self, level, level_name, score, moves,
                      oxygen, battery, inventory):
self.level_label.config(text=f"Уровень: {level} — {level_name}")
self.score_label.config(text=f"Очки: {score}")
self.moves_label.config(text=f"Ходов: {moves}")
self.oxygen_bar["value"] = oxygen
self.oxygen_value.config(text=f"{oxygen}/{START_OXYGEN}")
self.battery_bar["value"] = battery
self.battery_value.config(text=f"{battery}/{START_BATTERY}")
self.inventory_label.config(text=self._format_inventory(inventory))

    def set_message(self, text):
self.message_label.config(text=text)

    @staticmethod
    def _format_inventory(inventory):
        if not inventory:
            return "— пусто —"
        names = {"crystal": "Кристаллы", "pearl": "Жемчуг", "gold": "Золото"}
        lines = []
        for key, count in inventory.items():
            label = names.get(key, key)
lines.append(f"  {label}: {count}")
        return "\n".join(lines)




class BathyscapheApp:

    def __init__(self, root):
self.root = root
self.root.title(WINDOW_TITLE)
self.root.configure(bg=COLOR_BG)
self.root.resizable(False, False)

self.current_level = 0
self.game_over = False
self.score = 0
self.moves = 0

self._create_menu()
self._create_widgets()
self._start_level(self.current_level)
self._bind_keys()

    def _create_menu(self):
menu_bar = tk.Menu(self.root)

game_menu = tk.Menu(menu_bar, tearoff=0)
game_menu.add_command(label="Новаяигра", command=self._new_game)
game_menu.add_command(label="Перезапуститьуровень",
                              command=self._restart_level)
game_menu.add_separator()
        game_menu.add_command(label="Сохранитьрезультат",
command=self._save_result)
game_menu.add_separator()
game_menu.add_command(label="Выход", command=self.root.quit)
menu_bar.add_cascade(label="Игра", menu=game_menu)

level_menu = tk.Menu(menu_bar, tearoff=0)
        for idx, level in enumerate(LEVELS):
level_menu.add_command(
                label=f"Уровень {idx + 1}: {level['name']}",
                command=lambda i=idx: self._start_level(i)
            )
menu_bar.add_cascade(label="Уровень", menu=level_menu)

help_menu = tk.Menu(menu_bar, tearoff=0)
help_menu.add_command(label="Правила", command=self._show_rules)
help_menu.add_command(label="Опрограмме", command=self._show_about)
menu_bar.add_cascade(label="Справка", menu=help_menu)

self.root.config(menu=menu_bar)

    def _create_widgets(self):
main_frame = tk.Frame(self.root, bg=COLOR_BG)
main_frame.pack(padx=10, pady=10)

canvas_width = GRID_COLS * CELL_SIZE
canvas_height = GRID_ROWS * CELL_SIZE
self.canvas = tk.Canvas(
main_frame, width=canvas_width, height=canvas_height,
bg=COLOR_BG, highlightthickness=2,
highlightbackground=COLOR_GRID
        )
self.canvas.grid(row=0, column=0, rowspan=2, padx=(0, 10))

side_frame = tk.Frame(main_frame, bg=COLOR_PANEL, padx=10, pady=10)
side_frame.grid(row=0, column=1, sticky="ns")

self.stats_panel = StatsPanel(side_frame)
self.stats_panel.pack(fill="x", pady=(0, 10))

self._create_control_buttons(side_frame)

help_label = tk.Label(
main_frame,
text="Управление: стрелки / WASD. Пробел — всплыть, R — рестарт.",
bg=COLOR_BG, fg=COLOR_TEXT, font=("Arial", 10)
        )
help_label.grid(row=1, column=1, pady=(10, 0), sticky="s")

    def _create_control_buttons(self, parent):
btn_frame = tk.LabelFrame(
            parent, text=" Управление ",
bg=COLOR_PANEL, fg=COLOR_TEXT,
            font=("Arial", 11, "bold"), padx=5, pady=5
        )
btn_frame.pack(fill="x")

btn_style = {
            "width": 4, "height": 2,
            "font": ("Arial", 12, "bold"),
            "bg": "#2a6da8", "fg": "white",
            "activebackground": "#3885c9",
            "relief": "raised", "bd": 2
        }

up_btn = tk.Button(btn_frame, text="▲",
                           command=lambda: self._move("up"), **btn_style)
up_btn.grid(row=0, column=1, padx=2, pady=2)

left_btn = tk.Button(btn_frame, text="◄",
                             command=lambda: self._move("left"), **btn_style)
left_btn.grid(row=1, column=0, padx=2, pady=2)

down_btn = tk.Button(btn_frame, text="▼",
                             command=lambda: self._move("down"), **btn_style)
down_btn.grid(row=1, column=1, padx=2, pady=2)

right_btn = tk.Button(btn_frame, text="►",
                              command=lambda: self._move("right"), **btn_style)
right_btn.grid(row=1, column=2, padx=2, pady=2)

surface_btn = tk.Button(
btn_frame, text="Всплыть",
            command=self._try_surface,
bg="#d97a2b", fg="white",
activebackground="#e89a5c",
            font=("Arial", 10, "bold"),
            relief="raised", bd=2
        )
surface_btn.grid(row=2, column=0, columnspan=3,
                         sticky="ew", padx=2, pady=(8, 2))

    def _bind_keys(self):
self.root.bind("<Up>", lambda e: self._move("up"))
self.root.bind("<Down>", lambda e: self._move("down"))
self.root.bind("<Left>", lambda e: self._move("left"))
self.root.bind("<Right>", lambda e: self._move("right"))

        for key, direction in [("w", "up"), ("s", "down"),
                               ("a", "left"), ("d", "right")]:
self.root.bind(f"<KeyPress-{key}>",
                           lambda e, dr=direction: self._move(dr))
self.root.bind(f"<KeyPress-{key.upper()}>",
                           lambda e, dr=direction: self._move(dr))

self.root.bind("<Key>", self._on_key_press)

self.root.bind("<r>", lambda e: self._restart_level())
self.root.bind("<R>", lambda e: self._restart_level())
self.root.bind("<space>", lambda e: self._try_surface())

    def _on_key_press(self, event):
ch = event.char.lower() if event.char else ""
ru_map = {
            "ц": "up", "ы": "down", "ф": "left", "в": "right",
        }
        if ch in ru_map:
self._move(ru_map[ch])
elifch == "к":  # русская К на месте R
self._restart_level()

    def _start_level(self, level_index):
        if level_index< 0 or level_index>= len(LEVELS):
messagebox.showinfo(
                "Поздравляем!",
f"Вы прошли все уровни игры!\n"
f"Итоговый счёт: {self.score}"
)
            return

self.current_level = level_index
self.game_over = False
self.moves = 0
level_cfg = LEVELS[level_index]

self.world = World(
            cols=GRID_COLS, rows=GRID_ROWS,
obstacles_count=level_cfg["obstacles"],
resources_count=level_cfg["resources"],
mines_count=level_cfg["mines"]
        )
self.world.generate()

start_x, start_y = self.world.start_position
self.bathyscaphe = Bathyscaphe(
            x=start_x, y=start_y,
            oxygen=START_OXYGEN, battery=START_BATTERY
        )

self.renderer = Renderer(self.canvas, self.world, self.bathyscaphe)

self._update_stats()
self.renderer.draw_world()
self.renderer.draw_bathyscaphe()

    def _move(self, direction):
        if self.game_over:
            return

        dx, dy = self._direction_to_delta(direction)
new_x = self.bathyscaphe.x + dx
new_y = self.bathyscaphe.y + dy

        if not self.world.is_inside(new_x, new_y):
self.stats_panel.set_message("Границамира!")
            return

cell_type = self.world.get_cell(new_x, new_y)

        if cell_type == "rock":
self.stats_panel.set_message("Впередискала — непройти.")
            return

self.bathyscaphe.move_to(new_x, new_y)
self.bathyscaphe.oxygen -= OXYGEN_COST
self.bathyscaphe.battery -= BATTERY_COST
self.moves += 1

self._handle_cell(new_x, new_y, cell_type)

self.renderer.draw_world()
self.renderer.draw_bathyscaphe()
self._update_stats()

self._check_game_over()

    @staticmethod
    def _direction_to_delta(direction):
        mapping = {
            "up": (0, -1), "down": (0, 1),
            "left": (-1, 0), "right": (1, 0),
        }
        return mapping.get(direction, (0, 0))

    def _handle_cell(self, x, y, cell_type):
        if cell_type in RESOURCE_SCORES:
            points = RESOURCE_SCORES[cell_type]
self.score += points
self.bathyscaphe.inventory[cell_type] = \
self.bathyscaphe.inventory.get(cell_type, 0) + 1
self.world.set_cell(x, y, "empty")
self.stats_panel.set_message(f"Собранресурс: +{points} очков.")

elifcell_type == "seaweed":
self.bathyscaphe.oxygen -= OXYGEN_COST
self.stats_panel.set_message(
"Водоросли: батискафпотратилбольшекислорода."
)

elifcell_type == "mine":
            penalty = OBSTACLE_PENALTIES["mine"]
self.score = max(0, self.score + penalty)
self.bathyscaphe.battery -= 20
self.world.set_cell(x, y, "empty")
self.stats_panel.set_message(
"Столкновениесминой! Повреждение корпуса."
)

elifcell_type == "oxygen_station":
self.bathyscaphe.oxygen = min(
                START_OXYGEN, self.bathyscaphe.oxygen + 40
            )
self.world.set_cell(x, y, "empty")
            self.stats_panel.set_message(
"Кислородная станция: запас восполнен."
)

    def _check_game_over(self):
if self.bathyscaphe.oxygen<= 0:
self.game_over = True
messagebox.showwarning(
                "Конец миссии",
                "Кислород закончился. Батискаф не смог вернуться."
)
elifself.bathyscaphe.battery<= 0:
self.game_over = True
messagebox.showwarning(
"Конец миссии",
                "Батарея разряжена. Батискаф потерял управление."
)

    def _try_surface(self):
        if self.game_over:
            return

current_type = self.world.get_cell(
self.bathyscaphe.x, self.bathyscaphe.y
        )
        if current_type == "surface":
            bonus = int(self.bathyscaphe.oxygen * 0.2 +
self.bathyscaphe.battery * 0.2)
self.score += bonus
messagebox.showinfo(
                "Уровеньпройден",
                f"Батискафуспешновсплыл.\n"
f"Бонус за ресурсы: +{bonus} очков.\n"
f"Общий счёт: {self.score}"
)
self._start_level(self.current_level + 1)
        else:
self.stats_panel.set_message(
"Всплыть можно только из точки подъёма."
)

    def _new_game(self):
self.score = 0
self._start_level(0)

    def _restart_level(self):
self._start_level(self.current_level)

    def _update_stats(self):
self.stats_panel.update_values(
            level=self.current_level + 1,
level_name=LEVELS[self.current_level]["name"],
            score=self.score,
            moves=self.moves,
            oxygen=max(0, self.bathyscaphe.oxygen),
            battery=max(0, self.bathyscaphe.battery),
            inventory=self.bathyscaphe.inventory
        )

    def _save_result(self):
        data = {
            "level": self.current_level + 1,
            "score": self.score,
            "moves": self.moves,
            "inventory": self.bathyscaphe.inventory,
        }
        try:
            with open("result.json", "w", encoding="utf-8") as fp:
json.dump(data, fp, ensure_ascii=False, indent=2)
messagebox.showinfo(
                "Сохранено",
f"Результат записан в файл:\n"
f"{os.path.abspath('result.json')}"
            )
        except OSError as exc:
messagebox.showerror("Ошибка", f"Неудалосьсохранить: {exc}")

    @staticmethod
    def _show_rules():
        rules = (
"Правилаигры 'Батискаф':\n\n"
"1. Батискаф перемещается по подводному миру, "
            "разделённому на клетки.\n"
            "2. Нужно собирать ресурсы: кристаллы, жемчуг, золото.\n"
            "3. Следите за уровнем кислорода и заряда батареи.\n"
            "4. Избегайте мин — они повреждают корпус.\n"
            "5. Скалы непроходимы, их нужно обходить.\n"
            "6. Водоросли проходимы, но расходуют больше кислорода.\n"
            "7. Для завершения уровня найдите точку подъёма "
            "и нажмите 'Всплыть'."
        )
messagebox.showinfo("Правила", rules)

@staticmethod
def _show_about():
about = (
"Управляемая модель исполнителя 'Батискаф'\n\n"
            "Курсовая работа по дисциплине МДК 01.01\n"
            "Разработка программных модулей\n\n"
            "Среда разработки: PyCharm\n"
            "Язык программирования: Python 3.11\n"
            "Графическая библиотека: Tkinter\n\n"
            "Версия программы: 1.0"
        )
messagebox.showinfo("О программе", about)


def main():
    root = tk.Tk()
    app = BathyscapheApp(root)
root.mainloop()


if __name__ == "__main__":
main()