1
+ package day12
2
+
3
+ import shared.Point
4
+
5
+
6
+ class Day12 {
7
+
8
+ companion object {
9
+
10
+ fun part1 (input : List <String >): Int {
11
+ val graph = parseInput(input)
12
+
13
+ val start = graph.find {
14
+ it.char == ' S'
15
+ }!!
16
+ val target = graph.find {
17
+ it.char == ' E'
18
+ }!!
19
+
20
+ val distances = findShortestPath(graph, start)
21
+ return distances[target] ? : - 1
22
+ }
23
+
24
+ fun part2 (input : List <String >): Int {
25
+ // val graph = parseInput(input)
26
+ //
27
+ // val start = graph.find {
28
+ // it.char == 'E'
29
+ // }!!
30
+ //
31
+ // val distances = findShortestPath(graph, start)
32
+ //
33
+ // return distances.filter {
34
+ // it.key.char == 'a'
35
+ // }.values.minOrNull() ?: -1
36
+
37
+
38
+ // val graph = parseInput(input)
39
+ //
40
+ // val starts = graph.filter {
41
+ // it.char == 'a'
42
+ // }.toList()
43
+ //
44
+ //
45
+ // val target = graph.find {
46
+ // it.char == 'E'
47
+ // }!!
48
+ // var min = Int.MAX_VALUE
49
+ //
50
+ // for (start in starts) {
51
+ // val distances = findShortestPath(graph, start)
52
+ // val newMin = distances[target] ?: Int.MAX_VALUE
53
+ //
54
+ // if (newMin < min) {
55
+ // min = newMin
56
+ // }
57
+ // }
58
+ // return min
59
+
60
+ return - 1
61
+ }
62
+
63
+ private fun findShortestPath (locations : List <Location >, start : Location ): Map <Location , Int > {
64
+ val distances = mutableMapOf<Location , Int >()
65
+ val pathStartToAny = mutableMapOf<Location , Location ?>()
66
+
67
+ // Initialize
68
+ locations.forEach {
69
+ distances[it] = Int .MAX_VALUE
70
+ pathStartToAny[it] = null
71
+ }
72
+
73
+ // Set distance from start node to 0
74
+ distances[start] = 0
75
+
76
+ val queue = locations.toMutableList()
77
+
78
+ while (queue.isNotEmpty()) {
79
+ val u = extractMin(queue, distances)
80
+ queue.remove(u)
81
+
82
+ for ((neighbor, distance) in u.neighbors) {
83
+ // Relaxation
84
+ if (distances[neighbor]!! > distances[u]!! + distance) {
85
+ distances[neighbor] = distances[u]!! + distance
86
+ pathStartToAny[neighbor] = u
87
+ }
88
+ }
89
+ }
90
+
91
+ return distances
92
+ }
93
+
94
+ private fun extractMin (queue : List <Location >, distances : Map <Location , Int >): Location {
95
+ var min = queue[0 ]
96
+
97
+ for (location in queue) {
98
+ if (distances[location]!! < distances[min]!! ) {
99
+ min = location
100
+ }
101
+ }
102
+ return min
103
+ }
104
+
105
+ data class Location (val char : Char , val point : Point ) {
106
+ val neighbors = mutableMapOf<Location , Int >() // Target, distance
107
+
108
+ fun addNeighbor (possibleNeighbor : Location ) {
109
+ // Only allow movement to smaller or at most 1 higher
110
+ if (possibleNeighbor.elevation() <= elevation() + 1 ) {
111
+ neighbors[possibleNeighbor] = 1
112
+ }
113
+ }
114
+
115
+ private fun elevation (): Char = when (char) {
116
+ ' S' -> ' a'
117
+ ' E' -> ' z'
118
+ else -> char
119
+ }
120
+ }
121
+
122
+ private fun parseInput (input : List <String >): List <Location > {
123
+ val locationsMap = mutableListOf<List <Location >>()
124
+
125
+ // Create nodes
126
+ input.forEachIndexed { y, row ->
127
+ val locationsRow = mutableListOf<Location >()
128
+ row.forEachIndexed { x, char ->
129
+ locationsRow.add(Location (char, Point (x, y)))
130
+ }
131
+ locationsMap.add(locationsRow)
132
+ }
133
+
134
+
135
+ // Set neighbors
136
+ val lastYIndex = locationsMap.lastIndex
137
+ val lastXIndex = locationsMap[0 ].lastIndex
138
+
139
+ locationsMap.forEachIndexed { y, row ->
140
+ row.forEachIndexed { x, location ->
141
+ if (y > 0 ) {
142
+ location.addNeighbor(locationsMap[y - 1 ][x])
143
+ }
144
+ if (y < lastYIndex) {
145
+ location.addNeighbor(locationsMap[y + 1 ][x])
146
+ }
147
+ if (x > 0 ) {
148
+ location.addNeighbor(locationsMap[y][x - 1 ])
149
+ }
150
+ if (x < lastXIndex) {
151
+ location.addNeighbor(locationsMap[y][x + 1 ])
152
+ }
153
+ }
154
+ }
155
+
156
+ return locationsMap.flatten()
157
+ }
158
+ }
159
+ }
0 commit comments