Skip to content

Commit 56fbd06

Browse files
committed
24th day
1 parent 3b6949b commit 56fbd06

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

day24/day24.go

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
. "majcn.si/advent-of-code-2022/util"
8+
)
9+
10+
type Blizzard struct {
11+
Location
12+
Direction byte
13+
}
14+
15+
type DataType struct {
16+
Blizzards []Blizzard
17+
MapSizeX int
18+
MapSizeY int
19+
}
20+
21+
func parseData(data string) DataType {
22+
dataSplit := strings.Split(data, "\n")
23+
24+
result := DataType{
25+
Blizzards: []Blizzard{},
26+
MapSizeX: len(dataSplit[0]),
27+
MapSizeY: len(dataSplit),
28+
}
29+
30+
for y, line := range dataSplit {
31+
for x, v := range line {
32+
switch v {
33+
case '^', 'v', '<', '>':
34+
result.Blizzards = append(result.Blizzards, Blizzard{Location: Location{X: x, Y: y}, Direction: byte(v)})
35+
}
36+
}
37+
}
38+
39+
return result
40+
}
41+
42+
type GraphNode struct {
43+
Location
44+
BlizzardsIndex int
45+
}
46+
47+
type QueueNode struct {
48+
GraphNode
49+
Time int
50+
}
51+
52+
func bfs(startNode GraphNode, endLocation Location, getNeighborsF func(node GraphNode, startLocation, endLocation Location) []GraphNode) (int, GraphNode) {
53+
queue := make([]QueueNode, 0)
54+
visited := make(Set[GraphNode])
55+
56+
queue = append(queue, QueueNode{GraphNode: startNode, Time: 0})
57+
visited.Add(startNode)
58+
for len(queue) > 0 {
59+
queueEl := queue[0]
60+
queue = queue[1:]
61+
62+
node := queueEl.GraphNode
63+
64+
if node.Location == endLocation {
65+
return queueEl.Time, queueEl.GraphNode
66+
}
67+
68+
for _, neighbor := range getNeighborsF(node, startNode.Location, endLocation) {
69+
if !visited.Contains(neighbor) {
70+
queue = append(queue, QueueNode{GraphNode: neighbor, Time: queueEl.Time + 1})
71+
visited.Add(neighbor)
72+
}
73+
}
74+
}
75+
76+
return MaxInt, GraphNode{}
77+
}
78+
79+
func getNeighbors(node GraphNode, mapSizeX int, mapSizeY int, getBlizzardLocations func(i int) Set[Location], startLocation Location, endLocation Location) []GraphNode {
80+
result := make([]GraphNode, 0, 5)
81+
82+
neighbours := append(GetNeighbours4(), Location{X: 0, Y: 0})
83+
84+
newBlizzardsIndex := node.BlizzardsIndex + 1
85+
newBlizzards := getBlizzardLocations(newBlizzardsIndex)
86+
for _, neighbor := range neighbours {
87+
newLocation := node.Location.Add(neighbor)
88+
89+
if newLocation == endLocation {
90+
return []GraphNode{{Location: newLocation, BlizzardsIndex: newBlizzardsIndex}}
91+
}
92+
93+
if !newBlizzards.Contains(newLocation) {
94+
if newLocation == startLocation || newLocation.X > 0 && newLocation.X < mapSizeX-1 && newLocation.Y > 0 && newLocation.Y < mapSizeY-1 {
95+
result = append(result, GraphNode{
96+
Location: newLocation,
97+
BlizzardsIndex: newBlizzardsIndex,
98+
})
99+
}
100+
}
101+
}
102+
103+
return result
104+
}
105+
106+
func getBlizzardLocations(mapSizeX int, mapSizeY int, blizzards []Blizzard, time int) Set[Location] {
107+
xBlizzardPath := mapSizeX - 2
108+
yBlizzardPath := mapSizeY - 2
109+
110+
result := make(Set[Location])
111+
for _, blizzard := range blizzards {
112+
switch blizzard.Direction {
113+
case '^':
114+
result.Add(Location{X: blizzard.X, Y: Mod(blizzard.Y-1-time, yBlizzardPath) + 1})
115+
case 'v':
116+
result.Add(Location{X: blizzard.X, Y: Mod(blizzard.Y-1+time, yBlizzardPath) + 1})
117+
case '<':
118+
result.Add(Location{X: Mod(blizzard.X-1-time, xBlizzardPath) + 1, Y: blizzard.Y})
119+
case '>':
120+
result.Add(Location{X: Mod(blizzard.X-1+time, xBlizzardPath) + 1, Y: blizzard.Y})
121+
}
122+
}
123+
124+
return result
125+
}
126+
127+
func solvePartX(data DataType, paths []Location) (rc int) {
128+
mapSizeX, mapSizeY, blizzards := data.MapSizeX, data.MapSizeY, data.Blizzards
129+
allBlizzardLocations := make(map[int]Set[Location])
130+
131+
getBlizzardLocationsF := func(i int) Set[Location] {
132+
if _, ok := allBlizzardLocations[i]; ok {
133+
return allBlizzardLocations[i]
134+
}
135+
136+
blizzardLocations := getBlizzardLocations(mapSizeX, mapSizeY, blizzards, i)
137+
allBlizzardLocations[i] = blizzardLocations
138+
return blizzardLocations
139+
}
140+
141+
getNeighborsF := func(node GraphNode, startLocation, endLocation Location) []GraphNode {
142+
return getNeighbors(node, mapSizeX, mapSizeY, getBlizzardLocationsF, startLocation, endLocation)
143+
}
144+
145+
currentBlizzardIndex := 0
146+
node := GraphNode{Location: paths[0], BlizzardsIndex: currentBlizzardIndex}
147+
for _, p := range paths[1:] {
148+
time, goalNode := bfs(node, p, getNeighborsF)
149+
150+
node = goalNode
151+
rc += time
152+
}
153+
154+
return
155+
}
156+
157+
func solvePart1(data DataType) (rc int) {
158+
mapSizeX, mapSizeY := data.MapSizeX, data.MapSizeY
159+
160+
path := []Location{
161+
{X: 1, Y: 0},
162+
{X: mapSizeX - 2, Y: mapSizeY - 1},
163+
}
164+
165+
return solvePartX(data, path)
166+
}
167+
168+
func solvePart2(data DataType) (rc int) {
169+
mapSizeX, mapSizeY := data.MapSizeX, data.MapSizeY
170+
171+
path := []Location{
172+
{X: 1, Y: 0},
173+
{X: mapSizeX - 2, Y: mapSizeY - 1},
174+
{X: 1, Y: 0},
175+
{X: mapSizeX - 2, Y: mapSizeY - 1},
176+
}
177+
178+
return solvePartX(data, path)
179+
}
180+
181+
func main() {
182+
data := parseData(FetchInputData(24))
183+
fmt.Println(solvePart1(data))
184+
fmt.Println(solvePart2(data))
185+
}

day24/day24_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
. "majcn.si/advent-of-code-2022/util"
8+
)
9+
10+
func ExpectedPart1() int {
11+
return 18
12+
}
13+
14+
func ExpectedPart2() int {
15+
return 54
16+
}
17+
18+
var data DataType
19+
20+
func init() {
21+
input, _ := os.ReadFile("../examples/24.txt")
22+
data = parseData(string(input))
23+
}
24+
25+
func TestPart1(t *testing.T) {
26+
AssertTestPartX(t, ExpectedPart1(), solvePart1(data))
27+
}
28+
29+
func TestPart2(t *testing.T) {
30+
AssertTestPartX(t, ExpectedPart2(), solvePart2(data))
31+
}

examples/24.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#.######
2+
#>>.<^<#
3+
#.<..<<#
4+
#>v.><>#
5+
#<^v^^>#
6+
######.#

0 commit comments

Comments
 (0)