1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
object Day13 {
private sealed class FoldCommand {
abstract fun dispatch(dots: Set<Pos2D>): Set<Pos2D>
class AlongX(private val x: Int) : FoldCommand() {
override fun dispatch(dots: Set<Pos2D>): Set<Pos2D> = dots
.filter { it.x != x }
.map {
if (it.x < x) {
it
} else {
Pos2D(2 * x - it.x, it.y)
}
}
.toSet()
}
class AlongY(private val y: Int) : FoldCommand() {
override fun dispatch(dots: Set<Pos2D>): Set<Pos2D> = dots
.filter { it.y != y }
.map {
if (it.y < y) {
it
} else {
Pos2D(it.x, 2 * y - it.y)
}
}
.toSet()
}
}
private fun parseOrigami(input: List<String>): Pair<Set<Pos2D>, Sequence<FoldCommand>> {
val dots = mutableSetOf<Pos2D>()
val commands = mutableListOf<FoldCommand>()
for (line in input) {
if (line.matches("\\d+,\\d+".toRegex())) {
val (x, y) = line.split(",").map(String::toInt)
dots.add(Pos2D(x, y))
}
if (line.matches("fold along [xy]=\\d+".toRegex())) {
val equation = line.substring(11)
val (axis, valueString) = equation.split("=")
val value = valueString.toInt()
commands.add(
when (axis) {
"x" -> FoldCommand.AlongX(value)
"y" -> FoldCommand.AlongY(value)
else -> throw IllegalStateException("Illegal axis given!")
}
)
}
}
return dots to commands.asSequence()
}
fun part1(input: List<String>): Int {
val (dots, commands) = parseOrigami(input)
return commands.first().dispatch(dots).size
}
fun part2(input: List<String>): String {
val origami = parseOrigami(input)
var dots = origami.first
val commands = origami.second
commands.forEach {
dots = it.dispatch(dots)
}
val bounds = dots.reduce { max, pos ->
when ((pos.x > max.x) to (pos.y > max.y)) {
true to true -> pos
true to false -> Pos2D(pos.x, max.y)
false to true -> Pos2D(max.x, pos.y)
else -> max
}
}
val lines = Array(bounds.y + 1) { Array(bounds.x + 1) { ' ' } }
dots.forEach { lines[it.y][it.x] = '#' }
return lines.joinToString("\n") { it.joinToString("") }
}
}
fun main() {
val testInput = readInputAsLines("Day13_test")
check(Day13.part1(testInput) == 17)
val input = readInputAsLines("Day13")
println(Day13.part1(input))
println(Day13.part2(input))
}
|