Skip to content

Commit 59d3b81

Browse files
committed
Day 9
1 parent 28c79e2 commit 59d3b81

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed

src/main/kotlin/y24/Day9.kt

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package y24
2+
3+
import common.puzzle.solvePuzzle
4+
import common.puzzle.Input
5+
import common.puzzle.Puzzle
6+
import common.datastructures.*
7+
import common.ext.*
8+
import common.util.*
9+
import java.util.*
10+
import kotlin.math.*
11+
import kotlin.system.exitProcess
12+
13+
14+
fun main() = solvePuzzle(year = 2024, day = 9) { Day9(it) }
15+
16+
class Day9(val input: Input) : Puzzle {
17+
18+
data class Block(val at: Int, val size: Int)
19+
20+
data class Disk(val disk: List<Int?>) {
21+
override fun toString(): String {
22+
return disk.joinToString("") { it?.toString() ?: "." }
23+
}
24+
}
25+
26+
data class Disk2(val blocks: List<Block>, val freeSpace: List<Block>) {
27+
val size = blocks.sumOf { it.size } + freeSpace.sumOf { it.size }
28+
}
29+
30+
fun newDisk(line: String): Disk {
31+
val result = mutableListOf<Int?>()
32+
var isBlock = true
33+
var blockId = 0
34+
line.forEachIndexed { _, c ->
35+
val n = c.digitToInt()
36+
repeat(n) {
37+
result += if (isBlock) blockId else null
38+
}
39+
if (isBlock) {
40+
blockId++
41+
}
42+
isBlock = !isBlock
43+
}
44+
45+
return Disk(result)
46+
}
47+
48+
fun newDisk2(line: String): Disk2 {
49+
val blocks = mutableListOf<Block>()
50+
val freeSpace = mutableListOf<Block>()
51+
52+
var isBlock = true
53+
var idx = 0
54+
line.forEachIndexed { _, c ->
55+
val n = c.digitToInt()
56+
if (isBlock) {
57+
blocks += Block(idx, n)
58+
} else {
59+
freeSpace += Block(idx, n)
60+
}
61+
idx += n
62+
isBlock = !isBlock
63+
}
64+
65+
return Disk2(blocks, freeSpace)
66+
}
67+
68+
fun compact(d: Disk): Disk {
69+
val disk = d.disk
70+
var left = 0
71+
var right = disk.size - 1
72+
73+
val newDisk = disk.toMutableList()
74+
while (left < right) {
75+
while (disk[right] == null && left < right) right--
76+
while(disk[left] != null && left < right) left++
77+
78+
if (left == right) break
79+
80+
// Left is empty, right is block. Swap
81+
newDisk[left] = newDisk[right]
82+
newDisk[right] = null
83+
left++
84+
right--
85+
}
86+
87+
return Disk(newDisk)
88+
}
89+
90+
fun compactWholeBlocks(d: Disk2): Disk {
91+
val gaps = TreeMap<Int, Int>()
92+
d.freeSpace.forEach { (at, size) ->
93+
gaps[at] = size
94+
}
95+
96+
val newDisk = Array<Int?>(d.size) { null }
97+
d.blocks.reversed().forEachIndexed { blockIdReversed, block ->
98+
val blockId = d.blocks.size - blockIdReversed - 1
99+
var writeAt = block.at
100+
for ((at, size) in gaps) {
101+
if (at >= block.at) {
102+
// No more gaps
103+
break
104+
}
105+
106+
if (size < block.size) {
107+
// Too small
108+
continue
109+
}
110+
111+
// Found free space
112+
writeAt = at
113+
gaps.remove(at)
114+
val newGap = size - block.size
115+
if (newGap > 0) {
116+
gaps[at + block.size] = newGap
117+
}
118+
break
119+
}
120+
121+
for (i in 0 until block.size) {
122+
newDisk[writeAt + i] = blockId
123+
}
124+
}
125+
126+
return Disk(newDisk.toList())
127+
}
128+
129+
fun checkSum(disk: Disk): Long {
130+
var sum = 0L
131+
disk.disk.forEachIndexed { index, block ->
132+
if (block != null) {
133+
sum += index * block
134+
}
135+
}
136+
137+
return sum
138+
}
139+
140+
override fun solveLevel1(): Any {
141+
val disk = newDisk(input.lines[0])
142+
val compacted = compact(disk)
143+
return checkSum(compacted)
144+
}
145+
146+
override fun solveLevel2(): Any {
147+
val disk = newDisk2(input.lines[0])
148+
val compacted = compactWholeBlocks(disk)
149+
return checkSum(compacted)
150+
}
151+
}

src/test/kotlin/y24/Day9Test.kt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package y24
2+
3+
import common.puzzle.Input
4+
import org.junit.jupiter.api.Assertions.assertEquals
5+
import org.junit.jupiter.api.Test
6+
7+
internal class Day9Test {
8+
private val sample = Input("""
9+
2333133121414131402
10+
""".trimIndent())
11+
12+
private val day = Day9(sample)
13+
14+
@Test
15+
fun solveLevel1() {
16+
assertEquals(1928L, day.solveLevel1())
17+
}
18+
19+
@Test
20+
fun solveLevel2() {
21+
assertEquals(2858L, day.solveLevel2())
22+
}
23+
}

0 commit comments

Comments
 (0)