Skip to content

Commit

Permalink
added options
Browse files Browse the repository at this point in the history
  • Loading branch information
val antonini committed Apr 30, 2024
1 parent 31217ed commit 412633c
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ weights := []int{
grid := astar.NewGridFromSlice(8, 4, weights)

pathfinder := astar.NewPathfinder(grid)
got := pathfinder.Find(Vec2{1, 1}, Vec2{6, 2})
got := pathfinder.Find(astar.Vec2{1, 1}, astar.Vec2{6, 2})

want := []Vec2{
{1, 1},
Expand Down
47 changes: 31 additions & 16 deletions astar.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,35 +48,50 @@ type node struct {
// Pathfinder is a simple A* pathfinding algorithm implementation.
type Pathfinder struct {
weights Grid[int]
options Options
heuristic heuristicFunc
getSuccessors getSuccessorsFunc
}

// NewPathfinder creates a new Pathfinder with the given weights. The weights
// are used to determine the cost of traversing a cell. A weight of 0 means the
// cell is not traversable. A weight of 1 or higher means the cell is
// traversable.
func NewPathfinder(weights Grid[int]) Pathfinder {
return Pathfinder{
// NewPathfinder creates a new Pathfinder with the given weights and options.
// The weights are used to determine the cost of traversing a cell. A weight of
// 0 means the cell is not traversable. A weight of 1 or higher means the cell
// is traversable.
func NewPathfinder(weights Grid[int], opts ...Option) Pathfinder {
opt := Options{
heuristic: man,
}

for _, optFunc := range opts {
optFunc(&opt)
}

pf := Pathfinder{
weights: weights,
options: opt,
heuristic: manhattan,
getSuccessors: func(v Vec2) []Vec2 {
return getSuccessors(v, weights.Width, weights.Height, cardinalSuccessors)
},
}
}

// NewDiagonalPathfinder creates a new Pathfinder with the given weights that
// supports diagonal movement. A weight of 0 means the cell is not traversable.
// A weight of 1 or higher means the cell is traversable.
func NewDiagonalPathfinder(weights Grid[int]) Pathfinder {
return Pathfinder{
weights: weights,
heuristic: diagonalDistance,
getSuccessors: func(v Vec2) []Vec2 {
switch opt.heuristic {
case man:
pf.heuristic = manhattan
case dd:
pf.heuristic = diagonalDistance
}

if opt.diagonals {
if opt.heuristic == man {
pf.heuristic = diagonalDistance
}
pf.getSuccessors = func(v Vec2) []Vec2 {
return getSuccessors(v, weights.Width, weights.Height, diagonalSuccessors)
},
}
}

return pf
}

// Find returns a path from start to end. If no path is found, an empty slice
Expand Down
4 changes: 2 additions & 2 deletions astar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func TestPath_Diagonal1(t *testing.T) {
}
grid := NewGridFromSlice(5, 5, weights)

pathfinder := NewDiagonalPathfinder(grid)
pathfinder := NewPathfinder(grid, WithDiagonals())
got := pathfinder.Find(Vec2{1, 1}, Vec2{3, 1})

want := []Vec2{
Expand All @@ -209,7 +209,7 @@ func TestPath_Diagonal2(t *testing.T) {
}
grid := NewGridFromSlice(8, 4, weights)

pathfinder := NewDiagonalPathfinder(grid)
pathfinder := NewPathfinder(grid, WithDiagonals())
got := pathfinder.Find(Vec2{1, 1}, Vec2{6, 2})

want := []Vec2{
Expand Down
26 changes: 26 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package astar

type heuristic int

const (
// Manhattan heuristic.
man heuristic = iota
// Euclidean heuristic.
dd
)

// Option is a functional option for the pathfinder.
type Option func(o *Options)

// Options contains the options for the pathfinder.
type Options struct {
diagonals bool
heuristic heuristic
}

// WithDiagonals enables diagonal movement in the search space.
func WithDiagonals() Option {
return Option(func(o *Options) {
o.diagonals = true
})
}

0 comments on commit 412633c

Please sign in to comment.