Add day 17 part 2
parent
95f7c6203e
commit
0cf36dc66e
|
@ -18,13 +18,18 @@ const (
|
||||||
DirectionWest
|
DirectionWest
|
||||||
)
|
)
|
||||||
|
|
||||||
type Coordinate struct {
|
type Location struct {
|
||||||
Row int
|
Row int
|
||||||
Col int
|
Col int
|
||||||
FromDirection Direction
|
FromDirection Direction
|
||||||
NumMovesInDirection int
|
NumMovesInDirection int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VisitedNode struct {
|
||||||
|
Coordinate Location
|
||||||
|
LeftInDirection Direction
|
||||||
|
}
|
||||||
|
|
||||||
type Heap[T comparable] struct {
|
type Heap[T comparable] struct {
|
||||||
compare func(T, T) int
|
compare func(T, T) int
|
||||||
data []T
|
data []T
|
||||||
|
@ -137,31 +142,48 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Part 1: %d\n", part1(grid))
|
fmt.Printf("Part 1: %d\n", part1(grid))
|
||||||
|
fmt.Printf("Part 2: %d\n", part2(grid))
|
||||||
}
|
}
|
||||||
|
|
||||||
func part1(grid [][]int) int {
|
func part1(grid [][]int) int {
|
||||||
heuristic := func(pos Coordinate) int {
|
return doAStar(grid, func(_startPos Location, _direction Direction, neighbor Location) bool {
|
||||||
|
return neighbor.NumMovesInDirection > 2
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func part2(grid [][]int) int {
|
||||||
|
return doAStar(grid, func(startPos Location, direction Direction, neighbor Location) bool {
|
||||||
|
// < 3 because we are considering the node we started with, rather than are moving to.
|
||||||
|
// In other words, if we have moved fewer than three times on the node we started at, we can't change directions
|
||||||
|
return (startPos.FromDirection.Opposite() != direction && startPos.NumMovesInDirection < 3) || (neighbor.FromDirection.Opposite() == direction && neighbor.NumMovesInDirection > 9)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a really messy A* implementation I mostly lifted from wikipedia and adapted
|
||||||
|
// After writing it, I learned of some clearer ways to write A*, but I stuck with this
|
||||||
|
func doAStar(grid [][]int, skipNeighbor func(Location, Direction, Location) bool) int {
|
||||||
|
heuristic := func(pos Location) int {
|
||||||
endRow := len(grid)
|
endRow := len(grid)
|
||||||
endCol := len(grid[0])
|
endCol := len(grid[0])
|
||||||
return abs(endRow-pos.Row) + abs(endCol-pos.Col)
|
return abs(endRow-pos.Row) + abs(endCol-pos.Col)
|
||||||
}
|
}
|
||||||
|
|
||||||
startingLocation := Coordinate{
|
// Each location must also consider the direction it was approached from and how many steps lead up to it
|
||||||
|
startingLocation := Location{
|
||||||
Row: 0,
|
Row: 0,
|
||||||
Col: 0,
|
Col: 0,
|
||||||
FromDirection: DirectionWest,
|
FromDirection: DirectionWest,
|
||||||
NumMovesInDirection: 0,
|
NumMovesInDirection: 0,
|
||||||
}
|
}
|
||||||
estimatedDistances := map[Coordinate]int{
|
estimatedDistances := map[Location]int{
|
||||||
startingLocation: heuristic(startingLocation),
|
startingLocation: heuristic(startingLocation),
|
||||||
}
|
}
|
||||||
|
|
||||||
shortestDistances := map[Coordinate]int{
|
shortestDistances := map[Location]int{
|
||||||
startingLocation: 0,
|
startingLocation: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
toVisit := NewHeap[Coordinate](func(c1, c2 Coordinate) int {
|
toVisit := NewHeap[Location](func(c1, c2 Location) int {
|
||||||
estimatedC1Distance, haveC1Estimate := estimatedDistances[c1]
|
estimatedC1Distance, haveC1Estimate := estimatedDistances[c1]
|
||||||
estimatedC2Distance, haveC2Estimate := estimatedDistances[c2]
|
estimatedC2Distance, haveC2Estimate := estimatedDistances[c2]
|
||||||
if !haveC1Estimate && !haveC2Estimate {
|
if !haveC1Estimate && !haveC2Estimate {
|
||||||
|
@ -177,7 +199,6 @@ func part1(grid [][]int) int {
|
||||||
})
|
})
|
||||||
|
|
||||||
toVisit.PushItem(startingLocation)
|
toVisit.PushItem(startingLocation)
|
||||||
parents := make(map[Coordinate]VisitedNode)
|
|
||||||
|
|
||||||
firstVisit := true
|
firstVisit := true
|
||||||
for toVisit.Len() > 0 {
|
for toVisit.Len() > 0 {
|
||||||
|
@ -197,7 +218,7 @@ func part1(grid [][]int) int {
|
||||||
} else if searchPos.FromDirection == direction {
|
} else if searchPos.FromDirection == direction {
|
||||||
// can't turn around
|
// can't turn around
|
||||||
continue
|
continue
|
||||||
} else if neighborPos.NumMovesInDirection > 2 {
|
} else if skipNeighbor(searchPos, direction, neighborPos) {
|
||||||
// can't go straight too much
|
// can't go straight too much
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -221,17 +242,17 @@ func part1(grid [][]int) int {
|
||||||
panic("search failed to find an element")
|
panic("search failed to find an element")
|
||||||
}
|
}
|
||||||
|
|
||||||
func neighbors(coordinate Coordinate) map[Direction]Coordinate {
|
func neighbors(loc Location) map[Direction]Location {
|
||||||
res := map[Direction]Coordinate{
|
res := map[Direction]Location{
|
||||||
DirectionNorth: {Row: coordinate.Row - 1, Col: coordinate.Col, FromDirection: DirectionSouth},
|
DirectionNorth: {Row: loc.Row - 1, Col: loc.Col, FromDirection: DirectionSouth},
|
||||||
DirectionSouth: {Row: coordinate.Row + 1, Col: coordinate.Col, FromDirection: DirectionNorth},
|
DirectionSouth: {Row: loc.Row + 1, Col: loc.Col, FromDirection: DirectionNorth},
|
||||||
DirectionWest: {Row: coordinate.Row, Col: coordinate.Col - 1, FromDirection: DirectionEast},
|
DirectionWest: {Row: loc.Row, Col: loc.Col - 1, FromDirection: DirectionEast},
|
||||||
DirectionEast: {Row: coordinate.Row, Col: coordinate.Col + 1, FromDirection: DirectionWest},
|
DirectionEast: {Row: loc.Row, Col: loc.Col + 1, FromDirection: DirectionWest},
|
||||||
}
|
}
|
||||||
|
|
||||||
inLastDirection := res[coordinate.FromDirection.Opposite()]
|
inLastDirection := res[loc.FromDirection.Opposite()]
|
||||||
inLastDirection.NumMovesInDirection = coordinate.NumMovesInDirection + 1
|
inLastDirection.NumMovesInDirection = loc.NumMovesInDirection + 1
|
||||||
res[coordinate.FromDirection.Opposite()] = inLastDirection
|
res[loc.FromDirection.Opposite()] = inLastDirection
|
||||||
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue