4

I'm having some trouble finding the right approach to coding this.

Take a random-generated 2d array, about 50x50 with each cell having a value 1~99. Starting at a random position "Green", and the goal is to surround the target "Red" with the lowest amount of actions.
Moving to a neighboring cell takes 1~99 actions depending on it's value.
example small array with low values:

[

Currently the best idea i have is, generate 4 sets of checkpoints based on the diagonals of the target and then using a lot of Dijkstra's to find a path that goes through all of them, as well as the starting point.

One problem i have is this very quickly becomes an extreme numbers of paths.
FROM any starting point "NorthWest-1 to NW-20" TO any ending point in "NE-1 to NE-20", is 400 possibilities. Adding the 3rd and 4th diagonal to that becomes 400 * 20 * 20.

Another problem using diagonal checkpoints is that the problem is not [shortest path from green to a diagonal (orange path)]

[

but rather from "green to any point on the path around red".

Current pseudocode;

take 2 sets of diagonals nearest to Green/start
find the shortest path that connects those diagonals while going through Green
(backtracking through the path is free)

draw a line starting from the target point, in-between the 2 connected diagonals,
set those cells to value infinite to force going around them (and thus around the target)

find the shortest path connecting the now-seperated diagonals

Unfortunately this pseudocode already includes some edge cases where the 'wall' blocks the most efficient path.

If relevant, this will be written in javascript.

Edit, as an edge case it could spiral the target before surrounding, though extremely rare

enter image description here

Edit2; "Surround" means disconnect the target from the rest of the field, regardless of how large the surrounded area is, or even if it includes the starting point (eg, all edges are 0)

Here is another larger field with (probably) optimal path, and 2 fields in text-form:
https://i.stack.imgur.com/q2fZj.png
https://pastebin.com/raw/YD0AG6YD

Lughaidh
  • 43
  • 4
  • Interesting one. One approach I can think of is splitting it into two different problems: a. find the closed loop, containing the target, with the lowest cost. b. Run BFS from the source until you hit one cell of the closed loop found in a. The first problem (a) is the more difficult one of course. – c0der Oct 30 '20 at 06:07
  • Please can you edit the question to include one of your test cases' data as code (i.e. a 2D array) so it can be copy/pasted? – kaya3 Oct 30 '20 at 12:56
  • Fences have two sides. Would a fence that surrounds the start-node be considered to also be "surrounding" the target node? If not, can you clarify what "surrounding" means, that is, for any given path that disconnects start from target nodes, which of those are considered to be "surrounding" the target and which ones are not? – tucuxi Oct 30 '20 at 13:26

2 Answers2

1

For short, let us call paths that surround the target fences. A valid fence is a set of (connected) nodes that makes the target disconnected from the start, but does not include the target. A minimal fence is one that does so while having a minimal cost. A lasso could be a fence that includes a path to the start node. The goal is to build a minimal-cost lasso.

A simple algorithm would be to use the immediate neighborhood of the target as a fence, and run Dijkstra to any of those fence-nodes to build a (probably non-optimal) lasso. Note that, if optimal answers are required, the choice of fence actually influences the choice of path from the start to the fence -- and vice-versa, the choice of path from start to fence can influence how the fence itself is chosen. The problem cannot be split neatly into two parts.

I believe that the following algorithm will yield optimal fences:

  1. Build a path using Dijkstra from start to target (not including the end-points). Let us call this the yellow path.
  2. Build 2 sets of nodes, one on each side of this yellow path, and neighboring it. Call those sets red and blue. Note that, for any given node that neighbors the path, it can either be part of the path, blue set, red set, or is actually an end-point.
  3. For each node in the red set, run Dijkstra to find the shortest path to a node in the blue set that does not cross the yellow path.
  4. For each of those previous paths, see which is shortest after adding the (missing) yellow-path bit to connect the blue and red ends together.

The cost is length(yellowPath) * cost_of_Dijkstra(redStart, anyBlue)

To make a good lasso, it would be enough to run Dijkstra from the start to any fence node. However, I am unsure of whether the final lasso will be optimal or not.

tucuxi
  • 17,561
  • 2
  • 43
  • 74
  • This seems to be a great solution, currently working on coding it to see the details. --- rather than the target, i will probably dijkstra to one of the cells "behind" the target (looking from the start), this might be slightly more accurate? --- the "red and blue" requires some adjustment, instead of working with nodes, only the boundary between the yellow path and the "red boundary cells" needs to turn 1-way --- otherwise it creates issues when the path spirals or so --- finally, there needs to be a wall so red-blue doesn't surround the starting point. Will take a while to code :) – Lughaidh Nov 01 '20 at 03:27
  • Hmm, right. If a node would be both red and blue, then you would have to handle it to act like both, and acting as "closed in 0" for step-4 calculations. I do not think pathing to "behind" the target makes sense, as the shortest path may or may not include any given "behind" – tucuxi Nov 01 '20 at 07:04
0

You might want to consider the A* search algorithm instead, you can probably adjust the algorithm to search for all 4 spots at once.

https://en.wikipedia.org/wiki/A*_search_algorithm

Basically A* expands Dijkstra's algorithm by focusing it's search on spots that are "closer" to the destination.

There are a number of other variations for search algorithms that may be more useful for your situation as well in the "Also See" section, though some of them are more suited for video game path planning rather than 2D grid paths.

Edit after reviewing question again:

Seems each spot has a weight. This makes the distance calculation a bit less straightforward. In this case, I would treat it as an optimization. For the heuristic cost function, it may be best to just use the most direct path (diagonal) to the goal as the heuristic cost, and then just use A* search to try to find an even better path.


As for the surround logic. I would treat that as it's own logic and a separate step (likely the second step). Find least cost path to the target first. Then find the cheapest way to surround the path. Honestly, the cheapest way to surround a point is probably worth it's own question.

Once you have both parts, it should be easy enough to merge the two. There will be some point where the two first overlap and that is where they are merged together.

Nuclearman
  • 5,029
  • 1
  • 19
  • 35