From 32089ceef2159622f355b2f748648be7dc77ed8c Mon Sep 17 00:00:00 2001 From: Stephan Linkel <251381+norganos@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:05:47 +0100 Subject: [PATCH] day 18 and 19, as well as empty files for days 20-25 --- src/main/kotlin/de/linkel/aoc/Day18.kt | 99 +++--------- src/main/kotlin/de/linkel/aoc/Day19.kt | 167 ++++++++++++++++++++- src/main/kotlin/de/linkel/aoc/Day20.kt | 14 ++ src/main/kotlin/de/linkel/aoc/Day21.kt | 14 ++ src/main/kotlin/de/linkel/aoc/Day22.kt | 14 ++ src/main/kotlin/de/linkel/aoc/Day23.kt | 14 ++ src/main/kotlin/de/linkel/aoc/Day24.kt | 14 ++ src/main/kotlin/de/linkel/aoc/Day25.kt | 14 ++ src/test/kotlin/de/linkel/aoc/Day18Test.kt | 18 ++- src/test/kotlin/de/linkel/aoc/Day19Test.kt | 29 +++- src/test/kotlin/de/linkel/aoc/Day20Test.kt | 13 ++ src/test/kotlin/de/linkel/aoc/Day21Test.kt | 13 ++ src/test/kotlin/de/linkel/aoc/Day22Test.kt | 13 ++ src/test/kotlin/de/linkel/aoc/Day23Test.kt | 13 ++ src/test/kotlin/de/linkel/aoc/Day24Test.kt | 13 ++ src/test/kotlin/de/linkel/aoc/Day25Test.kt | 13 ++ 16 files changed, 392 insertions(+), 83 deletions(-) create mode 100644 src/main/kotlin/de/linkel/aoc/Day20.kt create mode 100644 src/main/kotlin/de/linkel/aoc/Day21.kt create mode 100644 src/main/kotlin/de/linkel/aoc/Day22.kt create mode 100644 src/main/kotlin/de/linkel/aoc/Day23.kt create mode 100644 src/main/kotlin/de/linkel/aoc/Day24.kt create mode 100644 src/main/kotlin/de/linkel/aoc/Day25.kt create mode 100644 src/test/kotlin/de/linkel/aoc/Day20Test.kt create mode 100644 src/test/kotlin/de/linkel/aoc/Day21Test.kt create mode 100644 src/test/kotlin/de/linkel/aoc/Day22Test.kt create mode 100644 src/test/kotlin/de/linkel/aoc/Day23Test.kt create mode 100644 src/test/kotlin/de/linkel/aoc/Day24Test.kt create mode 100644 src/test/kotlin/de/linkel/aoc/Day25Test.kt diff --git a/src/main/kotlin/de/linkel/aoc/Day18.kt b/src/main/kotlin/de/linkel/aoc/Day18.kt index 6827f0c..2a74ab9 100644 --- a/src/main/kotlin/de/linkel/aoc/Day18.kt +++ b/src/main/kotlin/de/linkel/aoc/Day18.kt @@ -2,24 +2,19 @@ package de.linkel.aoc import de.linkel.aoc.base.AbstractLinesAdventDay import de.linkel.aoc.base.QuizPart -import de.linkel.aoc.utils.grid.Grid -import de.linkel.aoc.utils.grid.Point import jakarta.inject.Singleton -import kotlin.math.max -import kotlin.math.min +import kotlin.math.abs @Singleton class Day18: AbstractLinesAdventDay() { override val day = 18 - data class Cube( - val dirIn: Char, - val dirOut: Char - ) data class Point( val x: Long, val y: Long - ) + ) { + override fun toString(): String = "${x}x${y}" + } interface Vector { val deltaX: Long val deltaY: Long @@ -39,17 +34,10 @@ class Day18: AbstractLinesAdventDay() { ): Vector operator fun Point.plus(vector: Vector): Point = Point(this.x + vector.deltaX, this.y + vector.deltaY) operator fun Vector.times(factor: Long): Vector = GenericVector(this.deltaX * factor, this.deltaY * factor) + operator fun Vector.plus(vector: Vector): Vector = GenericVector(this.deltaX + vector.deltaX, this.deltaY + vector.deltaY) override fun process(part: QuizPart, lines: Sequence): Long { - val origin = Point(0L,0L) - val map = mutableMapOf() - var minX = 0L - var minY = 0L - var maxX = 0L - var maxY = 0L -// val map = Grid(origin, Dimension(1,1)) - map[origin] = Cube('0','?') - lines.fold(origin) { pos, line -> + return lines.map { line -> val (dir, len) = if (part == QuizPart.A) { val token = line.split(' ') val dir = Direction.valueOf(token[0]) @@ -61,63 +49,26 @@ class Day18: AbstractLinesAdventDay() { val dir = Direction.entries[hex[5].digitToInt()] dir to len } - val dest = pos + dir * len -// map.stretchTo(dest) - (1L..len).forEach { - map[pos + dir * it] = Cube(line[0], line[0]) - } - minX = min(minX, dest.x) - minY = min(minY, dest.y) - maxX = max(maxX, dest.x) - maxY = max(maxY, dest.y) - map[pos] = map[pos]!!.copy(dirOut = line[0]) - dest + dir * len + }.let { + solve(it.toList()) } + } - var insides = 0L - (minY..maxY) - .forEach { y -> -// var upIn = false -// var downOut = false - var inside = false - (minX..maxX) - .forEach { x -> - val p = Point(x, y) - if (map[p] != null) { -// if (map[p]!!.dirIn == 'D' || map[p]!!.dirOut == 'U') - if (map[p]!!.dirIn == 'U' || map[p]!!.dirOut == 'D') - inside = !inside -// if (map[p]!!.dirIn == 'U') -// upIn = !upIn -// if (map[p]!!.dirOut == 'D') -// downOut = !downOut - } else if (inside) { -// } else if (upIn != downOut) { - insides++ -// map[p] = Cube('#', '#') - } - } - } + private fun points(digPlan: List): List = + digPlan.runningFold(Point(0, 0)) { acc, shiftVector -> + acc + shiftVector + } - return insides + map.size - } - fun printMap(grid: Grid) { - println( - buildString { - (grid.area.y until (grid.area.y + grid.area.height)) - .forEach { y -> - (grid.area.x until (grid.area.x + grid.area.width)) - .forEach { x -> - val p = Point(x, y) - if (grid[p] != null) { - append(grid[p]!!.dirIn) - } else { - append('.') - } - } - append('\n') - } - } - ) - } + private fun perimeterPoints(vectors: List): Long = + vectors.sumOf { abs(it.deltaX) + abs(it.deltaY) } // Manhattan Distance is ok here because we only have 90 degree turns + + private fun shoelaceFormula(corners: List): Long = + corners.zipWithNext().sumOf { (a, b) -> a.x * b.y - a.y * b.x } / 2 + + private fun pickTheorem(area: Long, perimeter: Long): Long = + area + perimeter / 2L + 1L + + private fun solve(digPlan: List): Long + = pickTheorem(shoelaceFormula(points(digPlan)), perimeterPoints(digPlan)) } diff --git a/src/main/kotlin/de/linkel/aoc/Day19.kt b/src/main/kotlin/de/linkel/aoc/Day19.kt index 5f6e002..e4f27b3 100644 --- a/src/main/kotlin/de/linkel/aoc/Day19.kt +++ b/src/main/kotlin/de/linkel/aoc/Day19.kt @@ -2,13 +2,174 @@ package de.linkel.aoc import de.linkel.aoc.base.AbstractLinesAdventDay import de.linkel.aoc.base.QuizPart +import de.linkel.aoc.utils.iterables.intersect import jakarta.inject.Singleton +import java.math.BigInteger @Singleton -class Day19: AbstractLinesAdventDay() { +class Day19: AbstractLinesAdventDay() { override val day = 19 - override fun process(part: QuizPart, lines: Sequence): Int { - return 0 + enum class Op(val char: Char, val lambda: (value: Int, threshold: Int) -> Boolean) { + GT('>', { v, t -> v > t }), + LT('<', { v, t -> v < t }) + } + + data class Rule( + val prop: String, + val op: Op, + val threshold: Int, + val dest: String + ) { + fun matches(part: Map): Boolean = op.lambda(part[prop]!!, threshold) + + fun validRange(): IntRange { + return when(op) { + Op.GT -> (threshold + 1)..4000 + Op.LT -> 1.. 1..(threshold) + Op.LT -> (threshold)..4000 + } + } + } + + data class Workflow( + val rules: List, + val otherwise: String + ) { + fun process(part: Map): String { + for (rule in rules) { + if (rule.matches(part)) + return rule.dest + } + return otherwise + } + } + + override fun process(part: QuizPart, lines: Sequence): BigInteger { + val iterator = lines.iterator() + val rulePattern = Regex("([xmas])([<>])([0-9]+):([a-zAR]+)") + val workflows = iterator + .asSequence() + .takeWhile { it.isNotEmpty() } + .associate { line -> + val name = line.substringBefore("{") + val ruleStrings = line.substringAfter("{").substringBefore("}").split(",") + val rules = ruleStrings.dropLast(1) + .map { token -> + val match = rulePattern.matchEntire(token) ?: throw Exception("$token does not match rule regex") + Rule(match.groupValues[1], Op.entries.first { it.char == match.groupValues[2][0]}, match.groupValues[3].toInt(), match.groupValues[4]) + } + val otherwise = ruleStrings.last() + name to Workflow(rules, otherwise) + } + return if (part == QuizPart.A) { + iterator + .asSequence() + .map { line -> + line.substring(1, line.length - 1).split(",") + .associate { it.substringBefore("=") to it.substringAfter("=").toInt() } + } + .map { machinePart -> + var dest = "in" + while (dest != "A" && dest != "R") { + dest = workflows[dest]!!.process(machinePart) + // println ("$machinePart to $dest") + } + machinePart to dest + } + .filter { (_, dest) -> dest == "A" } + .sumOf { (machinePart, _) -> machinePart.values.sum() } + .toBigInteger() + } else { + searchPathes(workflows, listOf("in"), mapOf("x" to 1..4000, "m" to 1..4000, "a" to 1..4000, "s" to 1..4000)) + .sumOf { + vc -> vc.values.fold(BigInteger.ONE) { p, r -> p * (r.last - r.first + 1).toBigInteger() } + } +// listOf("x","m","a","s") +// .map { prop -> +// prop to validConstraints.fold(listOf(1..4000)) { existing, constraint -> +// val range = constraint[prop]!! +// buildList { +// existing +// .sortedBy { it.first } +// .forEach { r -> +// if (r.last < range.first || r.first > range.last || r == range) { +// add(r) +// } else { +// add(r.first until range.first) +// add(max(r.first, range.first)..min(r.last, range.last)) +// add((range.last + 1)..r.last) +// } +// } +// } +// .filter { !it.isEmpty() } +// } +// } +// .map { prop -> +// prop.second +// .map { +// prop.first to it +// } +// } +// .combinations() +// .filter { combination -> +// validConstraints.any { constraint -> +// combination.all { prop -> +// prop.second.first >= constraint[prop.first]!!.first && prop.second.last <= constraint[prop.first]!!.last +// } +// } +// } +// .map { combination -> +// combination.fold(BigInteger.ONE) { product, prop -> product * (prop.second.last - prop.second.first + 1).toBigInteger()} +// } +// .sumOf { it } + } + } + fun Map.constraintBy(rule: Rule): Map { + val base = this + return buildMap { + putAll(base) + if (base.containsKey(rule.prop)) { + put(rule.prop, base[rule.prop]!!.intersect(rule.validRange())) + } else { + put(rule.prop, rule.validRange()) + } + } + } + fun Map.constraintByNot(rule: Rule): Map { + val base = this + return buildMap { + putAll(base) + if (base.containsKey(rule.prop)) { + put(rule.prop, base[rule.prop]!!.intersect(rule.invalidRange())) + } else { + put(rule.prop, rule.invalidRange()) + } + } + } + + fun searchPathes(workflows: Map, path: List, constraints: Map): Set> { + return if (path.last() == "A") { + setOf(constraints) + } else if (constraints.any { it.value.isEmpty() }) { + emptySet() + } else if (path.last() == "R") { + emptySet() + } else { + buildSet { + val wf = workflows[path.last()] ?: throw Exception("workflow ${path.last()} not found") + var otherwise = constraints + for (r in wf.rules) { + addAll(searchPathes(workflows, path + r.dest, otherwise.constraintBy(r))) + otherwise = otherwise.constraintByNot(r) + } + addAll(searchPathes(workflows, path + wf.otherwise, otherwise)) + } + } } } diff --git a/src/main/kotlin/de/linkel/aoc/Day20.kt b/src/main/kotlin/de/linkel/aoc/Day20.kt new file mode 100644 index 0000000..c5b6ad3 --- /dev/null +++ b/src/main/kotlin/de/linkel/aoc/Day20.kt @@ -0,0 +1,14 @@ +package de.linkel.aoc + +import de.linkel.aoc.base.AbstractLinesAdventDay +import de.linkel.aoc.base.QuizPart +import jakarta.inject.Singleton + +@Singleton +class Day20: AbstractLinesAdventDay() { + override val day = 20 + + override fun process(part: QuizPart, lines: Sequence): Int { + return 0 + } +} diff --git a/src/main/kotlin/de/linkel/aoc/Day21.kt b/src/main/kotlin/de/linkel/aoc/Day21.kt new file mode 100644 index 0000000..34ac74b --- /dev/null +++ b/src/main/kotlin/de/linkel/aoc/Day21.kt @@ -0,0 +1,14 @@ +package de.linkel.aoc + +import de.linkel.aoc.base.AbstractLinesAdventDay +import de.linkel.aoc.base.QuizPart +import jakarta.inject.Singleton + +@Singleton +class Day21: AbstractLinesAdventDay() { + override val day = 21 + + override fun process(part: QuizPart, lines: Sequence): Int { + return 0 + } +} diff --git a/src/main/kotlin/de/linkel/aoc/Day22.kt b/src/main/kotlin/de/linkel/aoc/Day22.kt new file mode 100644 index 0000000..0355260 --- /dev/null +++ b/src/main/kotlin/de/linkel/aoc/Day22.kt @@ -0,0 +1,14 @@ +package de.linkel.aoc + +import de.linkel.aoc.base.AbstractLinesAdventDay +import de.linkel.aoc.base.QuizPart +import jakarta.inject.Singleton + +@Singleton +class Day22: AbstractLinesAdventDay() { + override val day = 22 + + override fun process(part: QuizPart, lines: Sequence): Int { + return 0 + } +} diff --git a/src/main/kotlin/de/linkel/aoc/Day23.kt b/src/main/kotlin/de/linkel/aoc/Day23.kt new file mode 100644 index 0000000..35795d0 --- /dev/null +++ b/src/main/kotlin/de/linkel/aoc/Day23.kt @@ -0,0 +1,14 @@ +package de.linkel.aoc + +import de.linkel.aoc.base.AbstractLinesAdventDay +import de.linkel.aoc.base.QuizPart +import jakarta.inject.Singleton + +@Singleton +class Day23: AbstractLinesAdventDay() { + override val day = 23 + + override fun process(part: QuizPart, lines: Sequence): Int { + return 0 + } +} diff --git a/src/main/kotlin/de/linkel/aoc/Day24.kt b/src/main/kotlin/de/linkel/aoc/Day24.kt new file mode 100644 index 0000000..a69d921 --- /dev/null +++ b/src/main/kotlin/de/linkel/aoc/Day24.kt @@ -0,0 +1,14 @@ +package de.linkel.aoc + +import de.linkel.aoc.base.AbstractLinesAdventDay +import de.linkel.aoc.base.QuizPart +import jakarta.inject.Singleton + +@Singleton +class Day24: AbstractLinesAdventDay() { + override val day = 24 + + override fun process(part: QuizPart, lines: Sequence): Int { + return 0 + } +} diff --git a/src/main/kotlin/de/linkel/aoc/Day25.kt b/src/main/kotlin/de/linkel/aoc/Day25.kt new file mode 100644 index 0000000..210f925 --- /dev/null +++ b/src/main/kotlin/de/linkel/aoc/Day25.kt @@ -0,0 +1,14 @@ +package de.linkel.aoc + +import de.linkel.aoc.base.AbstractLinesAdventDay +import de.linkel.aoc.base.QuizPart +import jakarta.inject.Singleton + +@Singleton +class Day25: AbstractLinesAdventDay() { + override val day = 25 + + override fun process(part: QuizPart, lines: Sequence): Int { + return 0 + } +} diff --git a/src/test/kotlin/de/linkel/aoc/Day18Test.kt b/src/test/kotlin/de/linkel/aoc/Day18Test.kt index 5abebf0..dc09576 100644 --- a/src/test/kotlin/de/linkel/aoc/Day18Test.kt +++ b/src/test/kotlin/de/linkel/aoc/Day18Test.kt @@ -21,7 +21,23 @@ U 2 (#7a21e3) override val solutionA = 35991L override val exampleSolutionB = 952408144115L - override val solutionB = 0L + override val solutionB = 54058824661845L override val implementation = Day18() } +/* + +####### 7 0 +#.....# 2 5 +###...# 4 3 +..#...# 2 3 +..#...# 2 3 +###.### 6 1 +#...#.. 2 3 +##..### 5 2 +.#....# 2 4 +.###### 6 0 + + + + */ diff --git a/src/test/kotlin/de/linkel/aoc/Day19Test.kt b/src/test/kotlin/de/linkel/aoc/Day19Test.kt index 36c153d..2804923 100644 --- a/src/test/kotlin/de/linkel/aoc/Day19Test.kt +++ b/src/test/kotlin/de/linkel/aoc/Day19Test.kt @@ -1,13 +1,32 @@ package de.linkel.aoc -class Day19Test: AbstractDayTest() { +import java.math.BigInteger + +class Day19Test: AbstractDayTest() { override val exampleA = """ +px{a<2006:qkq,m>2090:A,rfg} +pv{a>1716:R,A} +lnx{m>1548:A,A} +rfg{s<537:gd,x>2440:R,A} +qs{s>3448:A,lnx} +qkq{x<1416:A,crn} +crn{x>2662:A,R} +in{s<1351:px,qqz} +qqz{s>2770:qs,m<1801:hdj,R} +gd{a>3333:R,R} +hdj{m>838:A,pv} + +{x=787,m=2655,a=1222,s=2876} +{x=1679,m=44,a=2067,s=496} +{x=2036,m=264,a=79,s=2244} +{x=2461,m=1339,a=466,s=291} +{x=2127,m=1623,a=2188,s=1013} """.trimIndent() - override val exampleSolutionA = 0 - override val solutionA = 0 + override val exampleSolutionA = 19114L.toBigInteger() + override val solutionA = 374873L.toBigInteger() - override val exampleSolutionB = 0 - override val solutionB = 0 + override val exampleSolutionB = 167409079868000L.toBigInteger() + override val solutionB = BigInteger("122112157518711") override val implementation = Day19() } diff --git a/src/test/kotlin/de/linkel/aoc/Day20Test.kt b/src/test/kotlin/de/linkel/aoc/Day20Test.kt new file mode 100644 index 0000000..b691167 --- /dev/null +++ b/src/test/kotlin/de/linkel/aoc/Day20Test.kt @@ -0,0 +1,13 @@ +package de.linkel.aoc + +class Day20Test: AbstractDayTest() { + override val exampleA = """ + """.trimIndent() + override val exampleSolutionA = 0 + override val solutionA = 0 + + override val exampleSolutionB = 0 + override val solutionB = 0 + + override val implementation = Day20() +} diff --git a/src/test/kotlin/de/linkel/aoc/Day21Test.kt b/src/test/kotlin/de/linkel/aoc/Day21Test.kt new file mode 100644 index 0000000..e8f3021 --- /dev/null +++ b/src/test/kotlin/de/linkel/aoc/Day21Test.kt @@ -0,0 +1,13 @@ +package de.linkel.aoc + +class Day21Test: AbstractDayTest() { + override val exampleA = """ + """.trimIndent() + override val exampleSolutionA = 0 + override val solutionA = 0 + + override val exampleSolutionB = 0 + override val solutionB = 0 + + override val implementation = Day20() +} diff --git a/src/test/kotlin/de/linkel/aoc/Day22Test.kt b/src/test/kotlin/de/linkel/aoc/Day22Test.kt new file mode 100644 index 0000000..44b23b6 --- /dev/null +++ b/src/test/kotlin/de/linkel/aoc/Day22Test.kt @@ -0,0 +1,13 @@ +package de.linkel.aoc + +class Day22Test: AbstractDayTest() { + override val exampleA = """ + """.trimIndent() + override val exampleSolutionA = 0 + override val solutionA = 0 + + override val exampleSolutionB = 0 + override val solutionB = 0 + + override val implementation = Day20() +} diff --git a/src/test/kotlin/de/linkel/aoc/Day23Test.kt b/src/test/kotlin/de/linkel/aoc/Day23Test.kt new file mode 100644 index 0000000..666d4ea --- /dev/null +++ b/src/test/kotlin/de/linkel/aoc/Day23Test.kt @@ -0,0 +1,13 @@ +package de.linkel.aoc + +class Day23Test: AbstractDayTest() { + override val exampleA = """ + """.trimIndent() + override val exampleSolutionA = 0 + override val solutionA = 0 + + override val exampleSolutionB = 0 + override val solutionB = 0 + + override val implementation = Day20() +} diff --git a/src/test/kotlin/de/linkel/aoc/Day24Test.kt b/src/test/kotlin/de/linkel/aoc/Day24Test.kt new file mode 100644 index 0000000..70dff98 --- /dev/null +++ b/src/test/kotlin/de/linkel/aoc/Day24Test.kt @@ -0,0 +1,13 @@ +package de.linkel.aoc + +class Day24Test: AbstractDayTest() { + override val exampleA = """ + """.trimIndent() + override val exampleSolutionA = 0 + override val solutionA = 0 + + override val exampleSolutionB = 0 + override val solutionB = 0 + + override val implementation = Day20() +} diff --git a/src/test/kotlin/de/linkel/aoc/Day25Test.kt b/src/test/kotlin/de/linkel/aoc/Day25Test.kt new file mode 100644 index 0000000..41bd625 --- /dev/null +++ b/src/test/kotlin/de/linkel/aoc/Day25Test.kt @@ -0,0 +1,13 @@ +package de.linkel.aoc + +class Day25Test: AbstractDayTest() { + override val exampleA = """ + """.trimIndent() + override val exampleSolutionA = 0 + override val solutionA = 0 + + override val exampleSolutionB = 0 + override val solutionB = 0 + + override val implementation = Day25() +}