aboutsummaryrefslogtreecommitdiff
path: root/src/Day13.kt
blob: f37c527e6dc4c4fe2a0fe14ce24d4decf0f28c4d (plain)
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
100
101
102
import java.lang.IllegalStateException

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(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()
    }
}

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 main() {
    fun part1(input: List<String>): Int {
        val (dots, commands) = parseOrigami(input)

        val res = commands.first().dispatch(dots).size

        return res
    }

    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("") }
    }


    val testInput = readInputAsLines("Day13_test")
    check(part1(testInput) == 17)

    val input = readInputAsLines("Day13")
    println(part1(input))
    println(part2(input))
}