Skip to content

Commit fe88c41

Browse files
committed
day20: solved part 1
1 parent 4dc306f commit fe88c41

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

day20/example.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
###############
2+
#...#...#.....#
3+
#.#.#.#.#.###.#
4+
#S#...#.#.#...#
5+
#######.#.#.###
6+
#######.#.#...#
7+
#######.#.###.#
8+
###..E#...#...#
9+
###.#######.###
10+
#...###...#...#
11+
#.#####.#.###.#
12+
#.#...#.#.#...#
13+
#.#.#.#.#.#.###
14+
#...#...#...###
15+
###############

day20/main.go

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"fmt"
7+
"os"
8+
9+
"github.com/fxnn/adventofcode2024/util"
10+
)
11+
12+
const (
13+
WALL = '#'
14+
EMPTY = '.'
15+
START = 'S'
16+
END = 'E'
17+
)
18+
19+
func readCourse() [][]byte {
20+
var scanner = bufio.NewScanner(os.Stdin)
21+
22+
var y int
23+
var course [][]byte
24+
for scanner.Scan() {
25+
var line = scanner.Text()
26+
var row = make([]byte, len(line))
27+
for x, r := range line {
28+
row[x] = byte(r)
29+
}
30+
course = append(course, row)
31+
y++
32+
}
33+
if err := scanner.Err(); err != nil {
34+
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
35+
os.Exit(1)
36+
}
37+
38+
return course
39+
}
40+
41+
var directions = []util.Point{{X: -1, Y: 0}, {X: 1, Y: 0}, {X: 0, Y: 1}, {X: 0, Y: -1}}
42+
43+
func findMoves(course [][]byte) []util.Point {
44+
var f = findStart(course)
45+
var moves = []util.Point{f}
46+
for course[f.Y][f.X] != END {
47+
for _, d := range directions {
48+
var t = f.Add(d)
49+
if len(moves) > 1 && t == moves[len(moves)-2] {
50+
continue
51+
}
52+
if !t.IsInBounds(len(course), len(course[f.Y])) {
53+
continue
54+
}
55+
if course[t.Y][t.X] == WALL {
56+
continue
57+
}
58+
moves = append(moves, t)
59+
//fmt.Printf("move %d,%d -> %d,%d\n", f.Y, f.X, t.Y, t.X)
60+
f = t
61+
break
62+
}
63+
}
64+
return moves
65+
}
66+
67+
func findStart(course [][]byte) util.Point {
68+
for y := 0; y < len(course); y++ {
69+
for x := 0; x < len(course[y]); x++ {
70+
if course[y][x] == START {
71+
return util.Point{Y: y, X: x}
72+
}
73+
}
74+
}
75+
fmt.Println("Error: start not found")
76+
os.Exit(1)
77+
return util.Point{}
78+
}
79+
80+
func findMoveIdx(moves []util.Point, move util.Point) int {
81+
for i := range moves {
82+
if moves[i] == move {
83+
return i
84+
}
85+
}
86+
return -1
87+
}
88+
89+
type cheat struct {
90+
start util.Point
91+
end util.Point
92+
}
93+
94+
func findCheats(course [][]byte, moves []util.Point, startIdx int, minSaving int, cheatedWalls map[util.Point]util.Void) []cheat {
95+
var s = moves[startIdx]
96+
var cheats []cheat
97+
for _, d := range directions {
98+
var w = s.Add(d)
99+
if !w.IsInBounds(len(course), len(course[w.Y])) {
100+
continue
101+
}
102+
if course[w.Y][w.X] != WALL {
103+
continue
104+
}
105+
var e = w.Add(d)
106+
var ei = findMoveIdx(moves, e)
107+
// HINT: save 100 picoseconds, but this includes two additional steps
108+
if ei-startIdx < minSaving+2 {
109+
// TODO: might there be multiple cheats forward?
110+
continue
111+
}
112+
cheatedWalls[w] = util.Void{}
113+
fmt.Printf("%d picoseconds saved by cheat: %d,%d -> %d,%d\n", ei-startIdx-2, s.Y, s.X, e.Y, e.X)
114+
cheats = append(cheats, cheat{start: s, end: e})
115+
}
116+
return cheats
117+
}
118+
119+
func printCourseWithCheats(course [][]byte, cheats map[util.Point]util.Void) {
120+
for y := range course {
121+
for x := range course[y] {
122+
if _, ok := cheats[util.Point{Y: y, X: x}]; ok {
123+
fmt.Print("C")
124+
} else {
125+
fmt.Print(string(course[y][x]))
126+
}
127+
}
128+
fmt.Println()
129+
}
130+
fmt.Println()
131+
}
132+
133+
func main() {
134+
var minSaving = flag.Int("minSaving", 100, "consider cheats that save at least minSaving picoseconds")
135+
flag.Parse()
136+
137+
var course = readCourse()
138+
var moves = findMoves(course)
139+
var time = len(moves) - 1
140+
fmt.Printf("course takes %d picoseconds\n", time)
141+
var cheats = make(map[cheat]util.Void)
142+
var cheatedWalls = make(map[util.Point]util.Void)
143+
for i := range moves {
144+
for _, c := range findCheats(course, moves, i, *minSaving, cheatedWalls) {
145+
cheats[c] = util.Void{}
146+
}
147+
}
148+
printCourseWithCheats(course, cheatedWalls)
149+
fmt.Printf("found %d unique cheats saving >= %d picoseconds", len(cheats), *minSaving)
150+
}

0 commit comments

Comments
 (0)