Skip to content

Commit 7ae73c5

Browse files
committed
Solution 2017-14 (Disk Defragmentation)
1 parent e8d1586 commit 7ae73c5

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

src/main/kotlin/de/ronny_h/aoc/year2017/day10/KnotHash.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@ class KnotHash : AdventOfCode<String>(2017, 10) {
88
override fun part1(input: List<String>): String {
99
val lengths = input.single().split(",").map(String::toInt)
1010
val size = if (lengths.size < 5) 5 else 256 // just for testing
11-
return knotHash(size, lengths).toString()
11+
return sparseHashProduct(size, lengths).toString()
1212
}
1313

14-
override fun part2(input: List<String>): String {
15-
val lengths = input.single().toASCII() + listOf(17, 31, 73, 47, 23)
16-
val denseHash = sparseHash(256, lengths, 64).reduceToDenseHash()
17-
check(denseHash.size == 16)
18-
return denseHash.joinToString("") { it.toString(16).padStart(2, '0') }
19-
}
14+
override fun part2(input: List<String>): String = input.single().knotHash()
15+
}
16+
17+
fun String.knotHash(): String {
18+
val lengths = toASCII() + listOf(17, 31, 73, 47, 23)
19+
val denseHash = sparseHash(256, lengths, 64).reduceToDenseHash()
20+
check(denseHash.size == 16)
21+
return denseHash.joinToString("") { it.toString(16).padStart(2, '0') }
2022
}
2123

22-
fun knotHash(size: Int, lengths: List<Int>): Int {
24+
fun sparseHashProduct(size: Int, lengths: List<Int>): Int {
2325
val circularList = sparseHash(size, lengths)
2426
return circularList[0] * circularList[1]
2527
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package de.ronny_h.aoc.year2017.day14
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.grids.Coordinates
5+
import de.ronny_h.aoc.extensions.grids.SimpleCharGrid
6+
import de.ronny_h.aoc.year2017.day10.knotHash
7+
import java.math.BigInteger
8+
9+
fun main() = DiskDefragmentation().run(8226, 1128)
10+
11+
class DiskDefragmentation : AdventOfCode<Int>(2017, 14) {
12+
override fun part1(input: List<String>): Int = input
13+
.single()
14+
.toBinaryKnotHashes()
15+
.sumOf { binary -> binary.count { it == '1' } }
16+
17+
private fun String.toBinaryKnotHashes(): List<String> = (0..127)
18+
.map { "$this-$it" }
19+
.map { it.knotHash() }
20+
.map(::hexToBinary)
21+
22+
override fun part2(input: List<String>): Int {
23+
val binaryKnotHashes = input
24+
.single()
25+
.toBinaryKnotHashes()
26+
27+
return Disk(binaryKnotHashes)
28+
.clusterRegions()
29+
.size
30+
}
31+
}
32+
33+
class Disk(input: List<String>) : SimpleCharGrid(input, '0') {
34+
35+
fun clusterRegions(): List<List<Coordinates>> {
36+
val assigned = mutableSetOf<Coordinates>()
37+
return forEachCoordinates { position, element ->
38+
if (element == '1' && position !in assigned) {
39+
collectRegionAt(position, assigned)
40+
} else {
41+
null
42+
}
43+
}
44+
.filterNotNull()
45+
.toList()
46+
}
47+
48+
private fun collectRegionAt(
49+
position: Coordinates,
50+
visited: MutableSet<Coordinates> = mutableSetOf(position),
51+
regionsCoordinates: MutableList<Coordinates> = mutableListOf(position),
52+
): List<Coordinates> {
53+
position.neighbours().forEach { coordinates ->
54+
if (getAt(coordinates) == '1' && visited.add(coordinates)) {
55+
regionsCoordinates.add(coordinates)
56+
collectRegionAt(coordinates, visited, regionsCoordinates)
57+
}
58+
}
59+
return regionsCoordinates
60+
}
61+
}
62+
63+
fun hexToBinary(hexString: String): String =
64+
hexString
65+
.map { ch -> BigInteger("$ch", 16).toString(2).padStart(4, '0') }
66+
.joinToString("")

src/test/kotlin/de/ronny_h/aoc/year2017/day10/KnotHashTest.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import io.kotest.matchers.shouldBe
88
class KnotHashTest : StringSpec({
99

1010
"the knot hash of a small example" {
11-
knotHash(5, listOf(3, 4, 1, 5)) shouldBe 12
11+
sparseHashProduct(5, listOf(3, 4, 1, 5)) shouldBe 12
1212
}
1313

1414
"part 1: the knot hash of a small example" {
@@ -34,4 +34,15 @@ class KnotHashTest : StringSpec({
3434
KnotHash().part2(input) shouldBe hash
3535
}
3636
}
37+
38+
"the extracted knot hash function" {
39+
forAll(
40+
row("", "a2582a3a0e66e6e86e3812dcb672a272"),
41+
row("AoC 2017", "33efeb34ea91902bb2f59c9920caa6cd"),
42+
row("1,2,3", "3efbe78a8d82f29979031a4aa0b16a9d"),
43+
row("1,2,4", "63960835bcdc130f0b66d7ff4f6a5a8e"),
44+
) { input, hash ->
45+
input.knotHash() shouldBe hash
46+
}
47+
}
3748
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package de.ronny_h.aoc.year2017.day14
2+
3+
import io.kotest.core.spec.style.StringSpec
4+
import io.kotest.matchers.shouldBe
5+
6+
class DiskDefragmentationTest : StringSpec({
7+
8+
"hex to binary String" {
9+
hexToBinary("a0c2017") shouldBe "1010000011000010000000010111"
10+
}
11+
12+
"part 1: In the example, 8108 squares are used across the entire 128x128 grid" {
13+
DiskDefragmentation().part1(listOf("flqrgnkx")) shouldBe 8108
14+
}
15+
16+
"part 2: The number of regions present in the given key String" {
17+
DiskDefragmentation().part2(listOf("flqrgnkx")) shouldBe 1242
18+
}
19+
})

0 commit comments

Comments
 (0)