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) } }