🌅
This commit is contained in:
174
solutions/day12/day12.go
Normal file
174
solutions/day12/day12.go
Normal file
@@ -0,0 +1,174 @@
|
||||
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.")
|
||||
}
|
||||
Reference in New Issue
Block a user