day(19): add solution
Signed-off-by: Matej Focko <mfocko@redhat.com>
This commit is contained in:
parent
3701f6ffdf
commit
b5718fdb3b
3 changed files with 268 additions and 0 deletions
|
@ -11,6 +11,7 @@ private fun openFile(day: Int, name: String) = File("src/year%4d/day%02d".format
|
||||||
*/
|
*/
|
||||||
fun readInput(day: Int, name: String) = openFile(day, name).readLines()
|
fun readInput(day: Int, name: String) = openFile(day, name).readLines()
|
||||||
|
|
||||||
|
fun readInputAsString(day: Int, name: String) = openFile(day, name).readText()
|
||||||
fun readInputAsInts(day: Int, name: String) = readInput(day, name).map { it.toInt() }
|
fun readInputAsInts(day: Int, name: String) = readInput(day, name).map { it.toInt() }
|
||||||
fun readInputAsCommaSeparatedInts(day: Int, name: String) = openFile(day, name)
|
fun readInputAsCommaSeparatedInts(day: Int, name: String) = openFile(day, name)
|
||||||
.readText()
|
.readText()
|
||||||
|
|
131
src/year2021/day19/Day19.kt
Normal file
131
src/year2021/day19/Day19.kt
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package year2021.day19
|
||||||
|
|
||||||
|
import readInputAsString
|
||||||
|
import java.time.Instant
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.sin
|
||||||
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
|
data class Vector(val x: Int, val y: Int, val z: Int) {
|
||||||
|
fun magnitude(): Double = sqrt((x * x + y * y + z * z).toDouble())
|
||||||
|
fun translate(by: Vector): Vector = this - by
|
||||||
|
fun rotate(u: Vector, v: Vector, w: Vector): Vector =
|
||||||
|
Vector(
|
||||||
|
u.x * x + v.x * y + w.x * z,
|
||||||
|
u.y * x + v.y * y + w.y * z,
|
||||||
|
u.z * x + v.z * y + w.z * z,
|
||||||
|
)
|
||||||
|
|
||||||
|
operator fun plus(v: Vector): Vector = Vector(x + v.x, y + v.y, z + v.z)
|
||||||
|
operator fun minus(v: Vector): Vector = Vector(x - v.x, y - v.y, z - v.z)
|
||||||
|
operator fun unaryMinus(): Vector = Vector(-x, -y, -z)
|
||||||
|
operator fun times(c: Int): Vector = Vector(c * x, c * y, c * z)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Scanner(val beacons: Set<Vector>)
|
||||||
|
|
||||||
|
// region parsing
|
||||||
|
fun String.toVector() =
|
||||||
|
this.split(",").map(String::toInt).let { (x, y, z) ->
|
||||||
|
Vector(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.toScanner() =
|
||||||
|
Scanner(this.split("\n").drop(1).map(String::toVector).toSet())
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region constants
|
||||||
|
val TRIGONOMETRY: Set<Pair<Int, Int>> =
|
||||||
|
listOf(0, 90, 180, 270)
|
||||||
|
.map { Math.toRadians(it.toDouble()) }
|
||||||
|
.map { sin(it).toInt() to cos(it).toInt() }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
|
val ROTATIONS: Set<Triple<Vector, Vector, Vector>> =
|
||||||
|
TRIGONOMETRY
|
||||||
|
.flatMap { alpha -> TRIGONOMETRY.flatMap { beta -> TRIGONOMETRY.map { gamma -> Triple(alpha, beta, gamma) } } }
|
||||||
|
.map { (a, b, g) ->
|
||||||
|
val (sinA, cosA) = a
|
||||||
|
val (sinB, cosB) = b
|
||||||
|
val (sinG, cosG) = g
|
||||||
|
|
||||||
|
Triple(
|
||||||
|
Vector(cosA * cosB, sinA * cosB, -sinB),
|
||||||
|
Vector(cosA * sinB * sinG - sinA * cosG, sinA * sinB * sinG + cosA * cosG, cosB * sinG),
|
||||||
|
Vector(cosA * sinB * cosG + sinA * sinG, sinA * sinB * cosG - cosA * sinG, cosB * cosG)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.toSet()
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
fun checkOverlap(beacons: Set<Vector>, scanner: Scanner): Pair<Vector, List<Vector>>? {
|
||||||
|
ROTATIONS.forEach { (u, v, w) ->
|
||||||
|
val rotatedBeacons = scanner.beacons.map { it.rotate(u, v, w) }
|
||||||
|
|
||||||
|
beacons.forEach { anchor -> // anchor from already located beacons
|
||||||
|
val translateWithRegardsToAnchor = beacons.map { it.translate(anchor) }.toSet()
|
||||||
|
rotatedBeacons.forEach { rotatedAnchor ->
|
||||||
|
val translateWithRegardsToRotatedAnchor = rotatedBeacons.map { it.translate(rotatedAnchor) }.toSet()
|
||||||
|
|
||||||
|
val intersect = translateWithRegardsToAnchor.intersect(translateWithRegardsToRotatedAnchor)
|
||||||
|
if (intersect.size >= 12) {
|
||||||
|
val scannerPosition = rotatedAnchor - anchor
|
||||||
|
val translatedBeacons = rotatedBeacons.map { it - rotatedAnchor + anchor }
|
||||||
|
return scannerPosition to translatedBeacons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun locate(scanners: List<Scanner>): Pair<Set<Vector>, Set<Vector>> {
|
||||||
|
val beacons = mutableSetOf<Vector>()
|
||||||
|
val scannerPositions = mutableSetOf<Vector>()
|
||||||
|
|
||||||
|
// add first scanner that is used as anchor
|
||||||
|
beacons.addAll(scanners.first().beacons)
|
||||||
|
|
||||||
|
val remainingScanners = scanners.drop(1).toMutableList()
|
||||||
|
while (remainingScanners.isNotEmpty()) {
|
||||||
|
for (i in remainingScanners.indices.reversed()) {
|
||||||
|
val (scannerPosition, translatedBeacons) = checkOverlap(beacons, remainingScanners[i]) ?: continue
|
||||||
|
|
||||||
|
beacons.addAll(translatedBeacons)
|
||||||
|
scannerPositions.add(scannerPosition)
|
||||||
|
remainingScanners.removeAt(i)
|
||||||
|
println("Done: ${scanners.size - remainingScanners.size}/${scanners.size}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return scannerPositions to beacons
|
||||||
|
}
|
||||||
|
|
||||||
|
fun part1(input: Set<Vector>): Int = input.size
|
||||||
|
|
||||||
|
fun part2(input: Set<Vector>): Int =
|
||||||
|
input.maxOf { a ->
|
||||||
|
input.maxOf { b ->
|
||||||
|
(a.x - b.x).absoluteValue + (a.y - b.y).absoluteValue + (a.z - b.z).absoluteValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
val sample =
|
||||||
|
readInputAsString(19, "sample").split("\n\n").map(String::toScanner)
|
||||||
|
val input =
|
||||||
|
readInputAsString(19, "input").split("\n\n").map(String::toScanner)
|
||||||
|
|
||||||
|
println(Date.from(Instant.now()))
|
||||||
|
val (sampleScanners, sampleBeacons) = locate(sample)
|
||||||
|
check(part1(sampleBeacons) == 79)
|
||||||
|
check(part2(sampleScanners) == 3621)
|
||||||
|
|
||||||
|
val (inputScanners, inputBeacons) = locate(input)
|
||||||
|
println(part1(inputBeacons))
|
||||||
|
println(part2(inputScanners))
|
||||||
|
println(Date.from(Instant.now()))
|
||||||
|
}
|
136
src/year2021/day19/sample.txt
Normal file
136
src/year2021/day19/sample.txt
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
--- scanner 0 ---
|
||||||
|
404,-588,-901
|
||||||
|
528,-643,409
|
||||||
|
-838,591,734
|
||||||
|
390,-675,-793
|
||||||
|
-537,-823,-458
|
||||||
|
-485,-357,347
|
||||||
|
-345,-311,381
|
||||||
|
-661,-816,-575
|
||||||
|
-876,649,763
|
||||||
|
-618,-824,-621
|
||||||
|
553,345,-567
|
||||||
|
474,580,667
|
||||||
|
-447,-329,318
|
||||||
|
-584,868,-557
|
||||||
|
544,-627,-890
|
||||||
|
564,392,-477
|
||||||
|
455,729,728
|
||||||
|
-892,524,684
|
||||||
|
-689,845,-530
|
||||||
|
423,-701,434
|
||||||
|
7,-33,-71
|
||||||
|
630,319,-379
|
||||||
|
443,580,662
|
||||||
|
-789,900,-551
|
||||||
|
459,-707,401
|
||||||
|
|
||||||
|
--- scanner 1 ---
|
||||||
|
686,422,578
|
||||||
|
605,423,415
|
||||||
|
515,917,-361
|
||||||
|
-336,658,858
|
||||||
|
95,138,22
|
||||||
|
-476,619,847
|
||||||
|
-340,-569,-846
|
||||||
|
567,-361,727
|
||||||
|
-460,603,-452
|
||||||
|
669,-402,600
|
||||||
|
729,430,532
|
||||||
|
-500,-761,534
|
||||||
|
-322,571,750
|
||||||
|
-466,-666,-811
|
||||||
|
-429,-592,574
|
||||||
|
-355,545,-477
|
||||||
|
703,-491,-529
|
||||||
|
-328,-685,520
|
||||||
|
413,935,-424
|
||||||
|
-391,539,-444
|
||||||
|
586,-435,557
|
||||||
|
-364,-763,-893
|
||||||
|
807,-499,-711
|
||||||
|
755,-354,-619
|
||||||
|
553,889,-390
|
||||||
|
|
||||||
|
--- scanner 2 ---
|
||||||
|
649,640,665
|
||||||
|
682,-795,504
|
||||||
|
-784,533,-524
|
||||||
|
-644,584,-595
|
||||||
|
-588,-843,648
|
||||||
|
-30,6,44
|
||||||
|
-674,560,763
|
||||||
|
500,723,-460
|
||||||
|
609,671,-379
|
||||||
|
-555,-800,653
|
||||||
|
-675,-892,-343
|
||||||
|
697,-426,-610
|
||||||
|
578,704,681
|
||||||
|
493,664,-388
|
||||||
|
-671,-858,530
|
||||||
|
-667,343,800
|
||||||
|
571,-461,-707
|
||||||
|
-138,-166,112
|
||||||
|
-889,563,-600
|
||||||
|
646,-828,498
|
||||||
|
640,759,510
|
||||||
|
-630,509,768
|
||||||
|
-681,-892,-333
|
||||||
|
673,-379,-804
|
||||||
|
-742,-814,-386
|
||||||
|
577,-820,562
|
||||||
|
|
||||||
|
--- scanner 3 ---
|
||||||
|
-589,542,597
|
||||||
|
605,-692,669
|
||||||
|
-500,565,-823
|
||||||
|
-660,373,557
|
||||||
|
-458,-679,-417
|
||||||
|
-488,449,543
|
||||||
|
-626,468,-788
|
||||||
|
338,-750,-386
|
||||||
|
528,-832,-391
|
||||||
|
562,-778,733
|
||||||
|
-938,-730,414
|
||||||
|
543,643,-506
|
||||||
|
-524,371,-870
|
||||||
|
407,773,750
|
||||||
|
-104,29,83
|
||||||
|
378,-903,-323
|
||||||
|
-778,-728,485
|
||||||
|
426,699,580
|
||||||
|
-438,-605,-362
|
||||||
|
-469,-447,-387
|
||||||
|
509,732,623
|
||||||
|
647,635,-688
|
||||||
|
-868,-804,481
|
||||||
|
614,-800,639
|
||||||
|
595,780,-596
|
||||||
|
|
||||||
|
--- scanner 4 ---
|
||||||
|
727,592,562
|
||||||
|
-293,-554,779
|
||||||
|
441,611,-461
|
||||||
|
-714,465,-776
|
||||||
|
-743,427,-804
|
||||||
|
-660,-479,-426
|
||||||
|
832,-632,460
|
||||||
|
927,-485,-438
|
||||||
|
408,393,-506
|
||||||
|
466,436,-512
|
||||||
|
110,16,151
|
||||||
|
-258,-428,682
|
||||||
|
-393,719,612
|
||||||
|
-211,-452,876
|
||||||
|
808,-476,-593
|
||||||
|
-575,615,604
|
||||||
|
-485,667,467
|
||||||
|
-680,325,-822
|
||||||
|
-627,-443,-432
|
||||||
|
872,-547,-609
|
||||||
|
833,512,582
|
||||||
|
807,604,487
|
||||||
|
839,-516,451
|
||||||
|
891,-625,532
|
||||||
|
-652,-548,-490
|
||||||
|
30,-46,-14
|
Loading…
Reference in a new issue