package soko import ( "sort" "opslag.de/schobers/geom" ) type PathFinder struct { state State } func NewPathFinder(s State) PathFinder { return PathFinder{s} } type betterNeighbourFn func(geom.Point, int) func (p PathFinder) findBetterNeighbours(distances map[geom.Point]int, curr geom.Point, better betterNeighbourFn) { currDistance := distances[curr] newDistance := currDistance + 1 neighbours := Neighbours(curr) for _, next := range neighbours { if !p.state.IsWalkable(next) || p.state.Bricks.Has(next) { // filter neighbours continue } if distance, ok := distances[next]; ok && distance <= newDistance { // skip when shorter path exists continue } distances[next] = newDistance better(next, newDistance) } } func (p PathFinder) Find(target geom.Point) []geom.Point { source := p.state.Player.Pos frontier := []geom.Point{source} distances := map[geom.Point]int{source: 0} moves := map[geom.Point]geom.Point{source: source} heuristic := func(i int) int { pos := frontier[i] return distances[pos] + pos.DistInt(target) } for { curr := frontier[0] if curr == target { break } frontier = frontier[1:] p.findBetterNeighbours(distances, curr, func(next geom.Point, newDistance int) { moves[next] = curr frontier = append(frontier, next) }) if len(frontier) == 0 { return nil // no path } // apply heuristic to frontier (favor points closer to target) sort.Slice(frontier, func(i, j int) bool { return heuristic(i) < heuristic(j) }) } // build reverse path curr := target path := []geom.Point{curr} for { curr = moves[curr] if curr == source { break } path = append(path, curr) } // reverse path n := len(path) for i := 0; i < n/2; i++ { path[i], path[n-i-1] = path[n-i-1], path[i] } return path } func (p PathFinder) FindDistances() map[geom.Point]int { source := p.state.Player.Pos frontier := []geom.Point{source} distances := map[geom.Point]int{source: 0} for { curr := frontier[0] frontier = frontier[1:] p.findBetterNeighbours(distances, curr, func(next geom.Point, newDistance int) { frontier = append(frontier, next) }) if len(frontier) == 0 { return distances } } }