При разработке игровых механик, тестов или интерактивных панелей в 1С часто возникает задача перемешать элементы на форме в случайном порядке. Например, у нас есть несколько декораций с изображениями (самолет, волк, луна), и мы хотим, чтобы при нажатии кнопки их расположение менялось. Рассмотрим, как правильно реализовать этот алгоритм, избежав типичных ошибок начинающих разработчиков.
Часто программисты пытаются создать массив, в который помещают сами элементы формы (например, Элементы.Декорация1, Элементы.Декорация2), затем перемешивают этот массив и ожидают, что картинки на экране поменяются местами. Проанализируем ситуацию: массив — это просто список ссылок в памяти. Когда мы меняем порядок элементов в массиве, мы никак не воздействуем на свойства самих объектов формы. Каждая декорация остается привязанной к своему месту в иерархии формы и сохраняет свою картинку.
Чтобы визуально изменить порядок, нам нужно либо менять местами свойства этих элементов (например, переназначать путь к картинке), либо программно изменять их положение в контейнере. Разберем по шагам наиболее эффективные способы решения.
Этот метод основан на использовании объекта СписокЗначений и встроенной функции сортировки. Суть заключается в том, чтобы присвоить каждому элементу случайное число в качестве "представления" и выполнить сортировку по этому полю.
Рассмотрим пример кода, который выполняет перемешивание данных:
// 1. Формируем исходный массив картинок (адреса во временном хранилище или имена из библиотеки)
МассивКартинок = Новый Массив;
МассивКартинок.Добавить(БиблиотекаКартинок.Самолет);
МассивКартинок.Добавить(БиблиотекаКартинок.Волк);
МассивКартинок.Добавить(БиблиотекаКартинок.Луна);
МассивКартинок.Добавить(БиблиотекаКартинок.Червь);
// 2. Используем Генератор случайных чисел
ГСЧ = Новый ГенераторСлучайныхЧисел;
СписокДляПеремешивания = Новый СписокЗначений;
// 3. Заполняем список значениями и присваиваем случайные представления
Для Каждого Картинка Из МассивКартинок Цикл
СлучайныйВес = ГСЧ.СлучайноеЧисло(0, 99999);
// Форматируем число в строку с ведущими нулями для корректной сортировки
Представление = Формат(СлучайныйВес, "ЧЦ=5; ЧН=; ЧВН=; ЧГ=");
СписокДляПеремешивания.Добавить(Картинка, Представление);
КонецЦикла;
// 4. Сортируем список по представлению (случайному числу)
СписокДляПеремешивания.СортироватьПоПредставлению();
// 5. Выгружаем перемешанные данные обратно в массив
МассивКартинок = СписокДляПеремешивания.ВыгрузитьЗначения();
После выполнения этого кода в переменной МассивКартинок значения будут стоять в случайном порядке. Теперь нам остается только присвоить их элементам формы:
Элементы.Декорация1.Картинка = МассивКартинок[0];
Элементы.Декорация2.Kartinka = МассивКартинок[1];
// и так далее для всех элементов
Если нам нужно перемешивать большие объемы данных или мы хотим написать более "чистый" код без использования вспомогательных объектов типа СписокЗначений, стоит применить классический алгоритм Фишера — Йетса. Проанализируем его логику: мы проходим по массиву с конца к началу и меняем текущий элемент местами со случайным элементом, стоящим перед ним.
ГСЧ = Новый ГенераторСлучайныхЧисел;
К = МассивКартинок.Количество();
Пока К > 1 Цикл
К = К - 1;
ИндексСлучайный = ГСЧ.СлучайноеЧисло(0, К);
// Меняем элементы местами
ВременноеЗначение = МассивКартинок[ИндексСлучайный];
МассивКартинок[ИндексСлучайный] = МассивКартинок[К];
МассивКартинок[К] = ВременноеЗначение;
КонецЦикла;
Важный момент: при инициализации ГенераторСлучайныхЧисел в современных версиях платформы 8.3 не обязательно указывать "начальное число" (seed), так как платформа автоматически инициализирует его на основе системного времени.
Выясним причину, по которой иногда картинки не отображаются при программной установке. Если вы планируете загружать изображения по URL-адресу, как упоминалось в обсуждении, процедура усложняется. Напрямую присвоить URL свойству Картинка нельзя.
Выполним следующие шаги для работы с внешними изображениями:
HTTPСоединение для получения двоичных данных картинки.ПоместитьВоВременноеХранилище().Картинка декорации или полю формы.Рассмотрим пример загрузки:
Соединение = Новый HTTPСоединение("mysite.com");
Запрос = Новый HTTPЗапрос("/images/pic1.png");
Ответ = Соединение.Получить(Запрос);
Если Ответ.КодСостояния = 200 Тогда
ДанныеКартинки = Ответ.ПолучитьТелоКакДвоичныеДанные();
АдресХранилища = ПоместитьВоВременноеХранилище(ДанныеКартинки, ЭтаФорма.УникальныйИдентификатор);
Элементы.Декорация1.Картинка = АдресХранилища;
КонецЕсли;
Если картинок много (например, 10 или более), рисовать каждую декорацию в конфигураторе неудобно. Рассмотрим, как программно создать нужное количество элементов и сразу заполнить их перемешанными данными. Это позволит избежать громоздких конструкций типа Элементы.Декорация2, Элементы.Декорация3 и т.д.
// Предположим, у нас есть МассивКартинок (уже перемешанный)
Для Индекс = 0 По МассивКартинок.Количество() - 1 Цикл
ИмяЭлемента = "ДинамическаяКартинка_" + Индекс;
// Проверяем, не создан ли элемент ранее
НовыйЭлемент = Элементы.Найти(ИмяЭлемента);
Если НовыйЭлемент = Неопределено Тогда
// Добавляем новую декорацию в группу "ГруппаКартинок"
НовыйЭлемент = Элементы.Добавить(ИмяЭлемента, Тип("ДекорацияФормы"), Элементы.ГруппаКартинок);
НовыйЭлемент.Вид = ВидДекорацииФормы.Картинка;
КонецЕсли;
// Устанавливаем картинку из перемешанного массива
НовыйЭлемент.Картинка = МассивКартинок[Индекс];
КонецЦикла;
Подведем итог: для реализации рандома на форме 1С недостаточно просто перемешать массив элементов формы. Необходимо перемешать источники данных (адреса картинок или сами объекты картинок) с помощью ГенераторСлучайныхЧисел и СписокЗначений (или алгоритма Фишера-Йетса), а затем в цикле обновить свойства Картинка у соответствующих элементов формы.