diff --git a/README.md b/README.md
index b2c04ff..d301af1 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,8 @@
-# aoc2022
+# Advent of Code
-https://adventofcode.com/2022
+This repository contains various Advent of Code solutions. Kotlin support is now available for the 2024 edition.
+
+Useful links:
+
+* [Advent of Code 2022](https://adventofcode.com/2022)
+* [Advent of Code 2024](https://adventofcode.com/2024)
diff --git a/pom.xml b/pom.xml
index d9c55b7..8cce36a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -23,8 +23,9 @@
- src/main/java
- target/generated-sources/annotations
+ src/main/java
+ src/main/kotlin
+ target/generated-sources/annotations
@@ -37,7 +38,11 @@
- 1.8
+ 21
+
+ src/test/kotlin
+ src/test/java
+
diff --git a/src/main/kotlin/fr/lmo/aoc2024/AoCHelper.kt b/src/main/kotlin/fr/lmo/aoc2024/AoCHelper.kt
new file mode 100644
index 0000000..473bd8c
--- /dev/null
+++ b/src/main/kotlin/fr/lmo/aoc2024/AoCHelper.kt
@@ -0,0 +1,55 @@
+package fr.lmo.aoc2024
+
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.Paths
+
+/**
+ * Utility helper inspired by previous years to ease solving Advent of Code 2024 puzzles.
+ */
+abstract class AoCHelper {
+ abstract fun run()
+
+ private fun directoryName(): String = this::class.java.simpleName.lowercase()
+
+ private fun fileName(name: String): String {
+ var fileName = name
+ if (System.getProperty("test", "false").toBoolean()) {
+ fileName += "-test"
+ }
+ return "$fileName.txt"
+ }
+
+ private fun path(name: String): Path =
+ Paths.get("src", "main", "resources", "2024", directoryName(), fileName(name))
+
+ fun getTestInputPath(): Path = path("input-test")
+
+ fun getInputPath(): Path = path("input")
+
+ fun readFile(path: Path): String = Files.readString(path)
+
+ fun lines(path: Path): List = Files.readAllLines(path)
+
+ fun list(path: Path, mapper: (String) -> T): List =
+ Files.lines(path).use { it.map(mapper).toList() }
+
+ companion object {
+ @JvmStatic
+ fun main(args: Array) {
+ if (args.isEmpty()) {
+ println("Arg should contain classname")
+ return
+ }
+ val className = args[0]
+ try {
+ val clazz = Class.forName("${AoCHelper::class.java.packageName}.$className")
+ .asSubclass(AoCHelper::class.java)
+ val instance = clazz.getDeclaredConstructor().newInstance()
+ instance.run()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/fr/lmo/aoc2024/D01.kt b/src/main/kotlin/fr/lmo/aoc2024/D01.kt
new file mode 100644
index 0000000..6c67d18
--- /dev/null
+++ b/src/main/kotlin/fr/lmo/aoc2024/D01.kt
@@ -0,0 +1,12 @@
+package fr.lmo.aoc2024
+
+class D01 : AoCHelper() {
+ override fun run() {
+ println("Test: " + readFile(getTestInputPath()))
+ // println("Real: " + readFile(getInputPath()))
+ }
+}
+
+fun main(args: Array) {
+ AoCHelper.main(args)
+}
diff --git a/src/main/resources/2024/d01/input-test.txt b/src/main/resources/2024/d01/input-test.txt
new file mode 100644
index 0000000..1333ed7
--- /dev/null
+++ b/src/main/resources/2024/d01/input-test.txt
@@ -0,0 +1 @@
+TODO
diff --git a/src/main/resources/2024/d01/input.txt b/src/main/resources/2024/d01/input.txt
new file mode 100644
index 0000000..1333ed7
--- /dev/null
+++ b/src/main/resources/2024/d01/input.txt
@@ -0,0 +1 @@
+TODO