Skip to content

Commit c1d2583

Browse files
authored
Day 09 2024 (#268)
* Day 09 2024
1 parent c645db7 commit c1d2583

File tree

4 files changed

+170
-0
lines changed

4 files changed

+170
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package me.peckb.aoc._2024.calendar.day09
2+
3+
import javax.inject.Inject
4+
import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory
5+
6+
class Day09 @Inject constructor(
7+
private val generatorFactory: InputGeneratorFactory,
8+
) {
9+
fun partOne(filename: String) = generatorFactory.forFile(filename).readOne { data ->
10+
val memory = fillMemory(data)
11+
12+
defrag(memory, splitFiles = true)
13+
14+
checksum(memory)
15+
}
16+
17+
fun partTwo(filename: String) = generatorFactory.forFile(filename).readOne { data ->
18+
val memory = fillMemory(data)
19+
20+
defrag(memory, splitFiles = false)
21+
22+
checksum(memory)
23+
}
24+
25+
private fun fillMemory(line: String): MutableList<Space> {
26+
val memory = mutableListOf<Space>()
27+
28+
var file = true
29+
var id = 0
30+
31+
line.forEach { char ->
32+
val length = char.digitToInt()
33+
34+
if (file) { memory.add(Space.Full(length, File(id++))) }
35+
else { memory.add(Space.Empty(length)) }
36+
37+
file = !file
38+
}
39+
40+
return memory
41+
}
42+
43+
private fun defrag(memory: MutableList<Space>, splitFiles: Boolean) {
44+
var lastFileIndex = (memory.lastIndex downTo 0).first { memory[it] is Space.Full }
45+
var spaceIndex = 1
46+
47+
while(spaceIndex < memory.size && (spaceIndex < lastFileIndex)) {
48+
val lastFile = (lastFileIndex downTo spaceIndex)
49+
.first { i -> memory[i] is Space.Full }
50+
.also { lastFileIndex = it }
51+
.let { memory[it] as Space.Full }
52+
53+
val emptySpace = (spaceIndex until lastFileIndex)
54+
.first { i -> memory[i] is Space.Empty }
55+
.also { spaceIndex = it }
56+
.let { memory[it] as Space.Empty }
57+
58+
val availableSpace = emptySpace.length
59+
val fileSize = lastFile.length
60+
61+
if (fileSize < availableSpace) {
62+
emptySpace.length = (availableSpace - fileSize)
63+
memory.add(spaceIndex, Space.Full(fileSize, lastFile.file))
64+
spaceIndex++
65+
memory[lastFileIndex + 1] = Space.Empty(fileSize)
66+
67+
} else if (fileSize == availableSpace) {
68+
emptySpace.length = 0
69+
memory.add(spaceIndex, Space.Full(availableSpace, lastFile.file))
70+
spaceIndex++
71+
memory[lastFileIndex + 1] = Space.Empty(fileSize)
72+
73+
} else { // fileSize > availableSpace
74+
if (splitFiles) {
75+
emptySpace.length = 0
76+
memory.add(spaceIndex, Space.Full(availableSpace, lastFile.file))
77+
78+
lastFile.length -= availableSpace
79+
lastFileIndex++
80+
81+
spaceIndex++
82+
spaceIndex += 2
83+
} else {
84+
var tempSpaceIndex = spaceIndex + 1
85+
var nextEmptySpace = (spaceIndex until lastFileIndex).firstOrNull { i ->
86+
memory[i] is Space.Empty
87+
}?.let { tempSpaceIndex = it; memory[it] as Space.Empty }
88+
89+
while (nextEmptySpace != null && tempSpaceIndex < lastFileIndex) {
90+
if (fileSize <= nextEmptySpace.length) {
91+
if (fileSize < nextEmptySpace.length) {
92+
nextEmptySpace.length = (nextEmptySpace.length - fileSize)
93+
memory.add(tempSpaceIndex, Space.Full(fileSize, lastFile.file))
94+
memory[++lastFileIndex] = Space.Empty(fileSize)
95+
96+
} else { // amountNeededToTake = nextEmptySpace.length
97+
nextEmptySpace.length = 0
98+
memory.add(tempSpaceIndex, Space.Full(fileSize, lastFile.file))
99+
memory[++lastFileIndex] = Space.Empty(fileSize)
100+
}
101+
102+
nextEmptySpace = null
103+
} else {
104+
nextEmptySpace = (tempSpaceIndex + 1 until lastFileIndex).firstOrNull { i ->
105+
memory[i] is Space.Empty
106+
}?.let { tempSpaceIndex = it; memory[it] as Space.Empty }
107+
}
108+
}
109+
110+
lastFileIndex--
111+
}
112+
}
113+
}
114+
}
115+
116+
private fun checksum(memory: MutableList<Space>): Long {
117+
var index = 0L
118+
return memory.sumOf { space ->
119+
when (space) {
120+
is Space.Empty -> 0
121+
is Space.Full -> (0 until space.length).sumOf { ((index + it) * space.file.id) }
122+
}.also { index += space.length() }
123+
}
124+
}
125+
126+
}
127+
128+
data class File(val id: Int)
129+
130+
sealed class Space {
131+
abstract fun length(): Int
132+
133+
data class Empty(var length: Int) : Space() { override fun length() = length }
134+
data class Full(var length: Int, val file: File) : Space() { override fun length() = length }
135+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
## [Day 9: Disk Fragmenter](https://adventofcode.com/2024/day/9)

src/test/kotlin/me/peckb/aoc/_2024/TestDayComponent.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import me.peckb.aoc._2024.calendar.day05.Day05Test
88
import me.peckb.aoc._2024.calendar.day06.Day06Test
99
import me.peckb.aoc._2024.calendar.day07.Day07Test
1010
import me.peckb.aoc._2024.calendar.day08.Day08Test
11+
import me.peckb.aoc._2024.calendar.day09.Day09Test
1112
import javax.inject.Singleton
1213
import me.peckb.aoc.DayComponent
1314
import me.peckb.aoc.InputModule
@@ -24,4 +25,5 @@ internal interface TestDayComponent : DayComponent {
2425
fun inject(day06Test: Day06Test)
2526
fun inject(day07Test: Day07Test)
2627
fun inject(day08Test: Day08Test)
28+
fun inject(day09Test: Day09Test)
2729
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package me.peckb.aoc._2024.calendar.day09
2+
3+
import javax.inject.Inject
4+
5+
import me.peckb.aoc._2024.DaggerTestDayComponent
6+
import org.junit.jupiter.api.Assertions.assertEquals
7+
import org.junit.jupiter.api.BeforeEach
8+
import org.junit.jupiter.api.Test
9+
10+
internal class Day09Test {
11+
@Inject
12+
lateinit var day09: Day09
13+
14+
@BeforeEach
15+
fun setup() {
16+
DaggerTestDayComponent.create().inject(this)
17+
}
18+
19+
@Test
20+
fun testDay09PartOne() {
21+
assertEquals(6384282079460, day09.partOne(DAY_09))
22+
}
23+
24+
@Test
25+
fun testDay09PartTwo() {
26+
assertEquals(6408966547049, day09.partTwo(DAY_09))
27+
}
28+
29+
companion object {
30+
private const val DAY_09: String = "advent-of-code-input/2024/day09.input"
31+
}
32+
}

0 commit comments

Comments
 (0)