Files
advent2022/solutions/day12/day12.go
2022-12-23 19:45:56 -08:00

175 lines
3.5 KiB
Go

package day12
import (
"bufio"
"fmt"
"os"
)
type Point struct {
x int
y int
}
func to_level(r rune) int {
return int(r - 'a')
}
func from_level(l int) rune {
return rune('a' + l)
}
func validMove(p1 Point, p2 Point, grid [][]int) bool {
if p2.x < 0 || p2.y < 0 || p2.x >= len(grid[0]) || p2.y >= len(grid) {
return false
}
diff := grid[p2.y][p2.x] - grid[p1.y][p1.x]
return (diff <= 1)
}
func updateDistances(grid [][]int, distances [][]int) bool {
y := 0
updatedSomething := false
for _, row := range distances {
for x := range row {
best := distances[y][x]
nexts := nextSteps(Point{x, y}, grid)
for _, next := range nexts {
if distances[next.y][next.x] != -1 {
if best == -1 || distances[next.y][next.x]+1 < best {
fmt.Println("Found a live one; at", Point{x, y}, "with score", distances[y][x], "going to", next, "with score", distances[next.y][next.x])
best = distances[next.y][next.x] + 1
updatedSomething = true
}
}
}
distances[y][x] = best
}
y += 1
}
return updatedSomething
}
func nextSteps(p Point, grid [][]int) []Point {
retval := []Point{}
// point above
above := Point{p.x, p.y - 1}
if validMove(p, above, grid) {
retval = append(retval, above)
}
// point below
below := Point{p.x, p.y + 1}
if validMove(p, below, grid) {
retval = append(retval, below)
}
// point left
left := Point{p.x - 1, p.y}
if validMove(p, left, grid) {
retval = append(retval, left)
}
// point right
right := Point{p.x + 1, p.y}
if validMove(p, right, grid) {
retval = append(retval, right)
}
return retval
}
func printMap(grid [][]int) {
for _, line := range grid {
for _, v := range line {
fmt.Printf("%c", from_level(v))
}
fmt.Println()
}
}
func printDistances(grid [][]int, distances [][]int) {
for y, line := range distances {
for x, v := range line {
fmt.Printf("%5d/%c", v, from_level(grid[y][x]))
}
fmt.Println()
}
}
func Run(filename string) {
file, err := os.Open(filename)
if err != nil {
fmt.Println("Error opening file:", err)
return
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
grid := [][]int{}
distances := [][]int{}
var start Point
var end Point
for scanner.Scan() {
line := scanner.Text()
row := []int{}
drow := []int{}
y := len(grid)
for x, r := range []rune(line) {
if r == 'S' {
r = 'a'
start = Point{x, y}
}
if r == 'E' {
r = 'z'
end = Point{x, y}
}
row = append(row, to_level(r))
drow = append(drow, -1)
}
grid = append(grid, row)
distances = append(distances, drow)
}
file.Close()
distances[end.y][end.x] = 0
printMap(grid)
printDistances(grid, distances)
fmt.Printf("Start position is (%d, %d)\n", start.x, start.y)
fmt.Printf("End position is (%d, %d)\n", end.x, end.y)
fmt.Println("Valid first steps:", nextSteps(start, grid))
iteration := 0
keepGoing := true
for keepGoing {
fmt.Println("Running iteration", iteration)
printDistances(grid, distances)
keepGoing = updateDistances(grid, distances)
iteration += 1
}
fmt.Printf("Best path is %d steps long.\n", distances[start.y][start.x])
closestAIs := -1
for y, line := range grid {
for x, v := range line {
if from_level(v) == 'a' {
distance := distances[y][x]
fmt.Printf("Point (%d, %d) is level `a`, and is %d steps from end.\n", x, y, distance)
if distance != -1 {
if closestAIs == -1 || distance < closestAIs {
closestAIs = distance
}
}
}
}
}
fmt.Println("The closest 'a' is", closestAIs, "steps away.")
}