Упрощенная генерация провинций

Мне нужно умное и довольно простое решение моей проблемы - генерация формы провинции. Предположим, что эта карта является матрицей NxM. Каждая ячейка представлена ​​натуральным числом. 0 означает, что плитка не принадлежит ни к одной провинции. цифры 1 означают, что она принадлежит провинции № 1, № 2 означает, что ячейка принадлежит провинции № 2... и т. д.

Рассмотрим эту карту размером 4x4:

0000
0000
0000
0000

Эта карта представляет собой 16 плиток, которые не принадлежат ни одной провинции.

Это карта, содержащая 1 провинцию:

0010
0111
0100
0000

это провинция размером 5 и id = 1. У нее нет соседей.

Рассмотрим 3 провинции:

1133
2100
2200
2000

Таким образом, провинция 1 является соседом 2 и 3. Провинция 3 является только соседом 1, а провинция 2 является только соседом 1. Также есть 7 не связанных тайлов.

Моя проблема: я хочу сгенерировать k провинций на карте NxN. Также есть несколько простых правил:

  • есть максимальный размер провинции и минимальный размер провинции (например, минимум = 2, максимум = 10)
  • все тайлы провинции должны быть соединены (по вертикали или горизонтали, но не по углам)

Пример неверной провинции (она не подключена):

1100
0000
0011
0000
  • не должно быть анклавов (провинция внутри провинции)
  • формы должны быть случайными

Я пытался реализовать это с помощью модификации заливки, но у нее есть некоторые недостатки. Я буду рад услышать некоторые идеи или любую помощь. Карта может быть 300x300 с 200 или более провинциями, так что это также должен быть какой-то хитрый алгоритм.


person dfens    schedule 01.11.2010    source источник


Ответы (3)


Использование диаграмм Вороного

Я думаю, что этот не будет генерировать все возможные карты, но сделает с наиболее "разумными".

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

Алгоритм:

1) Выберите набор случайных точек, превышающий или равный желаемому количеству провинций. Если вы сгенерируете больше, чем нужно, вы гарантированно получите пустые места.

альтернативный текст

2) Запускаем алгоритм Вороного (можно описать, если интересно, но легко найти в сети)

альтернативный текст

3) Вычислить площади полученных многоугольников

4) Убедитесь, что у вас достаточно площадей с поверхностью > (минимальная желаемая площадь). Если нет, перейдите к 1

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

6) Проверьте, имеют ли ваши полигоны площадь ‹ (максимальная площадь). Если нет, то вы должны уменьшить их.

7) Уменьшить площадь каждого полигона

  • While area > (max area)
    • Find Polygon boundary
    • Удалить случайную точку с границы полигона

Кстати, я написал эту программу на Mathematica, чтобы получить графики выше:

 Clear["Global`*"];
 Needs["ComputationalGeometry`"];
 data2D = Table[{RandomReal[16], RandomReal[16]}, {10}]
 convexhull = ConvexHull[data2D]
 (delval = DelaunayTriangulation[data2D]) // Shallow[#, {5, 6}] &
 b1 = {{0, 0}, {16, 0}, {16, 16}, {0, 16}};
 {diagvert1, diagval1} = BoundedDiagram[b1, data2D, delval, convexhull];
 Show[{Graphics[Join[{PointSize[Large]}, {Point@data2D}], Frame -> True]}]
 Show[{Graphics@Point[data2D],   DiagramPlot[data2D, diagvert1, diagval1]}]

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

Примечание: В описании алгоритма не упоминается, что ваши области состоят из квадратов...

ХТН

person Dr. belisarius    schedule 01.11.2010
comment
Я думаю, что это сгенерирует все возможные провинции, если вы сгенерируете все возможные позиции n точек, где n — количество провинций (включая пустые провинции), которые вы хотите. Хотя насчет поколения Вороных я не уверен. - person Brian Stinar; 01.11.2010
comment
@ Брайан Стинар Я думаю, что это больше с практической, чем с теоретической стороны. Поскольку эта штука может создавать очень большое количество конфигураций, напоминающих настоящую карту, я уверен, что ее можно использовать по назначению. Однако я предпочитаю ничего не претендовать на полноту. ;) - person Dr. belisarius; 02.11.2010

У меня мало времени, но есть хорошая идея: добавить провинцию сначала слева направо, а затем справа налево. Нравиться

 1111222
 3333322
 3344555        
 0000665

Я написал случайные числа.. это правильно?

void insert(Matrix matrix){
    lastProvince=0;
    missingProvince=MIN;
    if(matrix.dimensio<MIN*K) throw new RuntimeException("Matrix too small");
    for(y=0;y<matrix.height;y++){
        if(y%2==0){
            for(x=0;x<matrix.width;x++){
                matrix[x][y]=lastProvince;
                missingProvince--;
                if(missingProvince==0) {
                    lastProvince++;
                    missingProvince=MIN;
                }
                if(lastProvince==k) return;
            }
        }else{
            for(x=matrix.width;x>=0;x--){// is -- not ++
                matrix[x][y]=lastProvince;
                missingProvince--;
                if(missingProvince==0) {
                    lastProvince++;
                    missingProvince=MIN;
                }
                if(lastProvince==k) return;
            }
         }
   }
}

Не проверено, но это идея ..

person fabiofili2pi    schedule 01.11.2010
comment
Но вы должны генерировать все типы провинций? - person fabiofili2pi; 01.11.2010
comment
все должно быть возможно. но в любом случае это очень хороший ответ, +1. Я подожду других ответов, и если не будет новых, я приму это. - person dfens; 01.11.2010
comment
Может быть, вы можете лучше объяснить в вопросе, что вы должны сгенерировать все возможные типы провинций, но как вы могли это сделать? Может быть, вы должны лучше объяснить, почему вы должны это сделать =) - person fabiofili2pi; 01.11.2010

Просто у меня в голове:

  1. Создайте «начальное число» для каждой нужной вам провинции. У вас есть NxM карта и L провинций, просто сгенерируйте L уникальных случайных чисел в диапазоне [0-(N*M-1)]. координаты X,Y вашего семени с номером P равны P/M и P%M.
  2. Пока все ваши провинции не будут больше минимального размера и меньше максимального размера:

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

    б. Добавьте в эту провинцию случайную соседнюю ячейку, которая не является частью какой-либо провинции.

Есть небольшой шанс анклавов с этой техникой, но он очень низок. Вы можете улучшить шаг b, чтобы проверить их и не увеличивать, если рост создаст их.

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

person jilles de wit    schedule 01.11.2010
comment
что, если провинция меньше MIN и окружена другой провинцией? - person fabiofili2pi; 01.11.2010
comment
Отнять кусок у самого крупного соседа? Или вы можете сначала зациклить неслучайно все семена провинций, пока все провинции не будут иметь размер не менее MIN. - person jilles de wit; 01.11.2010