1
0
This commit is contained in:
Hubert Van De Walle 2021-12-03 12:34:02 +01:00
parent b9a8e7585b
commit 811a6a0af0
11 changed files with 66 additions and 187 deletions

View File

@ -1,12 +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.Lines
@Day @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 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++
@ -14,7 +15,7 @@ class Day01(@Lines val items: IntArray) {
return count return count
} }
fun part2(): Int { override 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()

View File

@ -1,39 +1,39 @@
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(@Text input: String) { class Day02 : BaseDay() {
private val lines = input.lines().map { it.split(' ').let { it[0] to it[1].toInt() } } 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 horizontalPosition = 0
var depth = 0 var depth = 0
lines.forEach { (direction, value) -> lines.forEach { (direction, value) ->
when (direction) { when (direction) {
"forward" -> horizontalPosition += value "forward" -> horizontalPosition += value
"down" -> depth += value "down" -> depth += value
"up" -> depth -= value "up" -> depth -= value
}
} }
}
return horizontalPosition * depth return horizontalPosition * depth
} }
fun part2(): Any { override fun part2(): Any {
var horizontalPosition = 0 var horizontalPosition = 0
var depth = 0 var depth = 0
var aim = 0 var aim = 0
lines.forEach { (direction, value) -> lines.forEach { (direction, value) ->
when (direction) { when (direction) {
"forward" -> { "forward" -> {
horizontalPosition += value horizontalPosition += value
depth += aim * value depth += aim * value
}
"down" -> aim += value
"up" -> aim -= value
} }
"down" -> aim += value
"up" -> aim -= value
} }
}
return horizontalPosition * depth return horizontalPosition * depth
} }

View File

@ -23,7 +23,7 @@ abstract class BaseDayTest(day: Int) {
BeanContext.run() 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 { private val exampleCtx = lazy {
@ -32,7 +32,7 @@ abstract class BaseDayTest(day: Int) {
.start() .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 @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(ctx.value.run(exampleInstance, "part1")).isEqualTo(part1Example) Assertions.assertThat(exampleInstance.part1()).isEqualTo(part1Example)
} }
@Test @Test
fun `part1 result`() { fun `part1 result`() {
Assertions.assertThat(ctx.value.run(instance, "part1")).isEqualTo(part1Answer) Assertions.assertThat(instance.part1()).isEqualTo(part1Answer)
} }
@Test @Test
fun `part2 example result`() { fun `part2 example result`() {
Assertions.assertThat(ctx.value.run(exampleInstance, "part2")).isEqualTo(part2Example) Assertions.assertThat(exampleInstance.part2()).isEqualTo(part2Example)
} }
@Test @Test
fun `part2 result`() { fun `part2 result`() {
Assertions.assertThat(ctx.value.run(instance, "part2")).isEqualTo(part2Answer) Assertions.assertThat(instance.part2()).isEqualTo(part2Answer)
} }
} }

View File

@ -1,4 +1,3 @@
rootProject.name = "Advent of Code" rootProject.name = "Advent of Code"
include("utils") include("utils")
include("2020")
include("2021") include("2021")

View File

@ -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
}

View File

@ -2,6 +2,7 @@
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
@ -9,8 +10,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<*>? = allBeanDefinitions fun BeanContext.findDayDefinition(day: Int): BeanDefinition<BaseDay>? = allBeanDefinitions
.find { it.name == "be.vandewalleh.aoc.days.Day${day.toString().padStart(length = 2, '0')}" } .find { it.name == "be.vandewalleh.aoc.days.Day${day.toString().padStart(length = 2, '0')}" } as BeanDefinition<BaseDay>?
inline fun <reified T> createDay() = createDay(T::class.java) inline fun <reified T> createDay() = createDay(T::class.java)

View File

@ -6,7 +6,6 @@ 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
@ -15,33 +14,3 @@ import java.lang.annotation.Inherited
@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

View File

@ -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<String>) {
val ints get() = value.map { it.toInt() }
val longs get() = value.map { it.toInt() }
}
}

View File

@ -1,55 +1,26 @@
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) {
@Csv @Prototype
fun csvInts(injectionPoint: InjectionPoint<*>): IntArray = fun input(injectionPoint: InjectionPoint<*>): Input {
injectionPoint.csv().map { it.toInt() }.toIntArray() val day = getDay(injectionPoint)
val path = resourceLoader.ofDay(day)
@Csv return Input(path.readText().trim())
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>() .findAnnotation(Day::class.java)
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}")

View File

@ -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 <reified T : Annotation> AnnotationMetadataProvider.findAnnotation(): Optional<AnnotationValue<T>> =
findAnnotation(T::class.java)

View File

@ -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<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")
}
}