165 lines
4.1 KiB
Go
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)
|
|
}
|
|
}
|