diff --git a/2021/src/main/kotlin/Day01.kt b/2021/src/main/kotlin/Day01.kt index 3ada987..d969f15 100644 --- a/2021/src/main/kotlin/Day01.kt +++ b/2021/src/main/kotlin/Day01.kt @@ -1,12 +1,13 @@ package be.vandewalleh.aoc.days +import be.vandewalleh.aoc.utils.BaseDay import be.vandewalleh.aoc.utils.input.Day -import be.vandewalleh.aoc.utils.input.Lines @Day -class Day01(@Lines val items: IntArray) { +class Day01 : BaseDay() { + private val items by lazy { input.lines.ints } - fun part1(): Int { + override fun part1(): Int { var count = 0 for (i in 0 until items.size - 1) { if (items[i] < items[i + 1]) count++ @@ -14,7 +15,7 @@ class Day01(@Lines val items: IntArray) { return count } - fun part2(): Int { + override fun part2(): Int { var count = 0 for (i in 0 until items.size - 3) { val a = items.drop(i).take(3).sum() diff --git a/2021/src/main/kotlin/Day02.kt b/2021/src/main/kotlin/Day02.kt index 12b1e21..eb527bc 100644 --- a/2021/src/main/kotlin/Day02.kt +++ b/2021/src/main/kotlin/Day02.kt @@ -1,39 +1,39 @@ package be.vandewalleh.aoc.days +import be.vandewalleh.aoc.utils.BaseDay import be.vandewalleh.aoc.utils.input.Day -import be.vandewalleh.aoc.utils.input.Text @Day -class Day02(@Text input: String) { - private val lines = input.lines().map { it.split(' ').let { it[0] to it[1].toInt() } } +class Day02 : BaseDay() { + private val lines by lazy { input.lines.value.map { it.split(' ').let { it[0] to it[1].toInt() } } } - fun part1(): Any { + override fun part1(): Int { var horizontalPosition = 0 var depth = 0 lines.forEach { (direction, value) -> - when (direction) { - "forward" -> horizontalPosition += value - "down" -> depth += value - "up" -> depth -= value - } + when (direction) { + "forward" -> horizontalPosition += value + "down" -> depth += value + "up" -> depth -= value } + } return horizontalPosition * depth } - fun part2(): Any { + override fun part2(): Any { var horizontalPosition = 0 var depth = 0 var aim = 0 lines.forEach { (direction, value) -> - when (direction) { - "forward" -> { - horizontalPosition += value - depth += aim * value - } - "down" -> aim += value - "up" -> aim -= value + when (direction) { + "forward" -> { + horizontalPosition += value + depth += aim * value } + "down" -> aim += value + "up" -> aim -= value } + } return horizontalPosition * depth } diff --git a/2021/src/test/kotlin/BaseDayTest.kt b/2021/src/test/kotlin/BaseDayTest.kt index 472d7af..9d22acd 100644 --- a/2021/src/test/kotlin/BaseDayTest.kt +++ b/2021/src/test/kotlin/BaseDayTest.kt @@ -23,7 +23,7 @@ abstract class BaseDayTest(day: Int) { BeanContext.run() } - val instance: Any by lazy { ctx.value.getBean(ctx.value.findDayDefinition(day)) } + val instance by lazy { ctx.value.getBean(ctx.value.findDayDefinition(day)) } private val exampleCtx = lazy { @@ -32,7 +32,7 @@ abstract class BaseDayTest(day: Int) { .start() } - val exampleInstance: Any by lazy { exampleCtx.value.getBean(exampleCtx.value.findDayDefinition(day)) } + val exampleInstance by lazy { exampleCtx.value.getBean(exampleCtx.value.findDayDefinition(day)) } @AfterAll fun `after all`() { @@ -44,22 +44,22 @@ abstract class BaseDayTest(day: Int) { @Test fun `part1 example result`() { - Assertions.assertThat(ctx.value.run(exampleInstance, "part1")).isEqualTo(part1Example) + Assertions.assertThat(exampleInstance.part1()).isEqualTo(part1Example) } @Test fun `part1 result`() { - Assertions.assertThat(ctx.value.run(instance, "part1")).isEqualTo(part1Answer) + Assertions.assertThat(instance.part1()).isEqualTo(part1Answer) } @Test fun `part2 example result`() { - Assertions.assertThat(ctx.value.run(exampleInstance, "part2")).isEqualTo(part2Example) + Assertions.assertThat(exampleInstance.part2()).isEqualTo(part2Example) } @Test fun `part2 result`() { - Assertions.assertThat(ctx.value.run(instance, "part2")).isEqualTo(part2Answer) + Assertions.assertThat(instance.part2()).isEqualTo(part2Answer) } } diff --git a/settings.gradle.kts b/settings.gradle.kts index d1487f4..6b5a63b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,3 @@ rootProject.name = "Advent of Code" include("utils") -include("2020") include("2021") diff --git a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/BaseDay.kt b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/BaseDay.kt new file mode 100644 index 0000000..7cae023 --- /dev/null +++ b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/BaseDay.kt @@ -0,0 +1,13 @@ +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 +} diff --git a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/factory/DayFactory.kt b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/factory/DayFactory.kt index 6515f0d..b20d13a 100644 --- a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/factory/DayFactory.kt +++ b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/factory/DayFactory.kt @@ -2,6 +2,7 @@ package be.vandewalleh.aoc.utils.factory +import be.vandewalleh.aoc.utils.BaseDay import be.vandewalleh.aoc.utils.input.TempFileResourceLoader import io.micronaut.context.BeanContext import io.micronaut.inject.BeanDefinition @@ -9,8 +10,8 @@ import java.io.File fun createDay(beanType: Class): T = BeanContext.run().getBean(beanType) -fun BeanContext.findDayDefinition(day: Int): BeanDefinition<*>? = allBeanDefinitions - .find { it.name == "be.vandewalleh.aoc.days.Day${day.toString().padStart(length = 2, '0')}" } +fun BeanContext.findDayDefinition(day: Int): BeanDefinition? = allBeanDefinitions + .find { it.name == "be.vandewalleh.aoc.days.Day${day.toString().padStart(length = 2, '0')}" } as BeanDefinition? inline fun createDay() = createDay(T::class.java) diff --git a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Annotations.kt b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Annotations.kt index 4e3e6b4..d4c5c44 100644 --- a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Annotations.kt +++ b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Annotations.kt @@ -6,7 +6,6 @@ import io.micronaut.context.annotation.Executable import io.micronaut.context.annotation.Prototype import io.micronaut.core.annotation.Introspected import jakarta.inject.Qualifier -import java.lang.annotation.Inherited @Prototype @Qualifier @@ -15,33 +14,3 @@ import java.lang.annotation.Inherited @Retention(AnnotationRetention.RUNTIME) @Executable 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 diff --git a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Input.kt b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Input.kt new file mode 100644 index 0000000..41bfdcb --- /dev/null +++ b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/Input.kt @@ -0,0 +1,14 @@ +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) { + val ints get() = value.map { it.toInt() } + val longs get() = value.map { it.toInt() } + } + +} diff --git a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/InputFactory.kt b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/InputFactory.kt index 1e833c3..0630a7c 100644 --- a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/InputFactory.kt +++ b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/InputFactory.kt @@ -1,55 +1,26 @@ package be.vandewalleh.aoc.utils.input import io.micronaut.context.annotation.Factory +import io.micronaut.context.annotation.Prototype import io.micronaut.inject.InjectionPoint import kotlin.io.path.ExperimentalPathApi -import kotlin.io.path.readLines import kotlin.io.path.readText @Factory @ExperimentalPathApi class InputFactory(private val resourceLoader: ResourceLoader) { - @Csv - fun csvInts(injectionPoint: InjectionPoint<*>): IntArray = - injectionPoint.csv().map { it.toInt() }.toIntArray() - - @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 = - injectionPoint.lines().toList() - - @Text - fun text(injectionPoint: InjectionPoint<*>): String = - injectionPoint.read() - - @Groups - fun groups(injectionPoint: InjectionPoint<*>): List> = - 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() } + @Prototype + fun input(injectionPoint: InjectionPoint<*>): Input { + val day = getDay(injectionPoint) + val path = resourceLoader.ofDay(day) + return Input(path.readText().trim()) + } private fun getDay(injectionPoint: InjectionPoint<*>): Int { val dayAnnotation = injectionPoint .declaringBean - .findAnnotation() + .findAnnotation(Day::class.java) if (dayAnnotation.isEmpty) error("@DayInput cannot only be used on classes annotated with ${Day::class.qualifiedName}") diff --git a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/MicronautExtensions.kt b/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/MicronautExtensions.kt deleted file mode 100644 index d9f8124..0000000 --- a/utils/src/main/kotlin/be/vandewalleh/aoc/utils/input/MicronautExtensions.kt +++ /dev/null @@ -1,8 +0,0 @@ -package be.vandewalleh.aoc.utils.input - -import io.micronaut.core.annotation.AnnotationMetadataProvider -import io.micronaut.core.annotation.AnnotationValue -import java.util.* - -internal inline fun AnnotationMetadataProvider.findAnnotation(): Optional> = - findAnnotation(T::class.java) diff --git a/utils/src/test/kotlin/input/DayTest.kt b/utils/src/test/kotlin/input/DayTest.kt index 31f755d..e69de29 100644 --- a/utils/src/test/kotlin/input/DayTest.kt +++ b/utils/src/test/kotlin/input/DayTest.kt @@ -1,81 +0,0 @@ -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) - - @Test - fun `check @Text String`() { - val day = createDay() - assertThat(day.input).isEqualTo("blablabla") - } - - @Test - fun `check @Csv IntArray`() { - val day = createDay() - assertThat(day.input).containsExactly(1, +2, 3, 4, -5) - } - - @Test - fun `check @Lines IntArray`() { - val day = createDay() - assertThat(day.input).containsExactly(1779, 1737, 1537, 1167, 1804, 1873) - } - - @Test - fun `check @Lines strings`() { - val day = createDay() - assertThat(day.input).containsExactly("a", "bb", "ccc") - } - -}