Solutions for Advent of Code puzzles.
See adventofcode.com for more information.
Advent of Code puzzles typically have one input file and two parts.
The harness provided by this repository --
- Downloads the input file;
- Runs code to produce an answer for each part; and
- Uploads each answer.
Set the ADVENT_OF_CODE_SESSION
environment variable with the value of your
session
cookie on the adventofcode.com website. This
is necessary for the harness to download the input file and upload your answers.
For each puzzle, create a class with a name in the format PuzzleY${year}D${day}
(e.g., PuzzleY2022D1
) that implements the Puzzle
interface.
interface Puzzle {
fun parse(input: String)
fun solve1(): Any?
fun solve2(): Any?
}
The parse
function is called once after the input is downloaded, and solve1
and
solve2
are called to provide an answer to the first and second part of the
problem respectively. Any type may be returned from these functions; toString
is
called on it to provide the answer that is uploaded.
Run the binary with the arguments solve YEAR DAY
(e.g., solve 2022 1
) to solve
the specified puzzle and upload your answer. If you only want to solve the first or
second part, you can specify that too (e.g., solve 2022 1 1
).
To run your solutions against sample inputs with expected answers, add a companion
object to your Puzzle
class with testInputN
and testAnswerN
fields. For
example --
class PuzzleY2022D1 : Puzzle {
// ...
companion object {
val testInput1 = """
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
""".trimIndent()
val testAnswer1 = 24000
val testInput2 = testInput1
val testAnswer2 = 45000
}
}
testInput1
and testAnswer1
are used with solve1
, and testInput2
and
testAnswer2
are used with solve2
.
If you want to provide multiple inputs for one solveN
function, you can provide
numbered or labeled inputs with matching expected answers:
class PuzzleY2022D1 : Puzzle {
// ...
companion object {
val testInput1_1 = "abc"
val testAnswer1_1 = 123
val testInput1_2 = "def"
val testAnswer1_2 = 456
val testInput1_3 = "hij"
val testAnswer1_3 = 789
val testInput1_large = "klmnop"
val testAnswer1_large = 789123
val testInput2 = "zyx"
val testAnswer2 = 987
}
}
The tests are run automatically before attempting to solve the real input. Solving the real input is not attempted unless all tests pass.
You can also include arbitrary test cases that also block submission if they fail
by adding arbitrary methods prefixed with test
:
class PuzzleY2022D1 : Puzzle {
// ...
companion object {
fun testSomething() {
assertThat(mySum(1, 2)).isEqualTo(3)
}
fun testSomethingElse() {
assertThat(myProduct(2, 3)).isEqualTo(6)
}
// ...
}
}
This is a quick-and-dirty runner, so the first failure stops execution. But it can be useful nonetheless.
Input files are cached to avoid repeatedly downloading potentially large files. You
can clear the cache by running the binary with clearCache
.