Skip to content

Commit 7768cff

Browse files
committed
Solution for 2023, day 23
1 parent 439c708 commit 7768cff

File tree

5 files changed

+266
-0
lines changed

5 files changed

+266
-0
lines changed

2023/23/Makefile

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
input:
2+
http "https://adventofcode.com/2023/day/23/input" "Cookie:session=${AOC_SESSION};" >input
3+
4+
main1:
5+
go build -o main1 main1.go common.go graph.go
6+
7+
main2:
8+
go build -o main2 main2.go common.go graph.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
20+

2023/23/common.go

+198
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"fmt"
6+
"maps"
7+
"os"
8+
"slices"
9+
)
10+
11+
type Direction uint8
12+
13+
const (
14+
N Direction = iota
15+
E
16+
S
17+
W
18+
)
19+
20+
type P struct{ x, y int }
21+
22+
var delta = map[Direction]P{
23+
N: {-1, 0},
24+
E: {0, 1},
25+
S: {1, 0},
26+
W: {0, -1},
27+
}
28+
29+
func (p P) Step(dir Direction) P {
30+
return P{p.x + delta[dir].x, p.y + delta[dir].y}
31+
}
32+
33+
type Grid struct {
34+
grid []string
35+
Start, End P
36+
Width, Height int
37+
}
38+
39+
func (g Grid) OOB(p P) bool {
40+
return p.x < 0 || p.x >= len(g.grid) || p.y < 0 || p.y >= len(g.grid[0])
41+
}
42+
43+
func (g Grid) Get(p P) uint8 {
44+
return g.grid[p.x][p.y]
45+
}
46+
47+
func parse() Grid {
48+
var g Grid
49+
scanner := bufio.NewScanner(os.Stdin)
50+
for scanner.Scan() {
51+
g.grid = append(g.grid, scanner.Text())
52+
}
53+
g.Height = len(g.grid)
54+
g.Width = len(g.grid[0])
55+
g.Start = P{0, 1}
56+
g.End = P{g.Height - 1, g.Width - 2}
57+
return g
58+
}
59+
60+
func main() {
61+
grid := parse()
62+
nodes := findNodes(grid)
63+
64+
graph := NewGraph()
65+
graph.AddNode(grid.Start)
66+
graph.AddNode(grid.End)
67+
for _, n := range nodes {
68+
graph.AddNode(n)
69+
}
70+
71+
for a := range graph {
72+
for b := range graph {
73+
if a != b {
74+
dist := distance(a, b, grid, graph, 0, map[P]struct{}{}, IgnoreSlopes)
75+
if dist != -1 {
76+
graph.AddEdge(a, b, dist)
77+
}
78+
}
79+
}
80+
}
81+
82+
fmt.Println(slices.Max(dfs(grid.Start, 0, graph, grid.End, map[P]struct{}{grid.Start: {}})))
83+
}
84+
85+
func findNodes(grid Grid) []P {
86+
var nodes []P
87+
88+
for i := 0; i < grid.Height; i++ {
89+
for j := 0; j < grid.Width; j++ {
90+
p := P{i, j}
91+
92+
if grid.Get(p) == '#' {
93+
continue
94+
}
95+
96+
adj := countAdjacent(grid, p)
97+
98+
if adj > 2 {
99+
nodes = append(nodes, p)
100+
}
101+
}
102+
}
103+
return nodes
104+
}
105+
106+
func countAdjacent(grid Grid, p P) int {
107+
count := 0
108+
for _, dir := range []Direction{N, E, S, W} {
109+
adj := p.Step(dir)
110+
if !grid.OOB(adj) && grid.Get(adj) != '#' {
111+
count++
112+
}
113+
}
114+
return count
115+
}
116+
117+
func distance(from, to P, grid Grid, graph Graph, weight int, visited map[P]struct{}, ignoreSlopes bool) int {
118+
visited[from] = struct{}{}
119+
120+
if from == to {
121+
return weight
122+
}
123+
124+
maxDistance := -1
125+
for _, dir := range []Direction{N, E, S, W} {
126+
127+
adj := from.Step(dir)
128+
129+
if _, ok := visited[adj]; ok {
130+
continue
131+
}
132+
133+
if grid.OOB(adj) {
134+
continue
135+
}
136+
137+
dest := grid.Get(adj)
138+
139+
if dest == '#' {
140+
continue
141+
}
142+
143+
if !ignoreSlopes {
144+
if dest == 'v' && dir != S {
145+
continue
146+
}
147+
148+
if dest == '^' && dir != N {
149+
continue
150+
}
151+
152+
if dest == '>' && dir != E {
153+
continue
154+
}
155+
156+
if dest == '<' && dir != W {
157+
continue
158+
}
159+
}
160+
161+
if !graph.IsNode(adj) {
162+
visited := maps.Clone(visited)
163+
distance := distance(adj, to, grid, graph, weight+1, visited, ignoreSlopes)
164+
if distance > maxDistance {
165+
maxDistance = distance
166+
}
167+
continue
168+
}
169+
170+
if adj == to {
171+
distance := weight + 1
172+
if distance > maxDistance {
173+
maxDistance = distance
174+
}
175+
}
176+
}
177+
178+
return maxDistance
179+
}
180+
181+
func dfs(start P, score int, graph Graph, goal P, visited map[P]struct{}) []int {
182+
183+
if start == goal {
184+
return []int{score}
185+
}
186+
187+
var scores []int
188+
189+
for _, edge := range graph.GetEdges(start) {
190+
if _, ok := visited[edge.To]; !ok {
191+
visited[edge.To] = struct{}{}
192+
scores = append(scores, dfs(edge.To, score+edge.Weight, graph, goal, visited)...)
193+
delete(visited, edge.To)
194+
}
195+
}
196+
197+
return scores
198+
}

2023/23/graph.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package main
2+
3+
type Edge struct {
4+
To P
5+
Weight int
6+
}
7+
8+
type Graph map[P]map[Edge]struct{}
9+
10+
func NewGraph() Graph {
11+
return Graph{}
12+
}
13+
14+
func (g Graph) AddNode(p P) {
15+
if _, ok := g[p]; !ok {
16+
g[p] = map[Edge]struct{}{}
17+
}
18+
}
19+
20+
func (g Graph) IsNode(p P) bool {
21+
_, ok := g[p]
22+
return ok
23+
}
24+
25+
func (g Graph) AddEdge(from, to P, weight int) {
26+
if _, ok := g[from]; !ok {
27+
g[from] = map[Edge]struct{}{}
28+
}
29+
if _, ok := g[to]; !ok {
30+
g[to] = map[Edge]struct{}{}
31+
}
32+
33+
g[from][Edge{to, weight}] = struct{}{}
34+
}
35+
36+
func (g Graph) GetEdges(from P) []Edge {
37+
list := []Edge{}
38+
for e := range g[from] {
39+
list = append(list, e)
40+
}
41+
return list
42+
}

2023/23/main1.go

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package main
2+
3+
const IgnoreSlopes = false

2023/23/main2.go

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package main
2+
3+
const IgnoreSlopes = true

0 commit comments

Comments
 (0)