Как реализовать игру «Сапер» на управляемых формах 1С и исправить ошибки динамического создания элементов

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Реализация игровых механик на платформе 1С:Предприятие — это отличный способ отточить навыки работы с динамическим программным интерфейсом. В данной статье мы разберем процесс создания игры «Сапер», проанализируем типичные ошибки при работе с коллекцией элементов формы и рассмотрим способы оптимизации алгоритмов обхода игрового поля.

Разбор архитектуры решения

Для создания игры нам необходимо программно сгенерировать сетку ячеек. В представленном коде используется подход с созданием групп (колонок) и декораций (ячеек) внутри них. Рассмотрим основной цикл создания поля, который инициируется процедурой НачатьИгру. Проанализируем, как происходит добавление элементов в цикле:


&НаКлиенте
Процедура СоздатьИгровоеПоле()
    Для НомерКолонки = 1 по Объект.ШиринаИгровогоПоля цикл
        Колонка = НоваяКолонка(НомерКолонки);
        Для НомерСтроки = 1 по Объект.ВысотаИгровогоПоля цикл
            ДобавитьЯчейку(НомерКолонки, НомерСтроки, Колонка);
            // Далее идет работа с контекстным меню
        КонецЦикла;
    КонецЦикла;
КонецПроцедуры

Процедура НоваяКолонка создает вертикальную группу, а ДобавитьЯчейку создает декорацию типа Картинка. Важно отметить, что каждой ячейке назначается действие УстановитьДействие("Нажатие", "ОткрытьЯчейку"), что позволяет обрабатывать клики пользователя единым обработчиком.

Исправление критической ошибки с контекстным меню

Разберем ситуацию, на которую обратили внимание участники обсуждения. При попытке динамически добавить пункты в контекстное меню создаваемого элемента возникла ошибка. В исходном коде использовалась конструкция:


ПунктМеню = Элементы.Добавить("Пункт2_"+ИмяЭлемента, Тип("КнопкаФормы"), Элементы.КонтекстноеМеню);

Выясним причину ошибки: в управляемом интерфейсе 1С у самой формы (доступной через коллекцию Элементы) нет общего свойства КонтекстноеМеню. Контекстное меню принадлежит конкретному элементу управления. Поэтому при попытке обращения к Элементы.КонтекстноеМеню система выдает ошибку, так как такого объекта не существует.

Правильное решение: необходимо обращаться к контекстному меню того самого элемента, который мы только что создали или нашли. Рассмотрим исправленный вариант кода:


// Находим созданный элемент (ячейку)
ЭлементЯчейка = Элементы.Найти(ИмяЭлемента);

// Добавляем пункт именно в контекстное меню этого элемента
ПунктМеню = Элементы.Добавить("Пункт2_" + ИмяЭлемента, Тип("КнопкаФормы"), ЭлементЯчейка.КонтекстноеМеню);
ПунктМеню.ИмяКоманды = "УбратьФлажок";

Таким образом, мы четко указываем родителем кнопки меню свойство КонтекстноеМеню конкретной декорации.

Алгоритм расстановки мин и расчет цифр

После создания визуальных элементов необходимо наполнить их логикой. Проанализируем процедуру ЗаполнитьПолеМинами. Здесь используется объект ГенераторСлучайныхЧисел. Важно следить, чтобы мины не устанавливались дважды в одну и ту же клетку, для этого в коде предусмотрена проверка свойства Заголовок.

Однако хранение информации о мине в заголовке декорации — не самое безопасное решение, так как опытный пользователь может программно прочитать эти значения. Рассмотрим, как рассчитывается количество мин вокруг ячейки в функции КоличествоМин:


Функция КоличествоМин(НомерСтроки, НомерКолонки)
    Результат = 0;
    Для Шаг = 1 По 8 Цикл
        // Формируем имя соседней ячейки (все 8 направлений)
        // ... (логика вычисления координат соседних ячеек)
        СоседнийЭлемент = Элементы.Найти(ИмяЭлемента);
        Если СоседнийЭлемент <> Неопределено и СоседнийЭлемент.Заголовок = "ЭтоМина" Тогда
            Результат = Результат + 1;
        КонецЕсли;
    КонецЦикла;
    Возврат Результат;
КонецФункции

Этот метод проверяет все 8 соседних координат. Обратите внимание на использование Элементы.Найти. Если индекс выходит за границы поля, метод вернет Неопределено, что позволяет избежать ошибок обращения к несуществующим объектам.

Оптимизация: рекурсивное открытие пустых ячеек

Одной из самых интересных задач в «Сапере» является автоматическое открытие всех соседних пустых ячеек при клике на клетку с нулем. В коде это реализовано через процедуру ОткрытьСоседниеЯчейки. Рассмотрим ее механизм:

  1. Программа получает координаты текущей ячейки через парсинг ее имени: СРЕД(Элемент.Имя, 8).
  2. Запускается цикл по 8 соседним клеткам.
  3. Для каждой соседней клетки проверяется условие: она не является миной и еще не открыта (Гиперссылка = Истина).
  4. Если соседняя ячейка тоже содержит "0", процедура вызывает саму себя рекурсивно.

Важное предостережение: использование рекурсии в 1С имеет ограничения по глубине стека. На игровых полях большого размера (например, 50x50) глубокая рекурсия может привести к аварийному завершению работы. В таких случаях мы рекомендуем использовать алгоритм на основе массива (стека), где координаты ячеек для проверки добавляются в список, а цикл выполняется, пока список не пуст.

Рекомендации по улучшению производительности

Проанализируем производительность интерфейса. Создание сотен декораций на форме (например, 30x30 = 900 элементов) значительно замедляет отрисовку управляемой формы. Для профессиональной реализации игр на 1С лучше использовать следующие подходы:

Подводя итог, отметим, что ключевым моментом в исправлении кода автора было понимание структуры объектной модели формы. Всегда проверяйте, какому именно объекту принадлежит свойство или коллекция, к которой вы обращаетесь.

← На главную