Skip to content

Commit 4fcb61c

Browse files
committed
day 12, part 1 solution
1 parent 14b610f commit 4fcb61c

File tree

8 files changed

+250
-0
lines changed

8 files changed

+250
-0
lines changed

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

day12/build.gradle.kts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
plugins {
2+
id("org.adventofcode.kotlin-application-conventions")
3+
}
4+
5+
dependencies {
6+
7+
}
8+
9+
application {
10+
mainClass.set("org.adventofcode.AppKt")
11+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package org.adventofcode
2+
3+
import java.io.File
4+
5+
sealed class Node {
6+
7+
abstract infix fun compareTo(other: Node): Int
8+
9+
companion object {
10+
fun fromString(s: String): Node = when {
11+
s == "start" -> Node.Start
12+
s == "end" -> Node.End
13+
s.matches("""[A-Z]+""".toRegex()) -> Node.Large(s)
14+
s.matches("""[a-z]+""".toRegex()) -> Node.Small(s)
15+
else -> error("Invalid node value $s")
16+
}
17+
}
18+
19+
object Start : Node() {
20+
override fun toString(): String = "Node.Start"
21+
override infix fun compareTo(other: Node): Int = when (other) {
22+
Start -> 0
23+
else -> 1
24+
}
25+
}
26+
27+
object End : Node() {
28+
override fun toString(): String = "Node.End"
29+
override infix fun compareTo(other: Node): Int = when (other) {
30+
End -> 0
31+
else -> -1
32+
}
33+
}
34+
35+
data class Large(val value: String) : Node() {
36+
override infix fun compareTo(other: Node): Int = when (other) {
37+
Start -> -1
38+
End -> 1
39+
is Large -> this.value.compareTo(other.value) * -1
40+
is Small -> 1
41+
}
42+
}
43+
44+
data class Small(val value: String) : Node() {
45+
override infix fun compareTo(other: Node): Int = when (other) {
46+
Start -> -1
47+
End -> 1
48+
is Large -> -1
49+
is Small -> this.value.compareTo(other.value) * -1
50+
}
51+
}
52+
53+
}
54+
55+
data class Edge(val first: Node, val second: Node) {
56+
constructor(pair: Pair<Node, Node>) : this(pair.first, pair.second)
57+
}
58+
59+
typealias EdgeList = List<Edge>
60+
61+
operator fun Edge.contains(n: Node): Boolean {
62+
return n == first || n == second
63+
}
64+
65+
fun Edge.nodePairingOrNull(n: Node): Node? {
66+
return when(n) {
67+
first -> second
68+
second -> first
69+
else -> null
70+
}
71+
}
72+
73+
fun Edge.toNodeList(): List<Node> {
74+
return listOf(first, second)
75+
}
76+
77+
fun EdgeList.toNodeMap(): Map<Node, Set<Node>> {
78+
return this.fold<Edge, Map<Node, Set<Node>>>(mapOf()) { mapping, edge ->
79+
mapping + edge.toNodeList().map { n1 ->
80+
val n1connections = edge.nodePairingOrNull(n1)?.let { n2 ->
81+
val set = mapping.getOrElse(n1) { setOf() }
82+
when (n2) {
83+
Node.Start -> set
84+
else -> set + n2
85+
}
86+
} ?: setOf()
87+
n1 to n1connections
88+
}
89+
}.filter { (key) -> key != Node.End }
90+
}
91+
92+
typealias Path = List<Node>
93+
94+
fun Path.toCompactString(): String {
95+
return this.joinToString(",") {
96+
when (it) {
97+
Node.Start -> "start"
98+
Node.End -> "end"
99+
is Node.Small -> it.value
100+
is Node.Large -> it.value
101+
}
102+
}
103+
}
104+
105+
infix fun Path.compareTo(other: Path): Int {
106+
return when {
107+
this.isEmpty() && other.isEmpty() -> 0
108+
this.isEmpty() && other.isNotEmpty() -> 1
109+
this.isNotEmpty() && other.isEmpty() -> -1
110+
else -> {
111+
when (val comparedResult = this.first() compareTo other.first()) {
112+
0 -> this.drop(1) compareTo other.drop(1)
113+
else -> comparedResult
114+
}
115+
}
116+
}
117+
}
118+
119+
data class Graph(val edges: List<Edge>)
120+
121+
fun Graph.walk(
122+
focusNode: Node,
123+
connections: Map<Node, Set<Node>>,
124+
path: Path = listOf(),
125+
smallNodesWalked: Set<Node> = setOf(),
126+
): List<Path> {
127+
if (focusNode == Node.End) {
128+
return listOf(path + focusNode)
129+
}
130+
131+
val nodesToWalk = connections[focusNode] ?: setOf()
132+
val nextSmallNodesWalked = when (focusNode) {
133+
is Node.Small -> smallNodesWalked + focusNode
134+
else -> smallNodesWalked
135+
}
136+
val walkedPath: Path = path + focusNode
137+
138+
return nodesToWalk.mapNotNull { toNode ->
139+
when (toNode) {
140+
in nextSmallNodesWalked -> null
141+
else -> walk(toNode, connections, walkedPath, nextSmallNodesWalked)
142+
}
143+
}.flatten()
144+
}
145+
146+
fun Graph.findAllCompletePaths(): List<Path> {
147+
return walk(Node.Start, edges.toNodeMap())
148+
}
149+
150+
object EdgeListFactory {
151+
fun fromFile(pathname: String): EdgeList {
152+
return File(pathname)
153+
.readLines()
154+
.map { line ->
155+
val (n1value, n2value) = line
156+
.split('-')
157+
.zipWithNext().first()
158+
val n1 = Node.fromString(n1value)
159+
val n2 = Node.fromString(n2value)
160+
Edge(n1, n2)
161+
}
162+
}
163+
}
164+
165+
fun main() {
166+
val edges = EdgeListFactory.fromFile("day12/src/main/resources/puzzleInput.txt")
167+
val graph = Graph(edges)
168+
val paths = graph.findAllCompletePaths()
169+
170+
paths
171+
.sortedWith { p1, p2 -> p1 compareTo p2 }
172+
.reversed()
173+
.forEach { println(it.toCompactString()) }
174+
175+
println()
176+
println("# paths: ${paths.size}")
177+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
DA-xn
2+
KD-ut
3+
gx-ll
4+
dj-PW
5+
xn-dj
6+
ll-ut
7+
xn-gx
8+
dg-ak
9+
DA-start
10+
ut-gx
11+
YM-ll
12+
dj-DA
13+
ll-xn
14+
dj-YM
15+
start-PW
16+
dj-start
17+
PW-gx
18+
YM-gx
19+
xn-ak
20+
PW-ak
21+
xn-PW
22+
YM-end
23+
end-ll
24+
ak-end
25+
ak-DA
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
start-A
2+
start-b
3+
A-c
4+
A-b
5+
b-d
6+
A-end
7+
b-end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
dc-end
2+
HN-start
3+
start-kj
4+
dc-start
5+
dc-HN
6+
LN-dc
7+
HN-end
8+
kj-sa
9+
kj-HN
10+
kj-dc
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
fs-end
2+
he-DX
3+
fs-he
4+
start-DX
5+
pj-DX
6+
end-zg
7+
zg-sl
8+
zg-pj
9+
pj-he
10+
RW-he
11+
fs-DX
12+
pj-RW
13+
zg-RW
14+
start-pj
15+
he-WI
16+
zg-he
17+
pj-fs
18+
start-RW

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ include(
2020
"day09",
2121
"day10",
2222
"day11",
23+
"day12",
2324
)

0 commit comments

Comments
 (0)