Skip to content

Commit fd22800

Browse files
committed
feat(angch/2024-20): Part1
1 parent c6195f3 commit fd22800

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

angch/2024-20/main.go

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"container/heap"
6+
"fmt"
7+
"log"
8+
"os"
9+
"time"
10+
)
11+
12+
var dirs = [][2]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}
13+
14+
type boardstate struct {
15+
index int
16+
mm map[[2]int]byte
17+
moves [][2]int
18+
}
19+
20+
// A PriorityQueue implements heap.Interface and holds Items.
21+
type PriorityQueue []*boardstate
22+
23+
func (pq PriorityQueue) Len() int { return len(pq) }
24+
func (pq PriorityQueue) Less(i, j int) bool {
25+
return len(pq[i].moves) < len(pq[j].moves)
26+
}
27+
func (pq PriorityQueue) Swap(i, j int) {
28+
pq[i], pq[j] = pq[j], pq[i]
29+
pq[i].index = i
30+
pq[j].index = j
31+
}
32+
33+
func (pq *PriorityQueue) Push(x any) {
34+
n := len(*pq)
35+
item := x.(*boardstate)
36+
item.index = n
37+
*pq = append(*pq, item)
38+
}
39+
func (pq *PriorityQueue) Pop() any {
40+
old := *pq
41+
n := len(old)
42+
item := old[n-1]
43+
old[n-1] = nil // don't stop the GC from reclaiming the item eventually
44+
item.index = -1 // for safety
45+
*pq = old[0 : n-1]
46+
return item
47+
}
48+
49+
func solve(mm map[[2]int]byte, start, end [2]int, maxx, maxy int) []boardstate {
50+
cur := start
51+
move := 0
52+
_ = move
53+
54+
pq := make(PriorityQueue, 1)
55+
pq[0] = &boardstate{0, mm, [][2]int{cur}}
56+
heap.Init(&pq)
57+
58+
for pq.Len() > 0 {
59+
e := heap.Pop(&pq).(*boardstate)
60+
61+
a:
62+
for _, d := range dirs {
63+
newpos := [2]int{e.moves[len(e.moves)-1][0] + d[0], e.moves[len(e.moves)-1][1] + d[1]}
64+
if newpos == end {
65+
return []boardstate{{0, e.mm, append(e.moves, newpos)}}
66+
}
67+
c := mm[newpos]
68+
if c == '#' {
69+
// it's a wall
70+
continue
71+
}
72+
if c == '.' {
73+
for _, v := range e.moves {
74+
if newpos == v {
75+
continue a
76+
}
77+
}
78+
heap.Push(&pq, &boardstate{0, e.mm, append(e.moves, newpos)})
79+
}
80+
}
81+
}
82+
return nil
83+
}
84+
85+
func day20(file string) (part1, part2 int) {
86+
f, err := os.Open(file)
87+
if err != nil {
88+
log.Fatal(err)
89+
}
90+
defer f.Close()
91+
scanner := bufio.NewScanner(f)
92+
93+
mm := make(map[[2]int]byte)
94+
start := [2]int{}
95+
end := [2]int{}
96+
maxx := 0
97+
y := 0
98+
for scanner.Scan() {
99+
t := scanner.Text()
100+
_ = t
101+
maxx = len(t)
102+
for x, c := range t {
103+
if c == 'S' {
104+
start = [2]int{x, y}
105+
mm[[2]int{x, y}] = '.'
106+
continue
107+
} else if c == 'E' {
108+
end = [2]int{x, y}
109+
mm[[2]int{x, y}] = '.'
110+
continue
111+
} else if c == '#' {
112+
mm[[2]int{x, y}] = '#'
113+
continue
114+
}
115+
mm[[2]int{x, y}] = '.'
116+
}
117+
y++
118+
}
119+
_ = start
120+
_ = end
121+
out := solve(mm, start, end, maxx, y)
122+
// log.Printf("%+v\n", out[0].moves)
123+
nocheat := len(out[0].moves) - 1
124+
part1 = nocheat
125+
126+
moves := out[0].moves
127+
128+
path := map[[2]int]int{}
129+
for k, move := range moves {
130+
path[move] = k
131+
}
132+
133+
counts := make(map[int]int)
134+
shortcuts := make(map[[4]int]int)
135+
for k, move := range moves {
136+
for _, d1 := range dirs {
137+
newpos1 := [2]int{move[0] + d1[0], move[1] + d1[1]}
138+
if mm[newpos1] == '#' {
139+
for _, d2 := range dirs {
140+
newpos2 := [2]int{newpos1[0] + d2[0], newpos1[1] + d2[1]}
141+
s, ok := path[newpos2]
142+
if s > k+2 && ok {
143+
144+
startpos := move
145+
endpos := newpos2
146+
saved := s - k - 2
147+
148+
first, ok := shortcuts[[4]int{startpos[0], startpos[1], endpos[0], endpos[1]}]
149+
if ok {
150+
if first <= saved {
151+
continue
152+
}
153+
}
154+
// fmt.Println("Found shortcut", startpos, endpos, saved)
155+
156+
shortcuts[[4]int{startpos[0], startpos[1], endpos[0], endpos[1]}] = saved
157+
158+
}
159+
}
160+
}
161+
}
162+
}
163+
for _, v := range shortcuts {
164+
counts[v]++
165+
if v >= 100 {
166+
part2++
167+
}
168+
}
169+
// fmt.Println(counts)
170+
return
171+
}
172+
173+
func main() {
174+
log.SetFlags(log.Lshortfile | log.LstdFlags)
175+
t1 := time.Now()
176+
part1, part2 := day20("test.txt")
177+
fmt.Println(part1, part2)
178+
if part1 != 84 || part2 != 0 {
179+
log.Fatal("Test failed ", part1, part2)
180+
}
181+
fmt.Println(day20("input.txt"))
182+
fmt.Println("Elapsed time:", time.Since(t1))
183+
}

angch/2024-20/test.txt

Lines changed: 15 additions & 0 deletions
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+
###############

0 commit comments

Comments
 (0)