Skip to content

Commit a99c3c3

Browse files
committed
day 13 solution, part 1 & 2
1 parent bffdb79 commit a99c3c3

File tree

6 files changed

+1000
-0
lines changed

6 files changed

+1000
-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.

day13/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: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package org.adventofcode
2+
3+
import java.io.File
4+
5+
data class Dot(val col: Int, val row: Int)
6+
sealed class FoldAction {
7+
data class FoldLeft(val fromColumn: Int) : FoldAction()
8+
data class FoldUp(val fromRow: Int) : FoldAction()
9+
}
10+
11+
typealias DotSet = Set<Dot>
12+
13+
fun DotSet.width(): Int {
14+
return if (this.isEmpty()) 0 else this.maxOf { it.col } + 1
15+
}
16+
17+
fun DotSet.height(): Int {
18+
return if (this.isEmpty()) 0 else this.maxOf { it.row } + 1
19+
}
20+
21+
fun DotSet.splitByRow(row: Int): Pair<DotSet, DotSet> {
22+
val initState = setOf<Dot>() to setOf<Dot>()
23+
return this.fold(initState) { (aboveRowGroup, belowRowGroup), dot ->
24+
when {
25+
dot.row < row -> aboveRowGroup + dot to belowRowGroup
26+
dot.row > row -> aboveRowGroup to belowRowGroup + dot
27+
else -> error("Invalid condition $row $dot")
28+
}
29+
}
30+
}
31+
32+
fun DotSet.splitByColumn(col: Int): Pair<DotSet, DotSet> {
33+
val initState = setOf<Dot>() to setOf<Dot>()
34+
return this.fold(initState) { (leftColumnGroup, rightColumnGroup), dot ->
35+
when {
36+
dot.col < col -> leftColumnGroup + dot to rightColumnGroup
37+
dot.col > col -> leftColumnGroup to rightColumnGroup + dot
38+
else -> error("Invalid condition $col $dot")
39+
}
40+
}
41+
}
42+
43+
data class Paper(val dots: DotSet, val foldWidth: Int? = null, val foldHeight: Int? = null) {
44+
val width by lazy { foldWidth?.let { it } ?: dots.width() }
45+
val height by lazy { foldHeight?.let { it } ?: dots.height() }
46+
}
47+
48+
fun Paper.foldUp(row: Int): Paper {
49+
val (dotsAboveFold, dotsBelowFold) = this.dots.splitByRow(row)
50+
val foldedDots = dotsBelowFold.fold(dotsAboveFold.toSet()) { set, dot ->
51+
val foldedDot = Dot(dot.col, row - (dot.row - row))
52+
set + foldedDot
53+
}
54+
return Paper(foldedDots, this.width, row)
55+
}
56+
57+
fun Paper.foldLeft(col: Int): Paper {
58+
val (dotsLeftOfFold, dotsRightOfFold) = this.dots.splitByColumn(col)
59+
val foldedRightDots = dotsRightOfFold.map {
60+
Dot(it.col - col - 1, it.row)
61+
}
62+
val foldedDots = dotsLeftOfFold.fold(foldedRightDots.toSet()) { set, dot ->
63+
val foldedDot = Dot(col - dot.col - 1, dot.row)
64+
set + foldedDot
65+
}
66+
return Paper(foldedDots, col, this.height)
67+
}
68+
69+
fun Paper.fold(foldAction: FoldAction): Paper {
70+
return when (foldAction) {
71+
is FoldAction.FoldUp -> foldUp(foldAction.fromRow)
72+
is FoldAction.FoldLeft -> foldLeft(foldAction.fromColumn)
73+
}
74+
}
75+
76+
fun Paper.flipVertically(): Paper {
77+
val midCol = this.width / 2
78+
val flippedDots = this.dots.map {
79+
val col = if (it.col > midCol) {
80+
midCol - (it.col - midCol)
81+
} else midCol + (midCol - it.col)
82+
Dot(col, it.row)
83+
}
84+
return this.copy(dots = flippedDots.toSet())
85+
}
86+
87+
fun Paper.prettyPrint(fold: FoldAction? = null) {
88+
val dotset = this.dots.toSet()
89+
(0 until height).forEach { row ->
90+
(0 until width)
91+
.joinToString("") { col -> when {
92+
fold is FoldAction.FoldUp && fold.fromRow == row -> "-"
93+
fold is FoldAction.FoldLeft && fold.fromColumn == col -> "|"
94+
Dot(col, row) in dotset -> "#"
95+
else -> "."
96+
} }
97+
.also { println(it) }
98+
}
99+
}
100+
101+
val FOLD_ACTION_REGEX_PATTERN = """fold along (\w)=(\d+)""".toRegex()
102+
103+
object InputParser {
104+
105+
fun fromFile(pathname: String): Pair<List<Dot>, List<FoldAction>> {
106+
val rawInput = File(pathname).readLines()
107+
val groups = mutableListOf(mutableListOf<String>())
108+
rawInput.forEach { input ->
109+
if (input.isEmpty()) {
110+
groups.add(mutableListOf())
111+
} else {
112+
groups.last().add(input)
113+
}
114+
}
115+
val dots = groups.first().map {
116+
val parts = it.split(",").map(String::toInt)
117+
Dot(parts.first(), parts.last())
118+
}
119+
val folds = groups.last().mapNotNull {
120+
val result = FOLD_ACTION_REGEX_PATTERN.matchEntire(it)
121+
result?.groupValues?.let { (_, direction, position) -> when (direction) {
122+
"y" -> FoldAction.FoldUp(position.toInt())
123+
"x" -> FoldAction.FoldLeft(position.toInt())
124+
else -> error("Unknown fold direction $direction")
125+
} }
126+
}
127+
return dots to folds
128+
}
129+
130+
}
131+
132+
fun runSolutionPart1(dots: DotSet, foldActions: List<FoldAction>) {
133+
println("Day 13 Solution: Part 1\n")
134+
135+
val paper = Paper(dots)
136+
val foldedPaper = paper.fold(foldActions.first())
137+
138+
println("visible dots: ${foldedPaper.dots.size}")
139+
}
140+
141+
fun runSolutionPart2(dots: DotSet, foldActions: List<FoldAction>) {
142+
println("Day 13 Solution: Part 2\n")
143+
144+
val initPaper = Paper(dots)
145+
val foldedPaper = foldActions.fold(initPaper) { paper, action -> paper.fold(action) }
146+
147+
foldedPaper.flipVertically().prettyPrint()
148+
}
149+
150+
fun main() {
151+
val (dots, foldActions) = InputParser.fromFile("day13/src/main/resources/puzzleInput.txt")
152+
// runSolutionPart1(dots.toSet(), foldActions)
153+
runSolutionPart2(dots.toSet(), foldActions)
154+
}

0 commit comments

Comments
 (0)