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


18

У меня есть боты в прямоугольной формации с рядами и столбцами. Проблема возникает, когда бот добавляется или удаляется из пласта. Когда это происходит, боты должны перестроиться так, чтобы прямоугольная формация была примерно такой же пропорции и была настолько прямоугольной, насколько это возможно. Как это сделать?

Некоторые идеи:

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

  • Когда бот удален, переместите бот, который был позади него, на свое место и продолжайте, пока не дойдете до конца формирования. Затем выровняйте задний ранг как можно больше, перетасовав ботов в задний ранг.

  • Другая идея, которая совершенно отличается, состоит в том, чтобы подражать тому, как структуры молекул остаются вместе. Сделайте так, чтобы каждый бот был окружен четырьмя другими ботами, привлекая четырех ближайших ботов и отталкивая остальных. Отбросьте все боты (включая четырех), которые находятся слишком близко, чтобы обеспечить разделение, используя закон обратных квадратов. Вам также понадобится дополнительная сила для формирования всей структуры. Но это звучит очень вычислительно дорого.

ОБНОВЛЕНИЕ : Итак, изучая ответ Сарама, я придумал хорошую общую функцию, которая дает хорошие размеры.

Сначала я решил приведенное ниже уравнение для ширины и высоты, а затем округлил ответы.

width/height=aspect ratio of your choice
width*height=number of bots

Это дает вам ближайший целочисленный прямоугольник к этому соотношению сторон для вашего количества ботов. Ближайший прямоугольник будет в половине случаев слишком большим, а в половине - слишком маленьким (конечно, иногда это будет правильно, но кого это волнует). В тех случаях , когда прямоугольник представляет собой немного слишком большим, ничто не должно быть сделано. Задний ранг в итоге будет почти полным, что идеально. В тех случаях , когда прямоугольник представляет собой немного слишком мал, у вас есть проблемы , потому что маленькие крошечные переполнения придется идти в свой собственный ранг создал ранг лишь несколько ботов на нем, который не выглядит красиво. Есть также случаи, когда разница велика(больше, чем половина ширины), в этом случае добавьте или вычтите один ранг, чтобы уменьшить разницу. Затем, когда прямоугольник слишком мал, добавьте один столбец, чтобы сделать его чуть больше. После этого похоже, что у бэк-ранга всегда будет как минимум вдвое меньше ботов, чем у других.

ОБНОВИТЬ

Как только вы получили размеры, сравните их с текущими размерами. Если фасад нового измерения больше, для каждого ранга выведите попсовых ботов с ранга ниже и подталкивайте их на текущий ранг до тех пор, пока число ботов этого ранга не станет равным фронтажу. Продолжайте этот алгоритм, пока не доберетесь до заднего ранга. Используя этот алгоритм, боты будут эффективно вписываться в новое измерение. После этого я просто толкаю нового старого на задний план. Алгоритм немного отличается для случаев, когда новый фронт меньше, но вы можете это выяснить!

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


Какое максимальное количество ботов в единице? Если он относительно небольшой, вы можете жестко указать, сколько строк и столбцов имеет формация для определенного количества ботов.
Exilyth

3
Можете ли вы опубликовать изображение образований, которые действительны против недействительных? У меня небольшие проблемы с пониманием того, что вы ищете. Разрешены ли неполные строки / столбцы?
MichaelHouse

3
Вы понимаете, что это не будет работать для простых чисел? например, с 7 ботами, вам нужно было бы сделать блок 3х2 с одним ботом сзади.
Exilyth

1
Ну, это неудобно. Я полностью забыл о простых числах. Тогда, возможно, следующая лучшая вещь будет состоять в том, чтобы разрешить только те строки и столбцы, которые заполнены ПОЧТИ. Один бот подряд не выглядит правильно, но один бот меньше подряд не будет выглядеть плохо.
Tiby312

3
Простые числа не единственные, которые могут вызвать проблемы - выбор размера пласта с помощью факторинга может привести к неоправданно длинным и худым пластам. Например, если у вас есть 14 ботов, единственное идеальное прямоугольное образование - 7x2, в то время как лучше было бы иметь образование 3x4 с дополнительным рядом из 2 ботов.
Натан Рид

Ответы:


16

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

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

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

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

Если я правильно понял, что вы ищете «военное» впечатление, и ваши бот-организации выглядят как фаланги, я считаю, что эта упорядоченная перестановка - лучший способ достичь этой цели.

Обновление .
Один из простых способов управления задним рядом состоит в том, чтобы разделить отряды заднего ряда на три отряда: по одному на каждом фланге и один в центре. В зависимости от того, является ли фронт четным или нечетным, а также от того, совпадает ли число блоков в задней строке с 0,1 или 2 модулями 3, существует ровно шесть вариантов управления.

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

Обновление № 2 :
дополнительная мысль о глубине пласта. Удар залпового огня в сочетании с современным штыком сделал глубину 3 или 4 достаточной в конце 18-го и начале 19-го века. (Британцы редко сражались в 2 рядах, вопреки распространенному мнению, до конца битвы; с одной стороны, они делали свои линии слишком длинными, чтобы быстро образовать квадрат.) До этого было обычным иметь большую глубину, возможно, до 8 или 10 для греческой фаланги с Сариссой. Выберите глубину, которая создает впечатление, которое вы хотите.

В реальной жизни армии стараются поддерживать фронт отрядов как можно дольше, за счет увеличения хрупкости отрядов, поскольку это упрощает раскладку поля битвы. Цезарь в Фарсале преднамеренно уменьшил глубину своего отряда, чтобы увеличить фронт, чтобы он соответствовал силе Помпея. Как говорится в цитате: «Мы выигрываем или умираем сегодня; у людей Помпея есть другой выбор». (что Цезарь умело и тщательно обеспечил, конечно).


Это звучит как гораздо более элегантное решение. Нет нужды суетиться о простых числах или соотношениях сторон, и все же он избегает строк, в которых есть необычно низкое число ботов, и единственное условие, которое необходимо проверить, - это насколько полный обратный ход!
Tiby312

Но держись. Скажем, в заднем ранге есть только 3 бота, и они находятся в столбцах 1, 2 и 3. И я удаляю кого-то из 5-го столбца кого-то рядом с фронтом. В итоге я получил бы свободное место на втором-последнем ряду в 5-м столбце без бота, который бы занял его место. Кто должен заполнить это место?
Tiby312

Предположительно, ближайший бот в заднем ранге (то есть тот, что в столбце 3) должен бежать, чтобы заполнить его. Или же вы могли бы сэкономить немного времени, располагая ботов в столбцах 3 и 4 от второго к последнему, ранжировать каждый шаг на один столбец вверх, перемещая пробел в столбец 3, а затем располагать бота в столбце 3 на шаг вперед для заполнения. Это. (ИМО, наиболее «естественно» выглядящей стратегией, вероятно, будет какая-то эвристическая комбинация двух, возможно, с некоторой добавленной случайностью.)
Илмари Каронен

1
Если у заднего ранга слишком мало членов (скажем, менее 50% от других рангов), и вы увеличиваете фронт, гарантированно ли это решить проблему, или возможно, что у заднего ранга все равно будет слишком мало членов после увеличения фасад, требующий его повторения или что-то?
Tiby312

1
@ Tiby312: Я полагаю, вы слишком обдумывали это. Попробуйте, зная, что вы всегда сможете настроить его позже
Питер Гиркенс

7

Предполагая, что единица представляет собой линейную структуру данных (например, список ) ботов.

Сначала вы должны добавить / удалить бота в / из структуры данных и определить новое количество ботов в юните.

Затем вы должны определить новое количество строк и столбцов, используя https://en.wikipedia.org/wiki/Integer_factorization .

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

Затем просто переберите структуру данных, назначив ботов по строкам и столбцам.

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

Чтобы сделать юнит с центром в одном углу , положение бота определяется как

unitPosition + heading * columnNumber * botSeparationDistance + rightVector * rowNumber * botSeparationDistance

Чтобы сделать юнит с центром в середине , положение бота определяется как

unitPosition + heading * (columnNumber * unitSeparationDistance - 0,5 * (numberOfColumns * botSeparationDistance) + rightVector * rowNumber * botSeparationDistance - 0,5 * (числоOfRows * botSeparationDistance)

где заголовок - это вектор, указывающий в направлении, в котором стоит устройство, а правый вектор - вектор, ортогональный направлению .

BotSeparationDistance можно настроить так, чтобы боты стояли дальше или ближе друг к другу.

Если вы чувствуете фантазии, вы можете компенсировать последнюю строку бот на rightVector * 0,5 * (numberOfColumns - actualNumberOfBotsInRow) к центру их на формировании .


Это очень близко к тому, что я ищу! Моя единственная оговорка заключается в том, что при назначении новых позиций бот справа от одного ряда может быть назначен в самом левом углу следующего ряда нового прямоугольника, в результате чего бот перемещается на большое расстояние и в процессах. мешать другим ботам пытаться достичь своей новой назначенной позиции. Я беспокоюсь, что когда бот будет добавлен или удален, вся формация будет беспорядочной, так как боты будут толкаться и суетиться, чтобы добраться до своего далекого места назначения.
Tiby312

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

Как сделать это, не заканчивая вычислением в квадрате? Мне нужно было бы найти ближайшую позицию в массиве 2d от их текущей позиции в массиве 2d для каждого бота, если я правильно понимаю.
Tiby312

В каждой итерации назначается одна единица (и, следовательно, нет необходимости учитывать ее при последующих итерациях), поэтому время выполнения будет равно O (n!). Что, тем не менее, не очень хорошо. Опять же, построение [оптимизирующей структуры выбора] и выполнение n запросов диапазона также не быстрые. Единственное, о чем я могу думать сейчас, это переместить последних ботов подряд назад или заполнить последние места ботов сзади.
Exilyth

Как насчет этого. Скажем, новая формация имеет меньший размер строки. Затем в каждом ряду у вас есть дополнительный бот. Вы назначаете этому боту один вниз, а другой слева. Затем в следующем ряду у вас есть два бота без места. Вы назначаете эти два один вниз, а другой слева. Тогда вы получили 3 ботов без места. Продолжайте, пока у вас не появится дополнительный ряд внизу. Я просто плюю здесь. Я не думал об этом до конца, но похоже, что это будет работать и быстро.
Tiby312

2

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

[4][3][2][1]
[3][3][2][1]
[2][2][2][1]
[1][1][1][1]

Каждый раз, когда робот удаляется, ищите всех остальных роботов и находите его в узле с наименьшим значением. Используйте алгоритм A * или BST, чтобы найти путь от минимального значения до свободного места. Если нет робота с меньшим значением, чем удаленный, ничего не делайте.

Вы также должны быть в состоянии контролировать, как прямоугольник распадается, делая это. Например, на приведенном ниже графике, когда робот покинет нижний со стороны, придет заполнить его место.

[4.9][3.8][2.7][1.0]
[4.8][3.7][2.6][1.0]
[3.9][3.6][2.5][1.0]
[3.5][3.4][2.4][1.0]
[2.9][2.8][2.3][1.0]
[2.0][2.1][2.2][1.0]
[1.9][1.8][1.7][1.0]
[1.6][1.5][1.4][1.0]

Здесь убирается тот, что в 3.8, так что тот, что в 2.5, приходит и занимает свое место.

[o][x][o][ ]
[o][o][o][ ]
[o][o][r][ ]
[o][o][ ][ ]
[o][o][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]

Другой пример. Здесь 2.8 удаляется, поэтому наименьший узел 2.2 занимает его место.

[o][o][o][ ]
[o][o][o][ ]
[o][o][o][ ]
[o][o][o][ ]
[o][x][r][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]

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

[0.0][0.0][0.0][0.0][0.0][0.0]
[0.0][4.9][3.8][2.7][1.0][0.0]
[0.0][4.8][3.7][2.6][1.0][0.0]
[0.0][3.9][3.6][2.5][1.0][0.0]
[0.0][3.5][3.4][2.4][1.0][0.0]
[0.0][2.9][2.8][2.3][1.0][0.0]
[0.0][2.0][2.1][2.2][1.0][0.0]
[0.0][1.9][1.8][1.7][1.0][0.0]
[0.0][1.6][1.5][1.4][1.0][0.0]
[0.0][0.0][0.0][0.0][0.0][0.0]

Хороший учебник по A * можно найти здесь .


Это хорошая идея, но если я правильно понимаю, вы допускаете образования, которые не являются идеальными прямоугольниками. Строки и столбцы на границах могут быть не полными. Я думал, что смогу сделать так, чтобы у него всегда была прямоугольная граница, и вместо этого немного изменить соотношение сторон, чтобы удовлетворить это требование, изменив количество строк и столбцов. Я уже могу рассчитать новые ширину и высоту, которые бы достигли этого, но затем есть какой-то сложный способ переназначить ботов в ближайший спот .. Я думаю.
Tiby312

@ Tiby312 Как вы планируете сделать идеальный прямоугольник, скажем ... 7 роботов?
ClassicThunder

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

@ Tiby312 Я думаю, вам лучше стремиться к постоянному соотношению сторон (т.е. всегда 4: 3 или 8: 5), чем пытаться всегда делать его идеальным прямоугольником.
CorsiKa
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.