Кратчайший путь Java

Я пытаюсь сделать небольшую игру в защиту башни на Java. У меня есть сетка, состоящая из массива Point2D.Double с именем:

ПолеАрр[h][v]

h представляет горизонтальные поля, v вертикальные вертикальные поля

получается вот такая сетка

+ + + + + + +
S + X + + + +
+ + + X + + +
+ X + + + + F
+ + X + + + +

S представляет старт, F представляет финиш, X представляет башни

теперь я хочу рассчитать кратчайший маршрут, но я понятия не имею, с чего начать.

Башни имеют следующие переменные для местоположения: HorizontalNr и VerticalNr.

для краски я делаю то:

public void paint(Graphics2D g2) {
    int Xpos = HorizontalNr * playfield.getSquarewidth() + playfield.GetinitialXPos();
    int Ypos = VerticalNr * playfield.getSquarewidth() + playfield.GetinitialYPos();
    g2.fillRect(Xpos, Ypos, 50, 50);
}

У кого-нибудь есть какие-нибудь советы о том, как мне создать свой вражеский класс, чтобы у меня не возникло проблем с алгоритмом? и/или есть советы, как рассчитать кратчайший путь?

уже спасибо грт киви


person Kiwi    schedule 23.02.2012    source источник
comment
Кратчайший путь для чего? Вы пытаетесь решить коммивояжера?   -  person SLaks    schedule 23.02.2012
comment
Кратчайший маршрут от начала до конца, избегая башен   -  person Kiwi    schedule 23.02.2012
comment
И будьте осторожны в своих сравнениях, особенно если вы хотите, чтобы башни блокировали врагов — значения Double/Float не являются «точными». В зависимости от ваших конкретных потребностей вам может потребоваться создать свой собственный класс Point.   -  person Clockwork-Muse    schedule 23.02.2012


Ответы (3)


Как сказал Марк, это задача о кратчайшем пути, которую можно решить легко и эффективно.

Обратите внимание: поскольку ваша проблема не взвешена, вы можете использовать здесь BFS, что довольно прост в реализации, а также гарантирует поиск пути сортировки для невзвешенных графов.

Псевдокод для BFS:

findShortestPath(source,target):
  queue<- new queue
  visited <- {}
  Map<point,point> parents <- empty map
  queue.push(source)
  while (queue.empty() == false): 
     current <- queue.takeFirst()
     if (current.equals(target)):
         extract the path from source to destination using the map parents(*)
         return
     visited.add(current)
     for each p such that p and current are neighbors: //insert neighbors to queue
          if p is not in visited: 
                if (p is not an obstacle):
                   queue.push(p)
                   parents.put(p,current) //current is the parent of p

(*) Извлечь путь из карты очень просто: просто следуйте current <- parent.get(current), пока не получите null, таким образом вы извлечете точный путь, который будете использовать.

Обратите внимание, что даже более быстрым решением [в большинстве случаев] будет A* с эвристика манхэттенского расстояния, но реализовать ее намного сложнее.

person amit    schedule 23.02.2012
comment
Хм, посмотрю на это, выглядит определенно проще ^^ - person Kiwi; 23.02.2012
comment
Но как я могу определить, скажем, источник (в java)? Я могу указать горизонтальный и вертикальный номера, но я не знаю, как я мог поместить это в 1 переменную. - person Kiwi; 23.02.2012
comment
@Kiwi Источник - это вход в любую задачу о кратчайшем пути - это начало пути или в играх в защиту башни: откуда враги входят на карту. - person amit; 23.02.2012
comment
Я знаю, но я не могу сказать, что point2D start = point2D(x,y), мое начало похоже на = start[1][1], и это блок 50x50, так что я должен вычислить центры и использовать их? - person Kiwi; 23.02.2012
comment
@Kiwi: я не понимаю. sorce в вашем примере – это S, а target – это F в вашем примере. - person amit; 24.02.2012
comment
Да, и каждый блок имеет номер по горизонтали и номер по вертикали. S = 1 блок, F = 1 блок, Башня = 1 блок, ... - person Kiwi; 24.02.2012
comment
@Kiwi: В этом случае: вы можете взять центр и проверить наличие коллизий. Вам также нужно позаботиться о том, чтобы перемещаться по блокам [а не по частям блоков]. Альтернативой [лучшей, на мой взгляд] является создание мини-карты, которая содержит все детали, но каждый блок будет иметь размер 1. Используйте алгоритм на этом миникарта - person amit; 24.02.2012
comment
Это сработало отлично для меня, спасибо! Я использовал свою собственную рекурсивную реализацию Дейкстры, но она была действительно неэффективной! Это намного быстрее. - person Ricard Pérez del Campo; 29.04.2013

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

Например, простым и эффективным алгоритмом является алгоритм Дейкстры. Из Википедии:

  1. Пусть узел, с которого мы начинаем, называется начальным узлом. Пусть расстояние узла Y будет расстоянием от начального узла до Y. Алгоритм Дейкстры назначит некоторые начальные значения расстояния и попытается улучшить их шаг за шагом. Назначьте каждому узлу предварительное значение расстояния: установите его равным нулю для нашего начального узла и бесконечностью для всех остальных узлов.
  2. Отметьте все узлы как непосещенные. Установите начальный узел как текущий. Создайте набор непосещенных узлов, называемый непосещенным набором, состоящий из всех узлов, кроме начального узла.
  3. Для текущего узла рассмотрите всех его непосещенных соседей и вычислите их ориентировочные расстояния. Например, если текущий узел A помечен ориентировочным расстоянием 6, а ребро, соединяющее его с соседом B, имеет длину 2, то расстояние до B (через A) будет 6+2=8. Если это расстояние меньше ранее записанного ориентировочного расстояния B, то перезапишите это расстояние. Несмотря на то, что соседний узел был просмотрен, он не помечен как посещенный в это время и остается в наборе непосещенных.
  4. Когда мы закончим рассмотрение всех соседей текущего узла, отметим текущий узел как посещенный и удалим его из набора непосещенных. Посещенный узел больше никогда не будет проверяться; его расстояние, записанное сейчас, является окончательным и минимальным.
  5. Если узел назначения помечен как посещенный (при планировании маршрута между двумя конкретными узлами) или если наименьшее предварительное расстояние между узлами в непосещенном наборе равно бесконечности (при планировании полного обхода), то остановитесь. Алгоритм завершен.
  6. Установите непосещенный узел, отмеченный наименьшим предварительным расстоянием, в качестве следующего «текущего узла» и вернитесь к шагу 3.
person Mark Byers    schedule 23.02.2012
comment
Я знаю алгоритм, но я не знаю, как его реализовать, - person Kiwi; 23.02.2012
comment
@Kiwi: На странице Википедии есть псевдокод. Вы можете использовать это как основу для своей реализации. - person Mark Byers; 23.02.2012

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

person Paul    schedule 09.10.2012
comment
Вы должны добавить больше деталей, обосновывающих ваш ответ, чтобы OP мог лучше понять проблему. - person WiSaGaN; 09.10.2012