Мне была сделана домашняя работа, которая выглядит примерно так:
Вам предоставляется изображение, состоящее из пикселей в четырех цветах. Цвета соответствуют местности, врагам, союзникам и стенам. Бомбу можно сбросить с любой координатой (пара целых чисел). Вам также дают:
r
- радиус бомбы эффекта (в пикселях, положительное целое число)e
- количество очков для убийства противникаa
- количество очков для убийства союзника(например,
r = 10
,e = 1
,a = -2
)Когда бомба падает, все враги и союзники в радиусе (евклидовом расстоянии) погибают, если между ними и бомбой нет стены (то есть неэлеализированная линия, соединяющая солдата с бомбой, пересекает стену). Когда бомба падает на стену, этот конкретный пиксель ведет себя точно так же, как и нормальный ландшафт. Остальная часть стены все еще стена.
Вы начинаете со счетом 0. Найдите координаты, где вы должны сбросить одну бомбу, чтобы получить лучший результат. Если есть несколько оптимальных решений, верните любой из них.
Здесь пример обрезанного, измененного размера и с измененными цветами для улучшения читаемости:
Исходное изображение, которое я получил, можно найти здесь.
Что я уже разработал
Я знаю, что грубая причина этой проблемы - ужасное решение. Я придумал, как быстро его решить, когда нет стен. Здесь некоторый псевдокод:
args Map, R, A, E
for (every Soldier)
create a Heightmap with dimensions of Map
zero-fill the Heightmap
on the Heightmap draw a filled circle of value 1 around Soldier with radius R
if (Soldier is Ally)
multiply Heightmap by A
else
multiply Heightmap by E
add all Heightmaps together
return coordinates of highest point in TotalHeightmap
Конечно, этот "фрагмент" можно оптимизировать, но его легче понять в этой форме. Он может быть расширен до полного решения путем ограничения кругов высотных карт со стенами. Чертежные круги просты, и многие библиотеки обработки изображений предоставляют функции для этого, поэтому, может быть, неплохо рисовать круги, затем нарисовать на них стены и заливать круги от центра, останавливаясь на стенах или границах круга. Я проверю производительность, когда буду ее реализовывать.
Без ограничений кругов я бы сделал так:
run the above code to get a TotalHeightmap
create empty PointList
for (every Point in TotalHeightmap)
create PointObject with properties:
Coordinates,
Height,
WallsFlag = False
add PointObject to PointList
sort PointList by descending Height
until (PointList[0].WallsFlag == True)
for (every Soldier in radius R from PointList[0])
if (Bresenham line connecting Soldier with PointList[0] intersects a Wall)
subtract (A if Soldier is Ally else E) from PointList[0].Height
set PointList[0].WallsFlag = True
sort PointList by descending Height
return PointList[0].Coordinates
Он будет работать до тех пор, пока обе вражеские и союзнические баллы будут неотрицательными, так что это далеко не идеально. Чтобы исправить это, я мог бы перебирать все пиксели, но это было бы ужасно медленным (не так медленно, как грубо заставляя его, я думаю, но это не похоже на хорошую идею). Метод поиска перекрестков на поверхности кажется слишком грубым.
Я ищу более элегантное и быстрое решение этой проблемы. Как бы вы решили? Я буду реализовывать его в Python с PIL, если это поможет.
Btw Я считаю, что мой учитель в порядке со мной, размещая этот вопрос на SO, я считаю, что он даже ожидает, что я обсужу его и воплощу лучшее решение.