Skip to content

Commit 427081a

Browse files
committed
Solution for 2024, day 16
1 parent eaffb8a commit 427081a

File tree

5 files changed

+194
-0
lines changed

5 files changed

+194
-0
lines changed

2024/16/Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
input:
2+
http "https://adventofcode.com/2024/day/16/input" "Cookie:session=${AOC_SESSION};" >input
3+
4+
main1:
5+
go build -o main1 main1.go priority_queue.go common.go
6+
7+
main2:
8+
go build -o main2 main2.go priority_queue.go common.go
9+
10+
.PHONY: run1 run2 clean
11+
12+
run1: main1 input
13+
./main1 <input
14+
15+
run2: main2 input
16+
./main2 <input
17+
18+
clean:
19+
rm -f main1 main2 input

2024/16/common.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"container/heap"
6+
"math"
7+
"os"
8+
)
9+
10+
type P struct{ x, y int }
11+
12+
type Direction uint8
13+
14+
func (d Direction) Clockwise() Direction { return (d + 4 + 1) % 4 }
15+
func (d Direction) Counterclockwise() Direction { return (d + 4 - 1) % 4 }
16+
17+
const (
18+
E Direction = iota
19+
S
20+
W
21+
N
22+
)
23+
24+
var Delta = map[Direction]P{N: {-1, 0}, E: {0, 1}, S: {1, 0}, W: {0, -1}}
25+
26+
func parseInput() (map[P]struct{}, P, P) {
27+
var (
28+
m = map[P]struct{}{}
29+
start P
30+
end P
31+
)
32+
33+
scanner := bufio.NewScanner(os.Stdin)
34+
for i := 0; scanner.Scan(); i++ {
35+
for j, ch := range scanner.Text() {
36+
switch ch {
37+
case 'S':
38+
m[P{i, j}] = struct{}{}
39+
start = P{i, j}
40+
case 'E':
41+
m[P{i, j}] = struct{}{}
42+
end = P{i, j}
43+
case '.':
44+
m[P{i, j}] = struct{}{}
45+
case '#':
46+
}
47+
}
48+
}
49+
return m, start, end
50+
}
51+
52+
type Node struct {
53+
Pos P
54+
Direction Direction
55+
}
56+
57+
func Dijkstra(m map[P]struct{}, start, end P) (int, map[Node][]Node) {
58+
var (
59+
minScore = math.MaxInt64
60+
parent = map[Node][]Node{}
61+
)
62+
63+
startNode := Node{start, E}
64+
65+
pq := &priorityQueue{}
66+
heap.Init(pq)
67+
heap.Push(pq, pqNode{startNode, 0})
68+
69+
scores := map[Node]int{startNode: 0}
70+
71+
for pq.Len() > 0 {
72+
curr := heap.Pop(pq).(pqNode)
73+
74+
// we reached the end
75+
if curr.Pos == end {
76+
77+
// stop only when we got over the minScore, as
78+
// we are interested into all the minScore paths
79+
if curr.Score > minScore {
80+
return minScore, parent
81+
}
82+
minScore = curr.Score
83+
}
84+
85+
for _, n := range neighbours(m, curr) {
86+
if _, ok := scores[n.Node]; !ok || n.Score <= scores[n.Node] {
87+
parent[n.Node] = append(parent[n.Node], curr.Node)
88+
scores[n.Node] = n.Score
89+
heap.Push(pq, n)
90+
}
91+
}
92+
}
93+
panic("no path found")
94+
}
95+
96+
func neighbours(m map[P]struct{}, curr pqNode) []pqNode {
97+
list := []pqNode{
98+
{Node{curr.Pos, curr.Direction.Clockwise()}, curr.Score + 1000},
99+
{Node{curr.Pos, curr.Direction.Counterclockwise()}, curr.Score + 1000},
100+
}
101+
102+
delta := Delta[curr.Direction]
103+
if _, ok := m[P{curr.Pos.x + delta.x, curr.Pos.y + delta.y}]; ok {
104+
list = append(list, pqNode{Node{
105+
Pos: P{curr.Pos.x + delta.x, curr.Pos.y + delta.y},
106+
Direction: curr.Direction,
107+
}, curr.Score + 1})
108+
}
109+
110+
return list
111+
}

2024/16/main1.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
score, _ := Dijkstra(parseInput())
7+
fmt.Println(score)
8+
}

2024/16/main2.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package main
2+
3+
import "fmt"
4+
5+
func main() {
6+
m, start, end := parseInput()
7+
_, parent := Dijkstra(m, start, end)
8+
9+
cellVisited := map[P]struct{}{}
10+
dfs(parent, Node{end, N}, map[Node]struct{}{}, cellVisited)
11+
12+
fmt.Println(len(cellVisited))
13+
}
14+
15+
func dfs(parent map[Node][]Node, node Node, visited map[Node]struct{}, cellVisited map[P]struct{}) {
16+
visited[node] = struct{}{}
17+
cellVisited[node.Pos] = struct{}{}
18+
19+
for _, n := range parent[node] {
20+
if _, ok := visited[n]; !ok {
21+
dfs(parent, n, visited, cellVisited)
22+
}
23+
}
24+
}

2024/16/priority_queue.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package main
2+
3+
type pqNode struct {
4+
Node
5+
Score int
6+
}
7+
8+
type priorityQueue []pqNode
9+
10+
func (n priorityQueue) Len() int {
11+
return len(n)
12+
}
13+
14+
func (n priorityQueue) Less(i, j int) bool {
15+
return n[i].Score < n[j].Score
16+
}
17+
18+
func (n priorityQueue) Swap(i, j int) {
19+
n[i], n[j] = n[j], n[i]
20+
}
21+
22+
func (n *priorityQueue) Push(x any) {
23+
*n = append(*n, x.(pqNode))
24+
}
25+
26+
func (n *priorityQueue) Pop() any {
27+
old := *n
28+
l := len(old)
29+
x := old[l-1]
30+
*n = old[0 : l-1]
31+
return x
32+
}

0 commit comments

Comments
 (0)