|
@@ -8,8 +8,9 @@ import (
|
|
)
|
|
)
|
|
|
|
|
|
type Point struct {
|
|
type Point struct {
|
|
- y, x int
|
|
|
|
- cost int
|
|
|
|
|
|
+ y, x int
|
|
|
|
+ cost int
|
|
|
|
+ cheats int
|
|
}
|
|
}
|
|
|
|
|
|
func (p *Point) key() string {
|
|
func (p *Point) key() string {
|
|
@@ -26,10 +27,10 @@ func findPoint(line string, mark byte) *Point {
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-func readInput(file *os.File) (*Point, *Point, [][]byte) {
|
|
|
|
|
|
+func readInput(file *os.File) (*Point, [][]byte) {
|
|
scanner := bufio.NewScanner(file)
|
|
scanner := bufio.NewScanner(file)
|
|
var matrix [][]byte
|
|
var matrix [][]byte
|
|
- var start, finish *Point
|
|
|
|
|
|
+ var start *Point
|
|
|
|
|
|
var y int
|
|
var y int
|
|
for scanner.Scan() {
|
|
for scanner.Scan() {
|
|
@@ -43,20 +44,80 @@ func readInput(file *os.File) (*Point, *Point, [][]byte) {
|
|
start = findPoint(line, 'S')
|
|
start = findPoint(line, 'S')
|
|
if start != nil {
|
|
if start != nil {
|
|
start.y = y
|
|
start.y = y
|
|
|
|
+ start.cheats = 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if finish == nil {
|
|
|
|
- finish = findPoint(line, 'E')
|
|
|
|
- if finish != nil {
|
|
|
|
- finish.y = y
|
|
|
|
|
|
+ y++
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return start, matrix
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+var directions [][]int = [][]int{
|
|
|
|
+ {0, -1}, {1, 0}, {0, 1}, {-1, 0},
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func getMoves(current Point, matrix [][]byte, xMax, yMax int, cheat bool) []Point {
|
|
|
|
+ var moves []Point
|
|
|
|
+ for _, direction := range directions {
|
|
|
|
+ move := Point{x: current.x + direction[0], y: current.y + direction[1], cost: current.cost + 1, cheats: current.cheats}
|
|
|
|
+ if move.x <= 0 || move.y <= 0 || move.x >= xMax || move.y >= yMax {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if matrix[move.y][move.x] == '#' {
|
|
|
|
+ if cheat && move.cheats > 0 {
|
|
|
|
+ move.cheats--
|
|
|
|
+ moves = append(moves, move)
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ continue
|
|
}
|
|
}
|
|
|
|
|
|
- y++
|
|
|
|
|
|
+ if cheat && move.cheats == 1 {
|
|
|
|
+ move.cheats = 0
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ moves = append(moves, move)
|
|
}
|
|
}
|
|
|
|
|
|
- return start, finish, matrix
|
|
|
|
|
|
+ return moves
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func hike(start *Point, matrix [][]byte, xMax, yMax int, cheat bool) int {
|
|
|
|
+ cost := 1000000000
|
|
|
|
+ visited := make(map[string]int)
|
|
|
|
+ visited[start.key()] = start.cost
|
|
|
|
+
|
|
|
|
+ moves := []Point{*start}
|
|
|
|
+ for len(moves) > 0 {
|
|
|
|
+ current := moves[0]
|
|
|
|
+ moves = moves[1:]
|
|
|
|
+ if matrix[current.y][current.x] == 'E' && current.cost < cost {
|
|
|
|
+ cost = current.cost
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ newMoves := getMoves(current, matrix, xMax, yMax, cheat)
|
|
|
|
+ for _, newMove := range newMoves {
|
|
|
|
+ if visited[newMove.key()] == 0 || visited[newMove.key()] > newMove.cost {
|
|
|
|
+ moves = append(moves, newMove)
|
|
|
|
+ visited[newMove.key()] = newMove.cost
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return cost
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func part1(start *Point, matrix [][]byte) int {
|
|
|
|
+ xMax := len(matrix[0]) - 1
|
|
|
|
+ yMax := len(matrix) - 1
|
|
|
|
+
|
|
|
|
+ bestWithoutCheating := hike(start, matrix, xMax, yMax, false)
|
|
|
|
+ fmt.Println(bestWithoutCheating)
|
|
|
|
+
|
|
|
|
+ return 0
|
|
}
|
|
}
|
|
|
|
|
|
func main() {
|
|
func main() {
|
|
@@ -70,6 +131,6 @@ func main() {
|
|
log.Fatalf("Failed to open %s!\n", filePath)
|
|
log.Fatalf("Failed to open %s!\n", filePath)
|
|
}
|
|
}
|
|
|
|
|
|
- start, finish, matrix := readInput(file)
|
|
|
|
- fmt.Println(start, finish, matrix)
|
|
|
|
|
|
+ start, matrix := readInput(file)
|
|
|
|
+ fmt.Println("Part1:", part1(start, matrix))
|
|
}
|
|
}
|