убери конец игры, чтобы алгоритм продолжал решать игру: import tkinter as tk
from tkinter import messagebox
import copy

# Размеры сеток
MAIN_GRID_SIZE = 9  # Размер основной сетки
BLOCK_GRID_SIZE = 5  # Размер блока
CELL_SIZE = 30  # Размер ячеек в пикселях

# Пример основного поля с уже заполненными ячейками (1 - занята, 0 - свободна)
MAIN_GRID = [
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0]
]

# Пример блоков (каждый блок представлен как список координат)
BLOCKS = [
    [],  # Блок 1
    [],  # Блок 2
    []   # Блок 3
]

class BlockudokuSolver:
    def __init__(self, main_grid, blocks, update_callback):
        self.main_grid = main_grid
        self.blocks = blocks  # Список блоков, каждый блок - список координат (x, y)
        self.update_callback = update_callback  # Функция для обновления поля
        self.current_block_index = 0  # Индекс текущего блока, который будем пытаться разместить

    def next_step(self):
        # Попытаться разместить следующий блок
        if self.current_block_index >= len(self.blocks):
            return False  # Если все блоки размещены, выходим

        block = self.blocks[self.current_block_index]
        placed = False
        for y in range(MAIN_GRID_SIZE):
            for x in range(MAIN_GRID_SIZE):
                if self.can_place(block, x, y):
                    self.place_block(block, x, y)
                    self.update_callback()  # Обновляем отображение после размещения блока
                    self.current_block_index += 1  # Переходим к следующему блоку
                    placed = True
                    return True  # Разместили блок, ожидаем следующий шаг
        return False  # Не удалось разместить текущий блок

    def can_place(self, block, x_offset, y_offset):
        # Проверка возможности размещения блока на сетке
        for x, y in block:
            x_new = x + x_offset
            y_new = y + y_offset
            if x_new < 0 or y_new < 0 or x_new >= MAIN_GRID_SIZE or y_new >= MAIN_GRID_SIZE:
                return False
            if self.main_grid[y_new][x_new] != 0:
                return False
        return True

    def place_block(self, block, x_offset, y_offset):
        # Размещение блока на сетке
        for x, y in block:
            self.main_grid[y + y_offset][x + x_offset] = 1

class BlockudokuApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Blockudoku")

        # Основная сетка, которую можно отредактировать
        self.main_grid = copy.deepcopy(MAIN_GRID)
        self.main_canvas = tk.Canvas(root, width=MAIN_GRID_SIZE*CELL_SIZE, height=MAIN_GRID_SIZE*CELL_SIZE, bg="white")
        self.main_canvas.grid(row=0, column=0, padx=10, pady=10)
        self.draw_grid(self.main_canvas, MAIN_GRID_SIZE, MAIN_GRID_SIZE)
        self.update_main_canvas()

        # Нижняя сетка для рисования блоков
        self.blocks = copy.deepcopy(BLOCKS)  # Используем пример блоков
        self.block_canvases = []
        for i in range(len(self.blocks)):
            frame = tk.Frame(root)
            frame.grid(row=1, column=i, padx=5, pady=5)
            label = tk.Label(frame, text=f"Блок {i+1}")
            label.pack()
            canvas = tk.Canvas(frame, width=BLOCK_GRID_SIZE*CELL_SIZE, height=BLOCK_GRID_SIZE*CELL_SIZE, bg="lightgrey")
            canvas.pack()
            self.draw_grid(canvas, BLOCK_GRID_SIZE, BLOCK_GRID_SIZE)
            # Исправление: передача текущего индекса блока в lambda через аргумент по умолчанию
            canvas.bind("<Button-1>", lambda event, idx=i: self.toggle_block_cell(idx, event))
            self.block_canvases.append(canvas)

        # Кнопка "Шаг"
        self.step_button = tk.Button(root, text="Следующий шаг", command=self.step)
        self.step_button.grid(row=2, column=0, columnspan=len(self.blocks), pady=10)

        # Стартовое состояние для алгоритма
        self.solver = None

    def draw_grid(self, canvas, rows, cols):
        for i in range(rows + 1):
            canvas.create_line(0, i * CELL_SIZE, cols * CELL_SIZE, i * CELL_SIZE)
        for j in range(cols + 1):
            canvas.create_line(j * CELL_SIZE, 0, j * CELL_SIZE, rows * CELL_SIZE)

    def toggle_block_cell(self, block_idx, event):
        # Изменить состояние клетки в блоке
        x = event.x // CELL_SIZE
        y = event.y // CELL_SIZE
        if 0 <= x < BLOCK_GRID_SIZE and 0 <= y < BLOCK_GRID_SIZE:
            # Найдем, находится ли эта ячейка в блоке
            coords = self.blocks[block_idx]
            if (x, y) in coords:
                coords.remove((x, y))  # Убираем клетку, если она была занята
            else:
                coords.append((x, y))  # Добавляем клетку в блок
            self.redraw_block(block_idx)

    def redraw_block(self, block_idx):
        # Перерисовываем блок
        canvas = self.block_canvases[block_idx]
        canvas.delete("all")
        self.draw_grid(canvas, BLOCK_GRID_SIZE, BLOCK_GRID_SIZE)
        coords = self.blocks[block_idx]
        for x, y in coords:
            canvas.create_rectangle(
                x*CELL_SIZE, y*CELL_SIZE,
                (x+1)*CELL_SIZE, (y+1)*CELL_SIZE,
                fill="black",
                outline=""
            )

    def start_solver(self):
        blocks_coords = self.get_blocks_coordinates()
        if not blocks_coords:
            messagebox.showwarning("Предупреждение", "Нарисуйте хотя бы один блок.")
            return False
        self.solver = BlockudokuSolver(self.main_grid, blocks_coords, self.update_main_canvas)
        return True

    def step(self):
        if not self.solver:
            started = self.start_solver()
            if not started:
                return

        if not self.solver.next_step():
            messagebox.showinfo("Конец игры", "Все блоки размещены или не удается разместить больше блоков.")
            self.step_button.config(state="disabled")  # Отключаем кнопку после завершения
        else:
            self.update_main_canvas()

    def update_main_canvas(self):
        self.main_canvas.delete("all")
        self.draw_grid(self.main_canvas, MAIN_GRID_SIZE, MAIN_GRID_SIZE)
        for y in range(MAIN_GRID_SIZE):
            for x in range(MAIN_GRID_SIZE):
                if self.main_grid[y][x]:
                    self.main_canvas.create_rectangle(
                        x*CELL_SIZE, y*CELL_SIZE,
                        (x+1)*CELL_SIZE, (y+1)*CELL_SIZE,
                        fill="black"
                    )

    def get_blocks_coordinates(self):
        # Получаем координаты всех активированных блоков
        blocks_coords = []
        for block in self.blocks:
            # Удаляем дублирующиеся координаты и сортируем
            unique_block = list(set(block))
            unique_block.sort()
            if unique_block:
                blocks_coords.append(unique_block)
        return blocks_coords

if __name__ == "__main__":
    root = tk.Tk()
    app = BlockudokuApp(root)
    root.mainloop()