aboutsummaryrefslogtreecommitdiff
path: root/aoc-2021-kotlin/src/Day13.kt
blob: 0f9b09687e4a031fc48ce3a4f43e158ca647a01a (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
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))
}