Skip to content

Commit 7acd09d

Browse files
authored
Day 02 2025 (#294)
1 parent 1dc74c4 commit 7acd09d

File tree

4 files changed

+91
-0
lines changed

4 files changed

+91
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package me.peckb.aoc._2025.calendar.day02
2+
3+
import javax.inject.Inject
4+
import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory
5+
6+
class Day02 @Inject constructor(
7+
private val generatorFactory: InputGeneratorFactory,
8+
) {
9+
fun partOne(filename: String) = generatorFactory.forFile(filename).readOne { idRangeList ->
10+
idRangeList.countInvalidIds(::isIdInvalid)
11+
}
12+
13+
fun partTwo(filename: String) = generatorFactory.forFile(filename).readOne { idRangeList ->
14+
idRangeList.countInvalidIds(::isIdActuallyInvalid)
15+
}
16+
17+
fun String.countInvalidIds(validation: (Long) -> Boolean): Long {
18+
return split(",")
19+
.map { it.split("-").let { (s, e) -> IdRange(s.toLong(), e.toLong()) } }
20+
.sumOf { idRange -> (idRange.start..idRange.end).filter { id -> validation(id) }.sum() }
21+
}
22+
23+
private fun isIdInvalid(id: Long): Boolean {
24+
val idString = id.toString()
25+
26+
// odd numbers cannot be the same pattern repeated
27+
if (idString.length %2 != 0) {
28+
return false
29+
}
30+
31+
// so we have an even length ID
32+
val halfLength = idString.length / 2
33+
return idString.take(halfLength) == idString.drop(halfLength)
34+
}
35+
36+
private fun isIdActuallyInvalid(id: Long): Boolean {
37+
val idString = id.toString()
38+
val fullLength = idString.length
39+
val halfLength = idString.length / 2
40+
41+
return (1 .. halfLength).any { lengthToRepeat ->
42+
// if we can't form a full pattern of string length no sense trying
43+
if (fullLength % lengthToRepeat != 0) { return@any false }
44+
45+
val data = idString.take(lengthToRepeat)
46+
var repeatedCount = 1
47+
while(repeatedCount * lengthToRepeat <= fullLength) {
48+
if (data.repeat(repeatedCount) == idString) { return@any true }
49+
repeatedCount++
50+
}
51+
return@any false
52+
}
53+
}
54+
}
55+
56+
data class IdRange(val start: Long, val end: Long)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
## [Day 2: Gift Shop](https://adventofcode.com/2025/day/2)

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package me.peckb.aoc._2025
22

33
import dagger.Component
4+
import me.peckb.aoc._2025.calendar.day02.Day02Test
45
import javax.inject.Singleton
56
import me.peckb.aoc.DayComponent
67
import me.peckb.aoc.InputModule
@@ -10,4 +11,5 @@ import me.peckb.aoc._2025.calendar.day01.Day01Test
1011
@Component(modules = [InputModule::class])
1112
internal interface TestDayComponent : DayComponent {
1213
fun inject(day01Test: Day01Test)
14+
fun inject(day02Test: Day02Test)
1315
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package me.peckb.aoc._2025.calendar.day02
2+
3+
import javax.inject.Inject
4+
5+
import me.peckb.aoc._2025.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 Day02Test {
11+
@Inject
12+
lateinit var day02: Day02
13+
14+
@BeforeEach
15+
fun setup() {
16+
DaggerTestDayComponent.create().inject(this)
17+
}
18+
19+
@Test
20+
fun testDay02PartOne() {
21+
assertEquals(28846518423, day02.partOne(DAY_02))
22+
}
23+
24+
@Test
25+
fun testDay02PartTwo() {
26+
assertEquals(31578210022, day02.partTwo(DAY_02))
27+
}
28+
29+
companion object {
30+
private const val DAY_02: String = "advent-of-code-input/2025/day02.input"
31+
}
32+
}

0 commit comments

Comments
 (0)