Compare commits
No commits in common. "782fccc572b903a8a660e22353d39e339a1d9568" and "b9a8e7585bf931a3fac29acb665f9dc39ac95ae9" have entirely different histories.
782fccc572
...
b9a8e7585b
@ -1,13 +1,12 @@
|
|||||||
package be.vandewalleh.aoc.days
|
package be.vandewalleh.aoc.days
|
||||||
|
|
||||||
import be.vandewalleh.aoc.utils.BaseDay
|
|
||||||
import be.vandewalleh.aoc.utils.input.Day
|
import be.vandewalleh.aoc.utils.input.Day
|
||||||
|
import be.vandewalleh.aoc.utils.input.Lines
|
||||||
|
|
||||||
@Day
|
@Day
|
||||||
class Day01 : BaseDay() {
|
class Day01(@Lines val items: IntArray) {
|
||||||
private val items by lazy { input.lines.ints }
|
|
||||||
|
|
||||||
override fun part1(): Int {
|
fun part1(): Int {
|
||||||
var count = 0
|
var count = 0
|
||||||
for (i in 0 until items.size - 1) {
|
for (i in 0 until items.size - 1) {
|
||||||
if (items[i] < items[i + 1]) count++
|
if (items[i] < items[i + 1]) count++
|
||||||
@ -15,7 +14,7 @@ class Day01 : BaseDay() {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun part2(): Int {
|
fun part2(): Int {
|
||||||
var count = 0
|
var count = 0
|
||||||
for (i in 0 until items.size - 3) {
|
for (i in 0 until items.size - 3) {
|
||||||
val a = items.drop(i).take(3).sum()
|
val a = items.drop(i).take(3).sum()
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
package be.vandewalleh.aoc.days
|
package be.vandewalleh.aoc.days
|
||||||
|
|
||||||
import be.vandewalleh.aoc.utils.BaseDay
|
|
||||||
import be.vandewalleh.aoc.utils.input.Day
|
import be.vandewalleh.aoc.utils.input.Day
|
||||||
|
import be.vandewalleh.aoc.utils.input.Text
|
||||||
|
|
||||||
@Day
|
@Day
|
||||||
class Day02 : BaseDay() {
|
class Day02(@Text input: String) {
|
||||||
private val lines by lazy { input.lines.value.map { it.split(' ').let { it[0] to it[1].toInt() } } }
|
private val lines = input.lines().map { it.split(' ').let { it[0] to it[1].toInt() } }
|
||||||
|
|
||||||
override fun part1(): Int {
|
fun part1(): Any {
|
||||||
var horizontalPosition = 0
|
var horizontalPosition = 0
|
||||||
var depth = 0
|
var depth = 0
|
||||||
lines.forEach { (direction, value) ->
|
lines.forEach { (direction, value) ->
|
||||||
@ -20,7 +20,7 @@ class Day02 : BaseDay() {
|
|||||||
return horizontalPosition * depth
|
return horizontalPosition * depth
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun part2(): Any {
|
fun part2(): Any {
|
||||||
var horizontalPosition = 0
|
var horizontalPosition = 0
|
||||||
var depth = 0
|
var depth = 0
|
||||||
var aim = 0
|
var aim = 0
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
package be.vandewalleh.aoc.days
|
|
||||||
|
|
||||||
import be.vandewalleh.aoc.utils.BaseDay
|
|
||||||
import be.vandewalleh.aoc.utils.input.Day
|
|
||||||
|
|
||||||
@Day
|
|
||||||
class Day03 : BaseDay() {
|
|
||||||
override fun part1(): Int {
|
|
||||||
val moreOnes = input.lines.value[0].indices
|
|
||||||
.map { i -> input.lines.value.map { it[i] } }
|
|
||||||
.map { it.count { it == '1' } >= it.size / 2 }
|
|
||||||
|
|
||||||
val gamma = moreOnes.joinToString("") { if (it) "1" else "0" }.toInt(radix = 2)
|
|
||||||
val epsilon = moreOnes.joinToString("") { if (!it) "1" else "0" }.toInt(radix = 2)
|
|
||||||
return gamma * epsilon
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun part2(): Any {
|
|
||||||
val oxygenNumbers = findNumber(input.lines.value) { ones, zeros -> if (ones >= zeros) '1' else '0' }
|
|
||||||
val co2Numbers = findNumber(input.lines.value) { ones, zeros -> if (zeros <= ones) '0' else '1' }
|
|
||||||
return oxygenNumbers[0].toInt(2) * co2Numbers[0].toInt(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findNumber(input: List<String>, keep: (Int, Int) -> Char): List<String> {
|
|
||||||
var numbers = input
|
|
||||||
for (i in this.input.lines.value[0].indices) {
|
|
||||||
if (numbers.size == 1) break
|
|
||||||
val eachCount = numbers.map { it[i] }.groupingBy { it }.eachCount()
|
|
||||||
val ones = eachCount['1'] ?: 0
|
|
||||||
val zeros = eachCount['0'] ?: 0
|
|
||||||
val maj = keep(ones, zeros)
|
|
||||||
numbers = numbers.filter { it[i] == maj }
|
|
||||||
}
|
|
||||||
return numbers
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -23,7 +23,7 @@ abstract class BaseDayTest(day: Int) {
|
|||||||
BeanContext.run()
|
BeanContext.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
val instance by lazy { ctx.value.getBean(ctx.value.findDayDefinition(day)) }
|
val instance: Any by lazy { ctx.value.getBean(ctx.value.findDayDefinition(day)) }
|
||||||
|
|
||||||
|
|
||||||
private val exampleCtx = lazy {
|
private val exampleCtx = lazy {
|
||||||
@ -32,7 +32,7 @@ abstract class BaseDayTest(day: Int) {
|
|||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
val exampleInstance by lazy { exampleCtx.value.getBean(exampleCtx.value.findDayDefinition(day)) }
|
val exampleInstance: Any by lazy { exampleCtx.value.getBean(exampleCtx.value.findDayDefinition(day)) }
|
||||||
|
|
||||||
@AfterAll
|
@AfterAll
|
||||||
fun `after all`() {
|
fun `after all`() {
|
||||||
@ -44,22 +44,22 @@ abstract class BaseDayTest(day: Int) {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `part1 example result`() {
|
fun `part1 example result`() {
|
||||||
Assertions.assertThat(exampleInstance.part1()).isEqualTo(part1Example)
|
Assertions.assertThat(ctx.value.run(exampleInstance, "part1")).isEqualTo(part1Example)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `part1 result`() {
|
fun `part1 result`() {
|
||||||
Assertions.assertThat(instance.part1()).isEqualTo(part1Answer)
|
Assertions.assertThat(ctx.value.run(instance, "part1")).isEqualTo(part1Answer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `part2 example result`() {
|
fun `part2 example result`() {
|
||||||
Assertions.assertThat(exampleInstance.part2()).isEqualTo(part2Example)
|
Assertions.assertThat(ctx.value.run(exampleInstance, "part2")).isEqualTo(part2Example)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `part2 result`() {
|
fun `part2 result`() {
|
||||||
Assertions.assertThat(instance.part2()).isEqualTo(part2Answer)
|
Assertions.assertThat(ctx.value.run(instance, "part2")).isEqualTo(part2Answer)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
package be.vandewalleh.aoc.days
|
|
||||||
|
|
||||||
class Day03Test : BaseDayTest(3) {
|
|
||||||
override val example = """
|
|
||||||
00100
|
|
||||||
11110
|
|
||||||
10110
|
|
||||||
10111
|
|
||||||
10101
|
|
||||||
01111
|
|
||||||
00111
|
|
||||||
11100
|
|
||||||
10000
|
|
||||||
11001
|
|
||||||
00010
|
|
||||||
01010
|
|
||||||
""".trimIndent()
|
|
||||||
|
|
||||||
override val part1Example = 198
|
|
||||||
override val part2Example = 230
|
|
||||||
|
|
||||||
override val part1Answer = 3277364
|
|
||||||
override val part2Answer = 5736383
|
|
||||||
}
|
|
||||||
@ -1,3 +1,4 @@
|
|||||||
rootProject.name = "Advent of Code"
|
rootProject.name = "Advent of Code"
|
||||||
include("utils")
|
include("utils")
|
||||||
|
include("2020")
|
||||||
include("2021")
|
include("2021")
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
package be.vandewalleh.aoc.utils
|
|
||||||
|
|
||||||
import be.vandewalleh.aoc.utils.input.Input
|
|
||||||
import jakarta.inject.Inject
|
|
||||||
|
|
||||||
abstract class BaseDay {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var input: Input
|
|
||||||
|
|
||||||
abstract fun part1(): Any
|
|
||||||
abstract fun part2(): Any
|
|
||||||
}
|
|
||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
package be.vandewalleh.aoc.utils.factory
|
package be.vandewalleh.aoc.utils.factory
|
||||||
|
|
||||||
import be.vandewalleh.aoc.utils.BaseDay
|
|
||||||
import be.vandewalleh.aoc.utils.input.TempFileResourceLoader
|
import be.vandewalleh.aoc.utils.input.TempFileResourceLoader
|
||||||
import io.micronaut.context.BeanContext
|
import io.micronaut.context.BeanContext
|
||||||
import io.micronaut.inject.BeanDefinition
|
import io.micronaut.inject.BeanDefinition
|
||||||
@ -10,8 +9,8 @@ import java.io.File
|
|||||||
|
|
||||||
fun <T> createDay(beanType: Class<T>): T = BeanContext.run().getBean(beanType)
|
fun <T> createDay(beanType: Class<T>): T = BeanContext.run().getBean(beanType)
|
||||||
|
|
||||||
fun BeanContext.findDayDefinition(day: Int): BeanDefinition<BaseDay>? = allBeanDefinitions
|
fun BeanContext.findDayDefinition(day: Int): BeanDefinition<*>? = allBeanDefinitions
|
||||||
.find { it.name == "be.vandewalleh.aoc.days.Day${day.toString().padStart(length = 2, '0')}" } as BeanDefinition<BaseDay>?
|
.find { it.name == "be.vandewalleh.aoc.days.Day${day.toString().padStart(length = 2, '0')}" }
|
||||||
|
|
||||||
inline fun <reified T> createDay() = createDay(T::class.java)
|
inline fun <reified T> createDay() = createDay(T::class.java)
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import io.micronaut.context.annotation.Executable
|
|||||||
import io.micronaut.context.annotation.Prototype
|
import io.micronaut.context.annotation.Prototype
|
||||||
import io.micronaut.core.annotation.Introspected
|
import io.micronaut.core.annotation.Introspected
|
||||||
import jakarta.inject.Qualifier
|
import jakarta.inject.Qualifier
|
||||||
|
import java.lang.annotation.Inherited
|
||||||
|
|
||||||
@Prototype
|
@Prototype
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@ -14,3 +15,33 @@ import jakarta.inject.Qualifier
|
|||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@Executable
|
@Executable
|
||||||
annotation class Day(val value: Int = -1)
|
annotation class Day(val value: Int = -1)
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Prototype
|
||||||
|
@Inherited
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class DayInput
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Prototype
|
||||||
|
@Inherited
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Csv
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Prototype
|
||||||
|
@Inherited
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Text
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Prototype
|
||||||
|
@Inherited
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Lines
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Prototype
|
||||||
|
@Inherited
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
annotation class Groups
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
package be.vandewalleh.aoc.utils.input
|
|
||||||
|
|
||||||
class Input(private val value: String) {
|
|
||||||
val text get() = value
|
|
||||||
|
|
||||||
val lines get() = Mapper(value.lines())
|
|
||||||
val csv get() = Mapper(value.split(','))
|
|
||||||
|
|
||||||
class Mapper(val value: List<String>) {
|
|
||||||
val ints get() = value.map { it.toInt() }
|
|
||||||
val longs get() = value.map { it.toInt() }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,26 +1,55 @@
|
|||||||
package be.vandewalleh.aoc.utils.input
|
package be.vandewalleh.aoc.utils.input
|
||||||
|
|
||||||
import io.micronaut.context.annotation.Factory
|
import io.micronaut.context.annotation.Factory
|
||||||
import io.micronaut.context.annotation.Prototype
|
|
||||||
import io.micronaut.inject.InjectionPoint
|
import io.micronaut.inject.InjectionPoint
|
||||||
import kotlin.io.path.ExperimentalPathApi
|
import kotlin.io.path.ExperimentalPathApi
|
||||||
|
import kotlin.io.path.readLines
|
||||||
import kotlin.io.path.readText
|
import kotlin.io.path.readText
|
||||||
|
|
||||||
@Factory
|
@Factory
|
||||||
@ExperimentalPathApi
|
@ExperimentalPathApi
|
||||||
class InputFactory(private val resourceLoader: ResourceLoader) {
|
class InputFactory(private val resourceLoader: ResourceLoader) {
|
||||||
|
|
||||||
@Prototype
|
@Csv
|
||||||
fun input(injectionPoint: InjectionPoint<*>): Input {
|
fun csvInts(injectionPoint: InjectionPoint<*>): IntArray =
|
||||||
val day = getDay(injectionPoint)
|
injectionPoint.csv().map { it.toInt() }.toIntArray()
|
||||||
val path = resourceLoader.ofDay(day)
|
|
||||||
return Input(path.readText().trim())
|
@Csv
|
||||||
}
|
fun csvLongs(injectionPoint: InjectionPoint<*>): LongArray =
|
||||||
|
injectionPoint.csv().map { it.toLong() }.toLongArray()
|
||||||
|
|
||||||
|
private fun InjectionPoint<*>.csv() = read().split(",")
|
||||||
|
|
||||||
|
@Lines
|
||||||
|
fun linesInts(injectionPoint: InjectionPoint<*>): IntArray =
|
||||||
|
injectionPoint.lines().map { it.toInt() }.toList().toIntArray()
|
||||||
|
|
||||||
|
@Lines
|
||||||
|
fun linesLongs(injectionPoint: InjectionPoint<*>): LongArray =
|
||||||
|
injectionPoint.lines().map { it.toLong() }.toList().toLongArray()
|
||||||
|
|
||||||
|
@Lines
|
||||||
|
fun lines(injectionPoint: InjectionPoint<*>): List<String> =
|
||||||
|
injectionPoint.lines().toList()
|
||||||
|
|
||||||
|
@Text
|
||||||
|
fun text(injectionPoint: InjectionPoint<*>): String =
|
||||||
|
injectionPoint.read()
|
||||||
|
|
||||||
|
@Groups
|
||||||
|
fun groups(injectionPoint: InjectionPoint<*>): List<List<String>> =
|
||||||
|
injectionPoint.read().split("\n\n").map { it.lines() }
|
||||||
|
|
||||||
|
private fun InjectionPoint<*>.path() = resourceLoader.ofDay(getDay(this))
|
||||||
|
private fun InjectionPoint<*>.read() = path().readText().trim()
|
||||||
|
private fun InjectionPoint<*>.lines() = path().readLines()
|
||||||
|
.asSequence()
|
||||||
|
.filter { it.isNotBlank() }
|
||||||
|
|
||||||
private fun getDay(injectionPoint: InjectionPoint<*>): Int {
|
private fun getDay(injectionPoint: InjectionPoint<*>): Int {
|
||||||
val dayAnnotation = injectionPoint
|
val dayAnnotation = injectionPoint
|
||||||
.declaringBean
|
.declaringBean
|
||||||
.findAnnotation(Day::class.java)
|
.findAnnotation<Day>()
|
||||||
|
|
||||||
if (dayAnnotation.isEmpty)
|
if (dayAnnotation.isEmpty)
|
||||||
error("@DayInput cannot only be used on classes annotated with ${Day::class.qualifiedName}")
|
error("@DayInput cannot only be used on classes annotated with ${Day::class.qualifiedName}")
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
package be.vandewalleh.aoc.utils.input
|
||||||
|
|
||||||
|
import io.micronaut.core.annotation.AnnotationMetadataProvider
|
||||||
|
import io.micronaut.core.annotation.AnnotationValue
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
internal inline fun <reified T : Annotation> AnnotationMetadataProvider.findAnnotation(): Optional<AnnotationValue<T>> =
|
||||||
|
findAnnotation(T::class.java)
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
package be.vandewalleh.aoc.utils.input
|
||||||
|
|
||||||
|
import be.vandewalleh.aoc.utils.factory.createDay
|
||||||
|
import com.google.common.jimfs.Jimfs
|
||||||
|
import io.micronaut.context.annotation.Replaces
|
||||||
|
import jakarta.inject.Singleton
|
||||||
|
import kotlin.io.path.ExperimentalPathApi
|
||||||
|
import kotlin.io.path.writeText
|
||||||
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class DayTest {
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Replaces(ResourceLoaderImpl::class)
|
||||||
|
@ExperimentalPathApi
|
||||||
|
class FakeResourceLoader : ResourceLoader {
|
||||||
|
private val inMemoryFs = Jimfs.newFileSystem().apply {
|
||||||
|
getPath("1").writeText("blablabla")
|
||||||
|
getPath("2").writeText("1,+2,3,4,-5")
|
||||||
|
getPath("3")
|
||||||
|
.writeText(
|
||||||
|
"""
|
||||||
|
1779
|
||||||
|
1737
|
||||||
|
1537
|
||||||
|
1167
|
||||||
|
1804
|
||||||
|
1873
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
getPath("4")
|
||||||
|
.also { println(it) }
|
||||||
|
.writeText(
|
||||||
|
"""
|
||||||
|
a
|
||||||
|
bb
|
||||||
|
ccc
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
override fun ofDay(day: Int) = inMemoryFs.getPath(day.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Day(1)
|
||||||
|
class TextStringExample(@Text val input: String)
|
||||||
|
|
||||||
|
@Day(2)
|
||||||
|
class CsvIntArrayExample(@Csv val input: IntArray)
|
||||||
|
|
||||||
|
@Day(3)
|
||||||
|
class IntLinesExample(@Lines val input: IntArray)
|
||||||
|
|
||||||
|
@Day(4)
|
||||||
|
class StringLinesExample(@Lines val input: List<String>)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `check @Text String`() {
|
||||||
|
val day = createDay<TextStringExample>()
|
||||||
|
assertThat(day.input).isEqualTo("blablabla")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `check @Csv IntArray`() {
|
||||||
|
val day = createDay<CsvIntArrayExample>()
|
||||||
|
assertThat(day.input).containsExactly(1, +2, 3, 4, -5)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `check @Lines IntArray`() {
|
||||||
|
val day = createDay<IntLinesExample>()
|
||||||
|
assertThat(day.input).containsExactly(1779, 1737, 1537, 1167, 1804, 1873)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `check @Lines strings`() {
|
||||||
|
val day = createDay<StringLinesExample>()
|
||||||
|
assertThat(day.input).containsExactly("a", "bb", "ccc")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user