AOC2022/day12/day12.go
2022-12-13 00:01:35 +01:00

165 lines
4.1 KiB
Go

package main
import (
"AOC2022/helper"
"fmt"
"os"
)
type FieldPoint struct {
cost int
height int
before [2]int
}
func main() {
args := os.Args[1:]
lines := helper.ReadTextFile(args[0])
start, end := getStartingPointAndEndpoint(lines)
fmt.Println(start)
fmt.Println(end)
field := getField(lines)
part1(field, start, end)
part2(lines, field, end)
}
func part2(lines []string, field [][]FieldPoint, end [2]int) {
lowestPoints := getLowestPoints(lines)
fastestPath := 999999
for _, point := range lowestPoints {
activePoints := make(map[[2]int]struct{})
activePoints[[2]int{point[0], point[1]}] = struct{}{}
field = getField(lines)
steps := getBestRouteLength(activePoints, field, end)
if steps < fastestPath && steps != 0 {
fastestPath = steps
}
}
fmt.Println(fastestPath)
}
func part1(field [][]FieldPoint, start, end [2]int) {
activePoints := make(map[[2]int]struct{})
activePoints[start] = struct{}{}
fmt.Println(getBestRouteLength(activePoints, field, end))
}
func getField(lines []string) [][]FieldPoint {
field := make([][]FieldPoint, len(lines))
for i := 0; i < len(lines); i++ {
line := lines[i]
fieldLine := make([]FieldPoint, len(line))
for j := 0; j < len(line); j++ {
height := int(line[j])
if line[j] == 'S' {
height = int('a')
}
if line[j] == 'E' {
height = int('z')
}
fieldLine[j] = FieldPoint{0, height, [2]int{-1, -1}}
}
field[i] = fieldLine
}
return field
}
func getBestRouteLength(activePoints map[[2]int]struct{}, field [][]FieldPoint, endPoint [2]int) int {
for len(activePoints) > 0 {
step(&field, &activePoints)
}
return field[endPoint[0]][endPoint[1]].cost
}
func step(field *[][]FieldPoint, activePoints *map[[2]int]struct{}) {
point := get_some_key(*activePoints)
delete(*activePoints, point)
current0 := point[0]
current1 := point[1]
currentFieldSumCost := (*field)[current0][current1].cost
directions := [4][2]int{{0, -1}, {+1, 0}, {0, 1}, {-1, 0}}
for _, direction := range directions {
toVisit0 := current0 + direction[0]
toVisit1 := current1 + direction[1]
if checkVisitable(point, direction, *field) {
cost := 1 + currentFieldSumCost
if (*field)[toVisit0][toVisit1].cost > cost || (*field)[toVisit0][toVisit1].cost == 0 {
(*field)[toVisit0][toVisit1].cost = cost
(*field)[toVisit0][toVisit1].before = [2]int{current0, current1}
(*activePoints)[[2]int{toVisit0, toVisit1}] = struct{}{}
}
}
}
}
func checkVisitable(activePosition [2]int, direction [2]int, field [][]FieldPoint) (visitable bool) {
toVisit := activePosition
toVisit[0] += direction[0]
toVisit[1] += direction[1]
if toVisit[0] > -1 && toVisit[1] > -1 &&
toVisit[0] < len(field) && toVisit[1] < len((field)[0]) &&
field[activePosition[0]][activePosition[1]].before != toVisit {
heightToVisit := field[toVisit[0]][toVisit[1]].height
heightCurrentPos := field[activePosition[0]][activePosition[1]].height + 1
if heightToVisit > heightCurrentPos {
return false
}
return true
}
return false
}
func getStartingPointAndEndpoint(field []string) (start, end [2]int) {
for i := 0; i < len(field); i++ {
for j := 0; j < len(field[i]); j++ {
if field[i][j] == 'S' {
start = [2]int{i, j}
}
if field[i][j] == 'E' {
end = [2]int{i, j}
}
}
}
return
}
func getLowestPoints(field []string) [][2]int {
lowestPoints := [][2]int{}
for i := 0; i < len(field); i++ {
for j := 0; j < len(field[i]); j++ {
if field[i][j] == 'a' {
lowestPoints = append(lowestPoints, [2]int{i, j})
}
}
}
return lowestPoints
}
func get_some_key(m map[[2]int]struct{}) [2]int {
for k := range m {
return k
}
return [2]int{-1, -1}
}
func print(field [][]FieldPoint) {
for i := 0; i < len(field); i++ {
fieldLine := field[i]
tempArray := []int{}
for j := 0; j < len(fieldLine); j++ {
tempArray = append(tempArray, fieldLine[j].height-96)
}
fmt.Println(tempArray)
}
fmt.Println()
for i := 0; i < len(field); i++ {
fieldLine := field[i]
tempArray := []int{}
for j := 0; j < len(fieldLine); j++ {
tempArray = append(tempArray, fieldLine[j].cost)
}
fmt.Println(tempArray)
}
}