https://github.com/vladovsiychuk/jump-point-search-algorithm
Improved version of A*, aka JPS
https://github.com/vladovsiychuk/jump-point-search-algorithm
a-star algorithm jps jps-algorithm jump-point-search pathfinding pathfinding-algorithm
Last synced: 17 days ago
JSON representation
Improved version of A*, aka JPS
- Host: GitHub
- URL: https://github.com/vladovsiychuk/jump-point-search-algorithm
- Owner: vladovsiychuk
- Created: 2024-11-23T08:44:04.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-11-25T09:35:53.000Z (over 1 year ago)
- Last Synced: 2025-10-19T15:59:54.017Z (9 months ago)
- Topics: a-star, algorithm, jps, jps-algorithm, jump-point-search, pathfinding, pathfinding-algorithm
- Language: Go
- Homepage:
- Size: 28.3 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
Implements the idea from https://zerowidth.com/2013/a-visual-explanation-of-jump-point-search/
## Pseudo Code
```
Node {
Position // X, Y coordinates
G, H, F // Cost metrics: G (from start), H (heuristic to end), F (total cost)
ParentDir // Direction from parent node
ForcedNeighborDir // Direction of a forced neighbor (if any)
Parent // Reference to parent node
}
findPathWithJPS(StartNode, EndNode, Matrix)
OpenList = createHeap() // Binary heap, pops node with lowest F value with log(N) speed
OpenList.push(StartNode) // Add StartNode to OpenList
while OpenList is not empty
CurrentNode = pop(OpenList) // Get node with the lowest F value
if CurrentNode.Position == EndNode.Position
return reconstructPath(CurrentNode) // Build path by traversing Parent nodes
Successors = findSuccessors(CurrentNode, EndNode, Matrix)
for each Successor in Successors
OpenList.push(Successor)
reconstructPath(Node)
ResultList = []
while Node != nil
add Node to ResultList
Node = Node.Parent
reverse(ResultList)
return ResultList
findSuccessors(CurrentNode, EndNode, Matrix)
Successors = []
X, Y = CurrentNode.Position
for each Dir in getDirections(CurrentNode) // Note: can be run in parallel
DX, DY = Dir
SX, SY, ForcedNeighborDir, found = jump(X+DX, Y+DY, DX, DY, EndNode, Matrix)
if found
Successor = new Node()
Successor.Position = {SX, SY}
Successor.G = CurrentNode.G + heuristic(CurrentNode.Position, Successor.Position)
Successor.H = heuristic(Successor.Position, EndNode.Position)
Successor.F = Successor.G + Successor.H
Successor.ParentDir = Dir
Successor.ForcedNeighborDir = ForcedNeighborDir
Successor.Parent = CurrentNode
add Successor to Successors
return Successors
getDirections(Node)
if Node.ParentDir == nil // Starting node
return [{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}] // All 8 directions
PDX, PDY = Node.ParentDir
FNDX, FNDY = Node.ForcedNeighborDir
if PDX != 0 and PDY != 0 // Diagonal movement
return [{PDX, PDY}, {PDX, 0}, {0, PDY}, if ForcedNeighborDir exists then also {FNDX, FNDY}]
else // Horizontal or vertical movement
return [{PDX, PDY}, if ForcedNeighborDir exists then also {FNDX, FNDY}]
jump(X, Y, DX, DY, EndNode, Matrix) returns X, Y, ForcedNeighnorDir, found
while isWalkable(X, Y, Matrix)
if {X, Y} == EndNode.Position
return X, Y, nil, true
// Diagonal movement: Check forced neighbors
if DX != 0 and DY != 0
if !isWalkable(X-DX, Y, Matrix) && !isWalkable(X, Y-DY, Matrix)
return 0, 0, nil, false
// Try to find the forced neighbor pattern for diagonal move as described in the article
if !isWalkable(X, Y+DY*-1, Matrix) and isWalkable(X+DX, Y+DY*-1, Matrix)
return X, Y, {DX, DY*-1}, true
if !isWalkable(X+DX*-1, Y Matrix) and isWalkable(X+DX*-1, Y+DY, Matrix)
return X, Y, {DX*-1, DY}, true
// Recursive jump for horizontal and vertical continuations
_, _, _, found1 = jump(X + DX, Y, DX, 0, EndNode, Matrix) // Only found is of interest
_, _, _, found2 = jump(X, Y + DY, 0, DY, EndNode, Matrix)
if (found1 == true) or (found2 == true)
return X, Y, nil, true
// Horizontal movement: Check forced neighbors
else if DX != 0
if !isWalkable(X, Y - 1, Matrix) and isWalkable(X + DX, Y - 1, Matrix)
return X, Y, {DX, -1}, true
if !isWalkable(X, Y + 1, Matrix) and isWalkable(X + DX, Y + 1, Matrix)
return X, Y, {DX, 1}, true
// Vertical movement: Check forced neighbors
else if DY != 0
if !isWalkable(X - 1, Y, Matrix) and isWalkable(X - 1, Y + DY, Matrix)
return X, Y, {-1, DY}, true
if !isWalkable(X + 1, Y, Matrix) and isWalkable(X + 1, Y + DY, Matrix)
return X, Y, {1, DY}, true
// Continue in the same direction
X += DX
Y += DY
return 0, 0, nil, false
isWalkable(X, Y, Matrix)
return X >= 0 and Y >= 0 and x < Matrix.size and y < Matrix[0].size and Matrix[x][y]
func heuristic(A, B, Matrix) returns int
// Using Manhattan distance as heuristic
return math.Abs(A.X-B.X) + math.Abs(A.Y-B.Y)
```
## Running Tests
1. Install Go with "brew install go" or https://go.dev/doc/install
2. git clone https://github.com/vladovsiychuk/jump-point-search-algorithm
3. cd jump-point-search-algorithm
4. go mod tidy
5. go test ./...