@ireader

Как сгенерировать наиболее разнообразные комбинаций из элементов заданного набора множеств?

Задача на генерацию спрайтов для формирования ландшафтного набора тайлов (tileset).

Дано некоторое количество базовых спрайтов, которые распределены по нескольким слоям. Для генерации одного тайла нам нужно взять по одному любому спрайту из каждого слоя и последовательно наложить их друг на друга. 

Например:
1 слой: Море/Берег/Суша
2 слой: Скалы
3 слой: Вершина/плоскогорье
4 слой: Трава
5 слой: Декоративные элементы

Количество спрайтов в каждом слое произвольно, но может быть только в пределах [1..16]
Кол-во слоёв также произвольно, но в пределах [1..6]

Нужно получить 16 или меньше (если больше сгенерировать невозможно) уникальных тайлов, состоящих, из как можно более разнообразных комбинаций исходных спрайтов - т.е. чем меньше они или их комбинации будут повторяться  для разный тайлов, тем лучше. 

Пример:
spoiler

для 
{{0, 1, 2}, - слой 1
 {0, 1, 2}, - слой 2
 {0, 1, 2}} - слой 3

Результат  будет примерно таким:
0 0 0
1 1 1
2 2 2
0 1 2
1 2 0
2 0 1
0 2 1
1 0 2
2 1 0
0 0 1
1 1 2
2 2 0
0 1 0
1 2 1
2 0 2
0 0 2

Мне представляется 2 хода решения этой задачи:

1. Каждый слой, по сути, представляет собой одномерное множество. Для получения всех возможных комбинаций нам достаточно выполнить прямое(декартово) произведение этих множеств. И отсортировать получившиеся в результате множества по "разнообразию". 
Но в этом случае есть 2 сложности:
  1. Комбинаций может быть довольно много (нам же надо только 16 из них).
  2. Сравнивать не только сами множества между собой но ещё и с уже отобранными, на предмет частоты повторения входящих в них комбинаций.

2. Сразу генерировать максимально разнообразные комбинации.

Вынужден признать, что я застрял на обоих вариантах - в первом на алгоритме сортировки, во втором на алгоритме генерации. Прошу помощи или подсказки.
  • Вопрос задан
  • 133 просмотра
Решения вопроса 1
AgentSmith
@AgentSmith
Это мой правильный ответ на твой вопрос
Вот хорошая старая статья на эту тему https://habr.com/ru/post/117160/
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Мне видится вот такой алгоритм:

Во-первых, если всего спрайтов можно сгенерировать меньше 16, то просто генерируйте все.

Далее будем генерировать сразу все 16 спрайтов. Текущие спрайты будут иметь первые K слоев заполнеными и сгруппированы в отрезки по совпадению. Далее для каждого отрезка длины L, если L больше количества вариантов в текущем слое (N), то разбивайте отрезко на N примерно одинаковых по длине кусков. Все куски будут длины floor(L/N) и L%N из них будут на 1 длиннее. Если L < N, то выбирайте случайно L спрайтов в текущем слое и получайте кучу отрезков длины 1.

Для пущей случайности можно слои перемешать перед генерацией и обрабатывать их в случайном порядке.
Ответ написан
Комментировать
Alexandroppolus
@Alexandroppolus
кодир
Рандомно перемешать каждый из массивов - https://qna.habr.com/q/1118198
после чего брать комбинации: (a[0], b[0], ..., f[0]), (a[1], b[1], ..., f[1]), ...
где a, b.. - слои

если, допустим, надо N тайлов, а в слое всего M вариантов, где M < N, то из этого слоя (перемешанного) можно брать' элемент с индексом (i % M)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы