├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src ├── main ├── kotlin │ └── com │ │ └── ginsberg │ │ └── advent2018 │ │ ├── BronKerbosch.kt │ │ ├── Day01.kt │ │ ├── Day02.kt │ │ ├── Day03.kt │ │ ├── Day04.kt │ │ ├── Day05.kt │ │ ├── Day06.kt │ │ ├── Day07.kt │ │ ├── Day08.kt │ │ ├── Day09.kt │ │ ├── Day10.kt │ │ ├── Day11.kt │ │ ├── Day12.kt │ │ ├── Day13.kt │ │ ├── Day14.kt │ │ ├── Day15.kt │ │ ├── Day16.kt │ │ ├── Day17.kt │ │ ├── Day18.kt │ │ ├── Day19.kt │ │ ├── Day20.kt │ │ ├── Day21.kt │ │ ├── Day22.kt │ │ ├── Day23.kt │ │ ├── Day24.kt │ │ ├── Day25.kt │ │ ├── ElfCode.kt │ │ ├── Extensions.kt │ │ ├── Point.kt │ │ └── Resources.kt └── resources │ ├── day01_input.txt │ ├── day02_input.txt │ ├── day03_input.txt │ ├── day04_input.txt │ ├── day05_input.txt │ ├── day06_input.txt │ ├── day07_input.txt │ ├── day08_input.txt │ ├── day09_input.txt │ ├── day10_input.txt │ ├── day11_input.txt │ ├── day12_input.txt │ ├── day13_input.txt │ ├── day14_input.txt │ ├── day15_input.txt │ ├── day16_input_part1.txt │ ├── day16_input_part2.txt │ ├── day17_input.txt │ ├── day18_input.txt │ ├── day19_input.txt │ ├── day20_input.txt │ ├── day21_input.txt │ ├── day22_input.txt │ ├── day23_input.txt │ ├── day24_input.txt │ ├── day24_input_immune.txt │ ├── day24_input_infection.txt │ └── day25_input.txt └── test ├── kotlin └── com │ └── ginsberg │ └── advent2018 │ ├── Day01Test.kt │ ├── Day02Test.kt │ ├── Day03Test.kt │ ├── Day04Test.kt │ ├── Day05Test.kt │ ├── Day06Test.kt │ ├── Day07Test.kt │ ├── Day08Test.kt │ ├── Day09Test.kt │ ├── Day10Test.kt │ ├── Day11Test.kt │ ├── Day12Test.kt │ ├── Day13Test.kt │ ├── Day14Test.kt │ ├── Day15Test.kt │ ├── Day16Test.kt │ ├── Day17Test.kt │ ├── Day18Test.kt │ ├── Day19Test.kt │ ├── Day20Test.kt │ ├── Day21Test.kt │ ├── Day22Test.kt │ ├── Day23Test.kt │ ├── Day24Test.kt │ ├── Day25Test.kt │ ├── ExtensionsTest.kt │ └── ResourcesTest.kt └── resources ├── day10_input_sample.txt ├── day10_part1_answer.txt ├── day10_part1_sample_answer.txt ├── day12_input_sample.txt ├── day13_input_sample_part1.txt ├── day13_input_sample_part2.txt ├── day15_input_sample1.txt ├── day15_input_sample2.txt ├── day15_input_sample3.txt ├── day15_input_sample4.txt ├── day15_input_sample5.txt ├── day15_input_sample6.txt ├── day15_input_sample7.txt ├── day15_input_sample8.txt ├── day15_input_sample9.txt ├── day16_input_sample_part1.txt ├── day17_input_sample.txt ├── day18_input_sample.txt ├── day19_input_sample.txt ├── day23_input_sample_part1.txt ├── day23_input_sample_part2.txt ├── day25_input_sample_1.txt ├── day25_input_sample_2.txt ├── day25_input_sample_3.txt ├── day25_input_sample_4.txt └── read_file_test_1.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .gradle 3 | /build/ 4 | *.jar 5 | /out/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Todd Ginsberg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Advent of Code 2018 Solutions in Kotlin 2 | 3 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 4 | 5 | This repo is my personal attempt at solving the [Advent of Code 2018](http://adventofcode.com/2018) set of problems with the Kotlin programming language. 6 | 7 | I am trying to solve these on the day they are posted with clear, idiomatic solutions. That means in some cases I will sacrifice performance for a more clear solution. 8 | 9 | | Day | Title | Links | 10 | | --------|-----------------------------------------------|--------------------------------------------- | 11 | | 1 | Chronal Calibration | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day1/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day01.kt) [\[AoC\]](http://adventofcode.com/2018/day/1) | 12 | | 2 | Inventory Management System | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day2/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day02.kt) [\[AoC\]](http://adventofcode.com/2018/day/2) | 13 | | 3 | No Matter How You Slice It | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day3/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day03.kt) [\[AoC\]](http://adventofcode.com/2018/day/3) | 14 | | 4 | Repose Record | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day4/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day04.kt) [\[AoC\]](http://adventofcode.com/2018/day/4) | 15 | | 5 | Alchemical Reduction | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day5/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day05.kt) [\[AoC\]](http://adventofcode.com/2018/day/5) | 16 | | 6 | Chronal Coordinates | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day6/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day06.kt) [\[AoC\]](http://adventofcode.com/2018/day/6) | 17 | | 7 | The Sum of Its Parts | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day7/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day07.kt) [\[AoC\]](http://adventofcode.com/2018/day/7) | 18 | | 8 | Memory Maneuver | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day8/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day08.kt) [\[AoC\]](http://adventofcode.com/2018/day/8) | 19 | | 9 | Marble Mania | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day9/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day09.kt) [\[AoC\]](http://adventofcode.com/2018/day/9) | 20 | | 10 | The Stars Align | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day10/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day10.kt) [\[AoC\]](http://adventofcode.com/2018/day/10) | 21 | | 11 | Chronal Charge | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day11/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day11.kt) [\[AoC\]](http://adventofcode.com/2018/day/11) | 22 | | 12 | Subterranean Sustainability | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day12/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day12.kt) [\[AoC\]](http://adventofcode.com/2018/day/12) | 23 | | 13 | Mine Cart Madness | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day13/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day13.kt) [\[AoC\]](http://adventofcode.com/2018/day/13) | 24 | | 14 | Chocolate Charts | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day14/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day14.kt) [\[AoC\]](http://adventofcode.com/2018/day/14) | 25 | | 15 | Beverage Bandits | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day15/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day15.kt) [\[AoC\]](http://adventofcode.com/2018/day/15) | 26 | | 16 | Chronal Classification | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day16/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day16.kt) [\[AoC\]](http://adventofcode.com/2018/day/16) | 27 | | 17 | Reservoir Research | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day17/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day17.kt) [\[AoC\]](http://adventofcode.com/2018/day/17) | 28 | | 18 | Settlers of The North Pole | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day18/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day18.kt) [\[AoC\]](http://adventofcode.com/2018/day/18) | 29 | | 19 | Go With The Flow | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day19/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day19.kt) [\[AoC\]](http://adventofcode.com/2018/day/19) | 30 | | 20 | A Regular Map | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day20/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day20.kt) [\[AoC\]](http://adventofcode.com/2018/day/20) | 31 | | 21 | Chronal Conversion | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day21/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day21.kt) [\[AoC\]](http://adventofcode.com/2018/day/21) | 32 | | 22 | Mode Maze | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day22/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day22.kt) [\[AoC\]](http://adventofcode.com/2018/day/22) | 33 | | 23 | Experimental Emergency Teleportation | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day23/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day23.kt) [\[AoC\]](http://adventofcode.com/2018/day/23) | 34 | | 24 | Immune System Simulator 20XX | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day24/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day24.kt) [\[AoC\]](http://adventofcode.com/2018/day/24) | 35 | | 25 | Four-Dimensional Adventure | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2018/day25/) [\[Code\]](https://github.com/tginsberg/advent-2018-kotlin/blob/master/src/main/kotlin/com/ginsberg/advent2018/Day25.kt) [\[AoC\]](http://adventofcode.com/2018/day/25) | 36 | 37 | 38 | Copyright © 2018 by Todd Ginsberg. 39 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | /* 4 | * Copyright (c) 2018 by Todd Ginsberg 5 | */ 6 | 7 | plugins { 8 | kotlin("jvm") version "1.3.11" 9 | } 10 | 11 | group = "com.ginsberg" 12 | version = "2018-SNAPSHOT" 13 | 14 | dependencies { 15 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") 16 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0") 17 | 18 | testApi("org.junit.jupiter:junit-jupiter-engine:5.3.2") 19 | testImplementation("org.assertj:assertj-core:3.11.1") 20 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.3.2") 21 | } 22 | 23 | repositories { 24 | mavenCentral() 25 | } 26 | 27 | tasks.withType { 28 | kotlinOptions { 29 | jvmTarget = "1.8" 30 | freeCompilerArgs = listOf("-Xjsr305=strict") 31 | } 32 | } 33 | 34 | tasks.withType { 35 | useJUnitPlatform() 36 | } 37 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tginsberg/advent-2018-kotlin/f33ff59cff3d5895ee8c4de8b9e2f470647af714/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | rootProject.name = "advent-2018-kotlin" -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/BronKerbosch.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | /** 8 | * Interested in this? 9 | * https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm 10 | */ 11 | class BronKerbosch(private val neighbors: Map>) { 12 | 13 | private var bestR: Set = emptySet() 14 | 15 | fun largestClique(): Set { 16 | execute(neighbors.keys) 17 | return bestR 18 | } 19 | 20 | private fun execute( 21 | p: Set, 22 | r: Set = emptySet(), 23 | x: Set = emptySet() 24 | ) { 25 | if (p.isEmpty() && x.isEmpty()) { 26 | // We have found a potential best R value, compare it to the best so far. 27 | if (r.size > bestR.size) bestR = r 28 | } else { 29 | val mostNeighborsOfPandX: T = (p + x).maxBy { neighbors.getValue(it).size }!! 30 | val pWithoutNeighbors = p.minus(neighbors[mostNeighborsOfPandX]!!) 31 | pWithoutNeighbors.forEach { v -> 32 | val neighborsOfV = neighbors[v]!! 33 | execute( 34 | p.intersect(neighborsOfV), 35 | r + v, 36 | x.intersect(neighborsOfV) 37 | ) 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day01.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 1 - Chronal Calibration 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/1 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day1/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day01(rawInput: List) { 14 | 15 | private val input: List = rawInput.map { it.toInt() } 16 | 17 | fun solvePart1(): Int = 18 | input.sum() 19 | 20 | fun solvePart2(): Int { 21 | val frequencies = mutableSetOf(0) 22 | var sum = 0 23 | return input.toInfiniteSequence() 24 | .map { 25 | sum += it 26 | sum 27 | } 28 | .first { !frequencies.add(it) } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day02.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 2 - Inventory Management System 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/2 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day2/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day02(private val input: List) { 14 | 15 | fun solvePart1(): Int { 16 | val pairs = input.map { it.findLetterSets() } 17 | return pairs.count { it.first } * pairs.count { it.second } 18 | } 19 | 20 | fun solvePart2(): String = 21 | input 22 | .asSequence() 23 | .mapIndexed { i, outer -> 24 | input.asSequence().drop(i).mapNotNull { inner -> 25 | val diff = outer.diffIndexes(inner) 26 | if (diff.size == 1) { 27 | outer.removeAt(diff.first()) 28 | } else { 29 | null 30 | } 31 | } 32 | } 33 | .flatten() 34 | .first() 35 | 36 | // Flag whether the given String has any sets of 2 or 3 matching chars. 37 | // Pair.first == 2 38 | // Pair.second == 3 39 | private fun String.findLetterSets(): Pair { 40 | val byChar = this.groupingBy { it }.eachCount() 41 | return Pair( 42 | byChar.any { it.value == 2 }, 43 | byChar.any { it.value == 3 } 44 | ) 45 | } 46 | 47 | // Rebuild a String with the given index missing (remove a character) 48 | private fun String.removeAt(index: Int): String = 49 | if (this.length <= 1) "" 50 | else this.substring(0 until index) + this.substring(index + 1) 51 | 52 | // Get the List of indexes where these two Strings differ. 53 | // Assumption untested: Strings are equal in length. 54 | private fun String.diffIndexes(other: String): List = 55 | this 56 | .mapIndexed { idx, char -> if (other[idx] != char) idx else null } 57 | .filterNotNull() 58 | 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day03.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 3 - No Matter How You Slice It 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/3 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day3/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day03(rawInput: List) { 14 | 15 | private val claims = rawInput.map { Claim.parse(it) } 16 | 17 | fun solvePart1(): Int = 18 | claims 19 | .flatMap { it.area() } 20 | .groupingBy { it } 21 | .eachCount() 22 | .count { it.value > 1 } 23 | 24 | fun solvePart2(): Int { 25 | val cloth = mutableMapOf, Int>() 26 | val uncovered = claims.map { it.id }.toMutableSet() 27 | claims.forEach { claim -> 28 | claim.area().forEach { spot -> 29 | val found = cloth.getOrPut(spot) { claim.id } 30 | if (found != claim.id) { 31 | uncovered.remove(found) 32 | uncovered.remove(claim.id) 33 | } 34 | } 35 | } 36 | return uncovered.first() 37 | } 38 | 39 | } 40 | 41 | data class Claim(val id: Int, val left: Int, val top: Int, val width: Int, val height: Int) { 42 | fun area(): List> = 43 | (0 + left until width + left).flatMap { w -> 44 | (0 + top until height + top).map { h -> 45 | Pair(w, h) 46 | } 47 | } 48 | 49 | // This code parses a String into a Claim, using a Regular Expression 50 | companion object { 51 | private val pattern = """^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)$""".toRegex() 52 | fun parse(input: String): Claim = 53 | pattern.find(input)?.let { 54 | val (id, left, top, w, h) = it.destructured 55 | Claim(id.toInt(), left.toInt(), top.toInt(), w.toInt(), h.toInt()) 56 | } ?: throw IllegalArgumentException("Cannot parse $input") 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day04.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 4 - Repose Record 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/4 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day4/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day04(rawInput: List) { 14 | 15 | private val sleepMinutesPerGuard: Map> = parseInput(rawInput) 16 | 17 | fun solvePart1(): Int = 18 | sleepMinutesPerGuard 19 | .maxBy { it.value.size }!! 20 | .run { key * value.mostFrequent()!! } 21 | 22 | fun solvePart2(): Int = 23 | sleepMinutesPerGuard.flatMap { entry -> 24 | entry.value.map { minute -> 25 | entry.key to minute // Guard to Minute 26 | } 27 | } 28 | .mostFrequent()!! // Which guard slept the most in a minute? 29 | .run { first * second } 30 | 31 | private fun parseInput(input: List): Map> { 32 | val sleeps = mutableMapOf>() 33 | var guard = 0 34 | var sleepStart = 0 35 | 36 | input.sorted().forEach { row -> 37 | when { 38 | row.contains("Guard") -> guard = guardPattern.single(row).toInt() 39 | row.contains("asleep") -> sleepStart = timePattern.single(row).toInt() 40 | else -> { 41 | val sleepMins = (sleepStart until timePattern.single(row).toInt()).toList() 42 | sleeps.merge(guard, sleepMins) { a, b -> a + b } 43 | } 44 | } 45 | } 46 | return sleeps 47 | } 48 | 49 | companion object { 50 | private val guardPattern = """^.+ #(\d+) .+$""".toRegex() 51 | private val timePattern = """^\[.+:(\d\d)] .+$""".toRegex() 52 | } 53 | 54 | private fun Regex.single(from: String): String = 55 | this.find(from)!!.destructured.component1() 56 | } 57 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day05.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 5 - Alchemical Reduction 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/5 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day5/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day05(private val input: String) { 14 | 15 | fun solvePart1(): Int = 16 | input.react().length 17 | 18 | fun solvePart2(): Int = 19 | ('A'..'Z') 20 | .map { input.react(it).length } 21 | .min() 22 | ?: throw IllegalStateException() 23 | 24 | private fun String.react(ignoring: Char? = null): String = 25 | this.fold(mutableListOf()) { done, char -> 26 | when { 27 | ignoring != null && char.equals(ignoring, true) -> Unit 28 | done.firstOrNull() matches char -> done.removeAt(0) 29 | else -> done.add(0, char) 30 | } 31 | done 32 | } 33 | .reversed() 34 | .joinToString(separator = "") 35 | 36 | private infix fun Char?.matches(other: Char): Boolean = 37 | when { 38 | this == null -> false 39 | this.toUpperCase() != other.toUpperCase() -> false 40 | else -> this != other 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day06.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 6 - Chronal Coordinates 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/6 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day6/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day06(input: List) { 14 | 15 | private val points: List = input.map { Point.of(it) } 16 | private val xRange: IntRange = (points.minBy { it.x }!!.x..points.maxBy { it.x }!!.x) 17 | private val yRange: IntRange = (points.minBy { it.y }!!.y..points.maxBy { it.y }!!.y) 18 | 19 | fun solvePart1(): Int { 20 | val infinite: MutableSet = mutableSetOf() 21 | return xRange.asSequence().flatMap { x -> 22 | yRange.asSequence().map { y -> 23 | val closest = points.map { it to it.distanceTo(x, y) }.sortedBy { it.second }.take(2) 24 | if (isEdge(x, y)) { 25 | infinite.add(closest[0].first) 26 | } 27 | closest[0].first.takeUnless { closest[0].second == closest[1].second } 28 | } 29 | } 30 | .filterNot { it in infinite } 31 | .groupingBy { it } 32 | .eachCount() 33 | .maxBy { it.value }!! 34 | .value 35 | } 36 | 37 | fun solvePart2(range: Int = 10_000): Int = 38 | xRange.asSequence().flatMap { x -> 39 | yRange.asSequence().map { y -> 40 | points.map { it.distanceTo(x, y) }.sum() 41 | } 42 | } 43 | .filter { it < range } 44 | .count() 45 | 46 | private fun isEdge(x: Int, y: Int): Boolean = 47 | x == xRange.first || x == xRange.last || y == yRange.first || y == yRange.last 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day07.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 7 - The Sum of Its Parts 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/7 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day7/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day07(input: List) { 14 | 15 | private val allPairs = parseInput(input) 16 | private val childrenOf: Map> = generateDependencies(allPairs) 17 | private val parentsOf: Map> = generateDependencies(allPairs.map { it.second to it.first }) 18 | private val allKeys = childrenOf.keys.union(parentsOf.keys) 19 | 20 | fun solvePart1(): String { 21 | val ready = allKeys.filterNot { it in parentsOf }.toMutableList() 22 | val done = mutableListOf() 23 | while (ready.isNotEmpty()) { 24 | val next = ready.sorted().first().also { ready.remove(it) } 25 | done.add(next) 26 | childrenOf[next]?.let { maybeReadySet -> 27 | ready.addAll(maybeReadySet.filter { maybeReady -> 28 | parentsOf.getValue(maybeReady).all { it in done } 29 | }) 30 | } 31 | } 32 | return done.joinToString(separator = "") 33 | } 34 | 35 | fun solvePart2(workers: Int, costFunction: (Char) -> Int): Int { 36 | val ready = allKeys.filterNot { it in parentsOf }.map { it to costFunction(it) }.toMutableList() 37 | val done = mutableListOf() 38 | var time = 0 39 | 40 | while (ready.isNotEmpty()) { 41 | // Work on things that are ready. 42 | // Do one unit of work per worker, per item at the head of the queue. 43 | ready.take(workers).forEachIndexed { idx, work -> 44 | ready[idx] = Pair(work.first, work.second - 1) 45 | } 46 | 47 | // These are done 48 | ready.filter { it.second == 0 }.forEach { workItem -> 49 | done.add(workItem.first) 50 | 51 | // Now that we are done, add some to ready that have become unblocked 52 | childrenOf[workItem.first]?.let { maybeReadySet -> 53 | ready.addAll( 54 | maybeReadySet.filter { maybeReady -> 55 | parentsOf.getValue(maybeReady).all { it in done } 56 | } 57 | .map { it to costFunction(it) } 58 | .sortedBy { it.first } 59 | ) 60 | } 61 | } 62 | 63 | // Remove anything that we don't need to look at anymore. 64 | ready.removeIf { it.second == 0 } 65 | 66 | time++ 67 | } 68 | return time 69 | } 70 | 71 | private fun parseInput(input: List): List> = 72 | input.map { row -> 73 | row.split(" ").run { this[1].first() to this[7].first() } 74 | } 75 | 76 | private fun generateDependencies(input: List>): Map> = 77 | input 78 | .groupBy { it.first } 79 | .mapValues { (_, value) -> value.map { it.second }.toSet() } 80 | 81 | companion object { 82 | fun exampleCostFunction(c: Char): Int = actualCostFunction(c) - 60 83 | fun actualCostFunction(c: Char): Int = 60 + (c - 'A' + 1) 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day08.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 8 - Memory Maneuver 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/8 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day8/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day08(rawInput: String) { 14 | private val tree: Node = Node.of(rawInput.split(" ").map { it.toInt() }.iterator()) 15 | 16 | fun solvePart1(): Int = 17 | tree.metadataTotal 18 | 19 | fun solvePart2(): Int = 20 | tree.value 21 | 22 | private class Node(children: List, metadata: List) { 23 | companion object { 24 | fun of(values: Iterator): Node { 25 | val numChildren: Int = values.next() 26 | val numMetadata: Int = values.next() 27 | val children = (0 until numChildren).map { Node.of(values) } 28 | val metadata = (0 until numMetadata).map { values.next() }.toList() 29 | return Node(children, metadata) 30 | } 31 | } 32 | 33 | val metadataTotal: Int = 34 | metadata.sum() + children.sumBy { it.metadataTotal } 35 | 36 | val value: Int = 37 | if (children.isEmpty()) metadata.sum() 38 | else metadata.sumBy { children.getOrNull(it - 1)?.value ?: 0 } 39 | 40 | } 41 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day09.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 9 - Marble Mania 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/9 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day9/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.util.ArrayDeque 14 | import java.util.Deque 15 | import kotlin.math.absoluteValue 16 | 17 | 18 | class Day09(private val players: Int, private val highest: Int) { 19 | 20 | fun solvePart1(): Long = 21 | play(players, highest) 22 | 23 | fun solvePart2(): Long = 24 | play(players, highest * 100) 25 | 26 | private fun play(numPlayers: Int, highest: Int): Long { 27 | val scores = LongArray(numPlayers) 28 | val marbles = ArrayDeque().also { it.add(0) } 29 | 30 | (1..highest).forEach { marble -> 31 | when { 32 | marble % 23 == 0 -> { 33 | scores[marble % numPlayers] += marble + with(marbles) { 34 | shift(-7) 35 | removeFirst().toLong() 36 | } 37 | marbles.shift(1) 38 | } 39 | else -> { 40 | with(marbles) { 41 | shift(1) 42 | addFirst(marble) 43 | } 44 | } 45 | } 46 | } 47 | return scores.max()!! 48 | } 49 | 50 | private fun Deque.shift(n: Int): Unit = 51 | when { 52 | n < 0 -> repeat(n.absoluteValue) { 53 | addLast(removeFirst()) 54 | } 55 | else -> repeat(n) { 56 | addFirst(removeLast()) 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day10.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 10 - The Stars Align 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/10 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day10/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day10(rawInput: List) { 14 | 15 | private val message: Message = Message(rawInput.map { Light.of(it) }) 16 | 17 | fun solvePart1(): String = 18 | message.resolveMessage().first 19 | 20 | fun solvePart2(): Int = 21 | message.resolveMessage().second 22 | 23 | private class Message(val lights: List) { 24 | 25 | fun resolveMessage(): Pair { 26 | var lastArea = Long.MAX_VALUE 27 | var thisArea = skyArea() 28 | var timeToResolve = -1 // Account for extra step at the end 29 | while (thisArea < lastArea) { 30 | moveLights() 31 | lastArea = thisArea 32 | thisArea = skyArea() 33 | timeToResolve++ 34 | } 35 | moveLights(false) // We've moved one too far, back everything up one. 36 | 37 | return Pair(this.toString(), timeToResolve) 38 | } 39 | 40 | private fun moveLights(forward: Boolean = true) = 41 | lights.forEach { it.move(forward) } 42 | 43 | private fun skyArea(): Long = 44 | rangeX().span * rangeY().span 45 | 46 | private fun rangeX(): IntRange = 47 | IntRange(lights.minBy { it.x }!!.x, lights.maxBy { it.x }!!.x) 48 | 49 | private fun rangeY(): IntRange = 50 | IntRange(lights.minBy { it.y }!!.y, lights.maxBy { it.y }!!.y) 51 | 52 | override fun toString(): String { 53 | val lightSet = lights.map { Pair(it.x, it.y) }.toSet() 54 | return rangeY().joinToString(separator = "\n") { y -> 55 | rangeX().map { x -> 56 | if (Pair(x, y) in lightSet) '#' else '.' 57 | }.joinToString(separator = "") 58 | } 59 | } 60 | } 61 | 62 | private class Light(var x: Int, var y: Int, val dX: Int, val dY: Int) { 63 | fun move(forward: Boolean = true) { 64 | if (forward) { 65 | x += dX 66 | y += dY 67 | } else { 68 | x -= dX 69 | y -= dY 70 | } 71 | } 72 | 73 | companion object { 74 | fun of(input: String): Light = 75 | input.split(",", "<", ">").map { it.trim() }.run { 76 | Light(this[1].toInt(), this[2].toInt(), this[4].toInt(), this[5].toInt()) 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day11.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 11 - Chronal Charge 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/11 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day11/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day11(private val serialNumber: Int, private val gridSize: Int = 300) { 14 | 15 | private val summedAreaTable: Array = createSummedAreaTable() 16 | 17 | fun solvePart1(): Pair = 18 | bestSquareBetweenSizes(3, 3).run { Pair(x, y) } 19 | 20 | fun solvePart2(): Triple = 21 | bestSquareBetweenSizes(1, gridSize).run { Triple(x, y, n) } 22 | 23 | private fun bestSquareBetweenSizes(smallest: Int, largest: Int): GridSquare = 24 | (smallest..largest).asSequence().flatMap { n -> 25 | (n until gridSize).asSequence().flatMap { y -> 26 | (n until gridSize).asSequence().map { x -> 27 | GridSquare(x - n + 1, y - n + 1, sumOfSquare(x, y, n), n) 28 | } 29 | } 30 | }.maxBy { it.power }!! 31 | 32 | private fun sumOfSquare(x: Int, y: Int, n: Int): Int { 33 | val lowerRight = summedAreaTable[y][x] 34 | val upperRight = if (y - n >= 0) summedAreaTable[y - n][x] else 0 35 | val lowerLeft = if (x - n >= 0) summedAreaTable[y][x - n] else 0 36 | val upperLeft = if (x - n >= 0 && y - n >= 0) summedAreaTable[y - n][x - n] else 0 37 | return lowerRight + upperLeft - upperRight - lowerLeft 38 | } 39 | 40 | private fun createSummedAreaTable(): Array { 41 | // Create an empty grid 42 | val summedGrid: Array = Array(gridSize) { IntArray(gridSize) } 43 | 44 | // Fill the grid 45 | (0 until gridSize).forEach { y -> 46 | (0 until gridSize).forEach { x -> 47 | val me = powerLevel(x, y) 48 | val up = if (y == 0) 0 else summedGrid[y - 1][x] 49 | val left = if (x == 0) 0 else summedGrid[y][x - 1] 50 | val upperLeft = if (x == 0 || y == 0) 0 else summedGrid[y - 1][x - 1] 51 | summedGrid[y][x] = me + up + left - upperLeft 52 | } 53 | } 54 | 55 | return summedGrid 56 | } 57 | 58 | private fun powerLevel(x: Int, y: Int): Int { 59 | val rackId = x + 10 60 | return (((rackId * y) + serialNumber) * rackId).hundreds() - 5 61 | } 62 | 63 | private fun Int.hundreds(): Int = (this / 100) % 10 64 | 65 | private class GridSquare(val x: Int, val y: Int, val power: Int, val n: Int) 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day12.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 12 - Subterranean Sustainability 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/12 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day12/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day12(rawInput: List) { 14 | 15 | private val rules: Set = parseRules(rawInput) 16 | private val initialState: String = rawInput.first().substring(15) 17 | 18 | fun solvePart1(): Long = 19 | mutatePlants().drop(19).first().second 20 | 21 | fun solvePart2(targetGeneration: Long = 50_000_000_000): Long { 22 | var previousDiff = 0L 23 | var previousSize = 0L 24 | var generationNumber = 0 25 | 26 | // Go through the sequence until we find one that grows the same one as its previous generation 27 | mutatePlants().dropWhile { thisGen -> 28 | val thisDiff = thisGen.second - previousSize // Our diff to last generation 29 | if (thisDiff != previousDiff) { 30 | // Still changing 31 | previousDiff = thisDiff 32 | previousSize = thisGen.second 33 | generationNumber += 1 34 | true 35 | } else { 36 | // We've found it, stop dropping. 37 | false 38 | } 39 | }.first() // Consume first because sequences are lazy and it won't start otherwise. 40 | 41 | return previousSize + (previousDiff * (targetGeneration - generationNumber)) 42 | } 43 | 44 | private fun mutatePlants(state: String = initialState): Sequence> = sequence { 45 | var zeroIndex = 0 46 | var currentState = state 47 | while (true) { 48 | // Make sure we have something to match to the left of our first real center point. 49 | while (!currentState.startsWith(".....")) { 50 | currentState = ".$currentState" 51 | zeroIndex++ 52 | } 53 | // Make sure we have something to match to the right of our last real center point. 54 | while (!currentState.endsWith(".....")) { 55 | currentState = "$currentState." 56 | } 57 | 58 | currentState = currentState 59 | .toList() 60 | .windowed(5, 1) 61 | .map { it.joinToString(separator = "") } 62 | .map { if (it in rules) '#' else '.' } 63 | .joinToString(separator = "") 64 | 65 | zeroIndex -= 2 // Because there are two positions to the left of the first real center and were not evaluated 66 | yield(Pair(currentState, currentState.sumIndexesFrom(zeroIndex))) 67 | } 68 | } 69 | 70 | private fun String.sumIndexesFrom(zero: Int): Long = 71 | this.mapIndexed { idx, c -> if (c == '#') idx.toLong() - zero else 0 }.sum() 72 | 73 | private fun parseRules(input: List): Set = 74 | input 75 | .drop(2) 76 | .filter { it.endsWith("#") } 77 | .map { it.take(5) } 78 | .toSet() 79 | } 80 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day13.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 13 - Mine Cart Madness 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/13 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day13/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.util.TreeSet 14 | 15 | typealias Track = Array 16 | 17 | class Day13(rawInput: List) { 18 | 19 | private val track: Track = rawInput.map { it.toCharArray() }.toTypedArray() 20 | private val carts: Set = Cart.findAll(track) 21 | 22 | fun solvePart1(): Point = 23 | collisions().first() 24 | 25 | fun solvePart2(): Point { 26 | collisions().toList() // Consume the entire sequence 27 | return carts.first { it.alive }.run { Point(this.x, this.y) } 28 | } 29 | 30 | 31 | private fun collisions(): Sequence = sequence { 32 | while (carts.count { it.alive } > 1) { 33 | carts.sorted().forEach { cart -> 34 | if (cart.alive) { 35 | cart.move(track) 36 | 37 | // If we collided, mark ourselves and the cart we collided with as not alive 38 | // yield the crash site. 39 | carts.firstOrNull { cart.collidesWith(it) }?.let { otherCart -> 40 | cart.alive = false 41 | otherCart.alive = false 42 | yield(Point(cart.x, cart.y)) 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | private data class Cart(var x: Int, var y: Int, 50 | var direction: Direction, var turn: Turn = Turn.Left, 51 | var alive: Boolean = true) : Comparable { 52 | 53 | companion object { 54 | fun findAll(theTrack: Track): Set = 55 | theTrack.mapIndexed { y, row -> 56 | row.mapIndexed { x, spot -> 57 | if (spot in setOf('>', '<', '^', 'v')) { 58 | Cart(x, y, Direction(spot)) 59 | } else null 60 | } 61 | } 62 | .flatten() 63 | .filterNotNull() 64 | .toCollection(TreeSet()) 65 | } 66 | 67 | fun collidesWith(other: Cart): Boolean = 68 | this != other && this.alive && other.alive && x == other.x && y == other.y 69 | 70 | fun move(track: Track) { 71 | // Move in the direction we are facing 72 | x += direction.dx 73 | y += direction.dy 74 | 75 | // Handle turning, anything else is movement in the same direction the next time through. 76 | when (track[y][x]) { 77 | // Interchange rules 78 | '+' -> { 79 | direction = direction.turn(turn) 80 | turn = turn.next 81 | } 82 | // Turn 83 | '\\' -> { 84 | direction = when (direction) { 85 | Direction.North, Direction.South -> direction.left 86 | else -> direction.right 87 | } 88 | } 89 | // Turn 90 | '/' -> { 91 | direction = when (direction) { 92 | Direction.East, Direction.West -> direction.left 93 | else -> direction.right 94 | } 95 | } 96 | } 97 | } 98 | 99 | override fun compareTo(other: Cart): Int = 100 | when { 101 | y < other.y -> -1 102 | y > other.y -> 1 103 | x < other.x -> -1 104 | x > other.x -> 1 105 | else -> 0 106 | } 107 | } 108 | 109 | private sealed class Turn { 110 | abstract val next: Turn 111 | 112 | object Left : Turn() { 113 | override val next = Center 114 | } 115 | 116 | object Center : Turn() { 117 | override val next = Right 118 | } 119 | 120 | object Right : Turn() { 121 | override val next = Left 122 | } 123 | } 124 | 125 | private sealed class Direction { 126 | 127 | companion object { 128 | operator fun invoke(id: Char): Direction = 129 | when (id) { 130 | '^' -> North 131 | 'v' -> South 132 | '>' -> East 133 | '<' -> West 134 | else -> throw IllegalArgumentException("No such direction $id") 135 | } 136 | } 137 | 138 | abstract val left: Direction 139 | abstract val right: Direction 140 | abstract val dx: Int 141 | abstract val dy: Int 142 | 143 | fun turn(turn: Turn): Direction = 144 | when (turn) { 145 | Turn.Left -> this.left 146 | Turn.Center -> this 147 | Turn.Right -> this.right 148 | } 149 | 150 | 151 | object North : Direction() { 152 | override val left = West 153 | override val right = East 154 | override val dx = 0 155 | override val dy = -1 156 | } 157 | 158 | object South : Direction() { 159 | override val left = East 160 | override val right = West 161 | override val dx = 0 162 | override val dy = 1 163 | } 164 | 165 | object East : Direction() { 166 | override val left = North 167 | override val right = South 168 | override val dx = 1 169 | override val dy = 0 170 | } 171 | 172 | object West : Direction() { 173 | override val left = South 174 | override val right = North 175 | override val dx = -1 176 | override val dy = 0 177 | } 178 | } 179 | 180 | 181 | } 182 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day14.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 14 - Chocolate Charts 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/14 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day14/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | 14 | class Day14(stoppingPoint: String) { 15 | 16 | private val stopInt = stoppingPoint.toInt() 17 | private val stopList = stoppingPoint.map { it.toString().toInt() }.toList() 18 | 19 | fun solvePart1(): String = 20 | recipes { it.size == stopInt + 10 }.takeLast(10).joinToString("") 21 | 22 | fun solvePart2(): Int = 23 | recipes { it.endsWith(stopList) }.size - stopList.size 24 | 25 | private fun recipes(stopCondition: (List) -> Boolean): List { 26 | val history = mutableListOf(3, 7) 27 | var elf1 = 0 28 | var elf2 = 1 29 | var stop = false 30 | 31 | while (!stop) { 32 | val nextValue = history[elf1] + history[elf2] 33 | nextValue.asDigits().forEach { 34 | if (!stop) { 35 | history.add(it) 36 | stop = stopCondition(history) 37 | } 38 | } 39 | elf1 = (elf1 + history[elf1] + 1) % history.size 40 | elf2 = (elf2 + history[elf2] + 1) % history.size 41 | } 42 | return history 43 | } 44 | 45 | private fun Int.asDigits(): List = 46 | this.toString().map { it.toString().toInt() } 47 | 48 | private fun List.endsWith(other: List): Boolean = 49 | if (this.size < other.size) false 50 | else this.slice(this.size - other.size until this.size) == other 51 | } 52 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day15.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 15 - Beverage Bandits 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/15 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day15/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.util.ArrayDeque 14 | import java.util.Deque 15 | 16 | typealias Caves = Array 17 | typealias Path = List 18 | 19 | class Day15(private val rawInput: List) { 20 | 21 | private var caves: Caves = parseCaves() 22 | private var fighters: List = Fighter.findFighters(caves) 23 | 24 | fun solvePart1(): Int { 25 | val result = goFightGoblins() 26 | return result.second.filterNot { it.dead }.sumBy { it.hp } * result.first 27 | } 28 | 29 | fun solvePart2(): Int = 30 | generateSequence(4, Int::inc).map { ap -> 31 | // Reset 32 | caves = parseCaves() 33 | fighters = Fighter.findFighters(caves) 34 | 35 | val result = goFightGoblins(ap) 36 | if (result.second.filter { it.team == Team.Elf }.none { it.dead }) { 37 | result.second.filterNot { it.dead }.sumBy { it.hp } * result.first 38 | } else { 39 | null 40 | } 41 | } 42 | .filterNotNull() 43 | .first() 44 | 45 | private fun goFightGoblins(elfAttackPoints: Int = 3): Pair> { 46 | fighters.filter { it.team == Team.Elf }.forEach { it.ap = elfAttackPoints } 47 | var rounds = 0 48 | while (round()) { 49 | rounds++ 50 | } 51 | return Pair(rounds, fighters) 52 | } 53 | 54 | private fun round(): Boolean { 55 | // Fighters need to be in order at the start of the round. 56 | // This is a sequence because we can lazily remove dead fighers before their turn, 57 | // otherwise we have to manually check. 58 | fighters.sorted().asSequence().filterNot { it.dead }.forEach { fighter -> 59 | // Check for premature end of the round - nobody left to fight 60 | if (!keepFighting()) { 61 | return false 62 | } 63 | 64 | // If we are already in range, stop moving. 65 | var target: Fighter? = fighter.inRange(fighters).firstOrNull() 66 | if (target == null) { 67 | // Movement 68 | val path = fighter.findPathToBestEnemyAdjacentSpot(fighters, caves) 69 | if (path.isNotEmpty()) { 70 | fighter.moveTo(path.first(), caves) 71 | } 72 | // Find target 73 | target = fighter.inRange(fighters).firstOrNull() 74 | } 75 | 76 | // Fight if we have a target 77 | target?.let { 78 | fighter.attack(it, caves) 79 | } 80 | } 81 | return true // Round ended at its natural end 82 | } 83 | 84 | private fun keepFighting(): Boolean = 85 | fighters.filterNot { it.dead }.distinctBy { it.team }.count() > 1 86 | 87 | private fun parseCaves(): Caves = 88 | rawInput.map { it.toCharArray() }.toTypedArray() 89 | 90 | } 91 | 92 | private enum class Team(val logo: Char) { 93 | Elf('E'), 94 | Goblin('G'); 95 | 96 | companion object { 97 | fun byLogo(logo: Char): Team? = 98 | values().firstOrNull { logo == it.logo } 99 | } 100 | } 101 | 102 | private data class Fighter( 103 | val team: Team, 104 | var location: Point, 105 | var hp: Int = 200, 106 | var ap: Int = 3, 107 | var dead: Boolean = false 108 | ) : Comparable { 109 | 110 | // Enemies are in range if they are not me, neither of us is dead, 111 | // we are not on the same team, and only 1 square away 112 | fun inRange(others: List): List = 113 | others.filter { 114 | it != this && 115 | !this.dead && 116 | !it.dead && 117 | it.team != this.team && 118 | this.location.distanceTo(it.location) == 1 119 | } 120 | .sortedWith(compareBy({ it.hp }, { it.location })) 121 | 122 | fun attack(target: Fighter, caves: Caves) { 123 | target.hp -= this.ap 124 | if (target.hp <= 0) { 125 | // Mark enemy as dead and clean up the corpse 126 | target.dead = true 127 | caves[target.location.y][target.location.x] = '.' 128 | } 129 | } 130 | 131 | fun moveTo(place: Point, caves: Caves) { 132 | // We need to alter the caves because we use it for pathfinding 133 | caves[location.y][location.x] = '.' 134 | location = place 135 | caves[location.y][location.x] = team.logo 136 | } 137 | 138 | // Bad real estate descriptions - Enemy Adjacent 139 | fun findPathToBestEnemyAdjacentSpot( 140 | fighters: List, 141 | caves: Caves 142 | ): Path = 143 | pathToAnyEnemy( 144 | enemyAdjacentOpenSpots(fighters, caves), 145 | caves 146 | ) 147 | 148 | private fun enemyAdjacentOpenSpots(fighters: List, caves: Caves): Set = 149 | fighters 150 | .filterNot { it.dead } 151 | .filterNot { it.team == team } 152 | .flatMap { it.location.cardinalNeighbors().filter { neighbor -> caves[neighbor.y][neighbor.x] == '.' } } 153 | .toSet() 154 | 155 | private fun pathToAnyEnemy( 156 | enemies: Set, 157 | caves: Caves 158 | ): Path { 159 | val seen: MutableSet = mutableSetOf(location) 160 | val paths: Deque = ArrayDeque() 161 | 162 | // Seed the queue with each of our neighbors, in reading order (that's important) 163 | location.cardinalNeighbors() 164 | .filter { caves[it.y][it.x] == '.' } 165 | .forEach { paths.add(listOf(it)) } 166 | 167 | // While we still have paths to examine, and haven't found the answer yet... 168 | while (paths.isNotEmpty()) { 169 | val path: Path = paths.removeFirst() 170 | val pathEnd: Point = path.last() 171 | 172 | // If this is one of our destinations, return it 173 | if (pathEnd in enemies) { 174 | return path 175 | } 176 | 177 | // If this is a new path, create a set of new paths from it for each of its 178 | // cardinal direction (again, in reader order), and add them all back 179 | // to the queue. 180 | if (pathEnd !in seen) { 181 | seen.add(pathEnd) 182 | pathEnd.cardinalNeighbors() 183 | .filter { caves[it.y][it.x] == '.' } 184 | .filterNot { it in seen } 185 | .forEach { paths.add(path + it) } 186 | } 187 | } 188 | return emptyList() 189 | } 190 | 191 | 192 | override fun compareTo(other: Fighter): Int = 193 | location.compareTo(other.location) 194 | 195 | companion object { 196 | fun findFighters(caves: Caves): List = 197 | caves.mapIndexed { y, row -> 198 | row.mapIndexed { x, spot -> 199 | Team.byLogo(spot)?.let { 200 | Fighter(it, Point(x, y)) 201 | } 202 | } 203 | } 204 | .flatten() 205 | .filterNotNull() 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day16.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 16 - Chronal Classification 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/16 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day16/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | typealias Registers = IntArray 14 | typealias Instruction = IntArray 15 | typealias Operation = (Registers, Instruction) -> Registers 16 | 17 | class Day16( 18 | part1RawInput: List, 19 | part2RawInput: List 20 | ) { 21 | 22 | private val part1Input: List = parsePart1Input(part1RawInput) 23 | private val part2Input: List = parsePart2Input(part2RawInput) 24 | 25 | fun solvePart1(): Int = 26 | part1Input.count { countMatchingOperations(it) >= 3 } 27 | 28 | fun solvePart2(): Int { 29 | // Create all possible matches. 30 | val functionToOpCodes: MutableMap> = part1Input.flatMap { input -> 31 | Operations.operations.mapNotNull { operation -> 32 | if (operation(input.registersBefore, input.instruction).contentEquals(input.expectedRegisters)) { 33 | input.id to operation 34 | } else { 35 | null 36 | } 37 | } 38 | } 39 | .groupBy({ it.second }, { it.first }) 40 | .mapValues { (_, list) -> list.toMutableSet() } 41 | .toMutableMap() 42 | 43 | val operations = mutableMapOf() 44 | while (functionToOpCodes.isNotEmpty()) { 45 | // Find all that have only one outcome, map them into the operations map and remove them from contention, 46 | functionToOpCodes 47 | .filter { (_, codes) -> codes.size == 1 } 48 | .map { Pair(it.key, it.value.first()) } 49 | .forEach { (op, code) -> 50 | operations[code] = op 51 | functionToOpCodes.remove(op) 52 | functionToOpCodes.forEach { (_, thoseFuncs) -> thoseFuncs.remove(code) } 53 | } 54 | functionToOpCodes.entries.removeIf { (_, value) -> value.isEmpty() } 55 | } 56 | 57 | 58 | // Run the code and return register 0 59 | return part2Input.fold(intArrayOf(0, 0, 0, 0)) { registers, instruction -> 60 | operations[instruction[0]]!!.invoke(registers, instruction) 61 | }.first() 62 | } 63 | 64 | private fun countMatchingOperations(input: Input): Int = 65 | Operations.operations.count { it(input.registersBefore, input.instruction).contentEquals(input.expectedRegisters) } 66 | 67 | 68 | private companion object { 69 | val digitsRegex = """[^0-9 ]""".toRegex() 70 | 71 | fun parsePart1Input(rawInput: List): List = 72 | rawInput.chunked(4) { chunk -> 73 | Input( 74 | chunk[0].toIntArray(), 75 | chunk[1].toIntArray(), 76 | chunk[2].toIntArray() 77 | ) 78 | } 79 | 80 | fun parsePart2Input(rawInput: List): List = 81 | rawInput.map { it.toIntArray() } 82 | 83 | private fun String.toIntArray(): IntArray = 84 | this.replace(digitsRegex, "").trim().split(" ").map { it.toInt() }.toIntArray() 85 | 86 | } 87 | 88 | private class Input(val registersBefore: Registers, val instruction: Instruction, val expectedRegisters: Registers) { 89 | val id = instruction[0] 90 | } 91 | 92 | private object Operations { 93 | val operations: List = listOf( 94 | ::addr, 95 | ::addi, 96 | ::mulr, 97 | ::muli, 98 | ::banr, 99 | ::bani, 100 | ::borr, 101 | ::bori, 102 | ::setr, 103 | ::seti, 104 | ::gtir, 105 | ::gtri, 106 | ::gtrr, 107 | ::eqir, 108 | ::eqri, 109 | ::eqrr 110 | ) 111 | 112 | fun addr(registers: Registers, instruction: Instruction): Registers = 113 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] + registers[instruction[2]] } 114 | 115 | fun addi(registers: Registers, instruction: Instruction): Registers = 116 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] + instruction[2] } 117 | 118 | fun mulr(registers: Registers, instruction: Instruction): Registers = 119 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] * registers[instruction[2]] } 120 | 121 | fun muli(registers: Registers, instruction: Instruction): Registers = 122 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] * instruction[2] } 123 | 124 | fun banr(registers: Registers, instruction: Instruction): Registers = 125 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] and registers[instruction[2]] } 126 | 127 | fun bani(registers: Registers, instruction: Instruction): Registers = 128 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] and instruction[2] } 129 | 130 | fun borr(registers: Registers, instruction: Instruction): Registers = 131 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] or registers[instruction[2]] } 132 | 133 | fun bori(registers: Registers, instruction: Instruction): Registers = 134 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] or instruction[2] } 135 | 136 | fun setr(registers: Registers, instruction: Instruction): Registers = 137 | registers.copyOf().apply { this[instruction[3]] = registers[instruction[1]] } 138 | 139 | fun seti(registers: Registers, instruction: Instruction): Registers = 140 | registers.copyOf().apply { this[instruction[3]] = instruction[1] } 141 | 142 | fun gtir(registers: Registers, instruction: Instruction): Registers = 143 | registers.copyOf().apply { this[instruction[3]] = if (instruction[1] > registers[instruction[2]]) 1 else 0 } 144 | 145 | fun gtri(registers: Registers, instruction: Instruction): Registers = 146 | registers.copyOf().apply { this[instruction[3]] = if (registers[instruction[1]] > instruction[2]) 1 else 0 } 147 | 148 | fun gtrr(registers: Registers, instruction: Instruction): Registers = 149 | registers.copyOf().apply { this[instruction[3]] = if (registers[instruction[1]] > registers[instruction[2]]) 1 else 0 } 150 | 151 | fun eqir(registers: Registers, instruction: Instruction): Registers = 152 | registers.copyOf().apply { this[instruction[3]] = if (instruction[1] == registers[instruction[2]]) 1 else 0 } 153 | 154 | fun eqri(registers: Registers, instruction: Instruction): Registers = 155 | registers.copyOf().apply { this[instruction[3]] = if (registers[instruction[1]] == instruction[2]) 1 else 0 } 156 | 157 | fun eqrr(registers: Registers, instruction: Instruction): Registers = 158 | registers.copyOf().apply { this[instruction[3]] = if (registers[instruction[1]] == registers[instruction[2]]) 1 else 0 } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day17.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 17 - Reservoir Research 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/17 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day17/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | class Day17(rawInput: List) { 14 | 15 | private val parsedData = createMap(rawInput) 16 | private val grid: Array = parsedData.first 17 | private val minY: Int = parsedData.second 18 | private val fountain: Point = Point(500, 0) 19 | 20 | fun solvePart1(): Int { 21 | flow(fountain) 22 | return grid.filterIndexed { idx, _ -> idx >= minY }.sumBy { row -> 23 | row.filter { it in flowOrStill }.count() 24 | } 25 | } 26 | 27 | fun solvePart2(): Int { 28 | flow(fountain) 29 | return grid.filterIndexed { idx, _ -> idx >= minY }.sumBy { row -> 30 | row.filter { it == '~' }.count() 31 | } 32 | } 33 | 34 | private fun flow(source: Point) { 35 | if (source.down !in grid) { 36 | return 37 | } 38 | if (grid[source.down] == '.') { 39 | grid[source.down] = '|' 40 | flow(source.down) 41 | } 42 | if (grid[source.down] in wallOrStill && source.right in grid && grid[source.right] == '.') { 43 | grid[source.right] = '|' 44 | flow(source.right) 45 | } 46 | if (grid[source.down] in wallOrStill && source.left in grid && grid[source.left] == '.') { 47 | grid[source.left] = '|' 48 | flow(source.left) 49 | } 50 | if (hasWalls(source)) { 51 | fillLeftAndRight(source) 52 | } 53 | } 54 | 55 | private fun hasWalls(source: Point): Boolean = 56 | hasWall(source, Point::right) && hasWall(source, Point::left) 57 | 58 | private fun hasWall(source: Point, nextPoint: (Point) -> Point): Boolean { 59 | var point = source 60 | while (point in grid) { 61 | when (grid[point]) { 62 | '#' -> return true 63 | '.' -> return false 64 | else -> point = nextPoint(point) 65 | } 66 | } 67 | return false 68 | } 69 | 70 | private fun fillLeftAndRight(source: Point) { 71 | fillUntilWall(source, Point::right) 72 | fillUntilWall(source, Point::left) 73 | } 74 | 75 | private fun fillUntilWall(source: Point, nextPoint: (Point) -> Point) { 76 | var point = source 77 | while (grid[point] != '#') { 78 | grid[point] = '~' 79 | point = nextPoint(point) 80 | } 81 | } 82 | 83 | 84 | private fun createMap(input: List): Pair, Int> { 85 | val spots = claySpotsFromInput(input) 86 | val minY = spots.minBy { it.y }!!.y 87 | val maxX = spots.maxBy { it.x }!!.x 88 | val maxY = spots.maxBy { it.y }!!.y 89 | 90 | // Generate based off of maximum sizes 91 | val grid: Array = (0..maxY).map { 92 | // Account for zero indexing and flowing off the right side of the map! 93 | CharArray(maxX + 2).apply { fill('.') } 94 | }.toTypedArray() 95 | 96 | // Add all clay spots to the grid 97 | spots.forEach { spot -> 98 | grid[spot] = '#' 99 | } 100 | // Add the fountain 101 | grid[0][500] = '+' 102 | 103 | return Pair(grid, minY) 104 | } 105 | 106 | private fun claySpotsFromInput(input: List): List = 107 | input.flatMap { row -> 108 | val digits = row.toIntArray() 109 | if (row.startsWith("y")) { 110 | (digits[1]..digits[2]).map { Point(it, digits[0]) } 111 | } else { 112 | (digits[1]..digits[2]).map { Point(digits[0], it) } 113 | } 114 | } 115 | 116 | companion object { 117 | private val nonDigits = """[xy=,]""".toRegex() 118 | private val wallOrStill = setOf('#', '~') 119 | private val flowOrStill = setOf('|', '~') 120 | 121 | private fun String.toIntArray(): IntArray = 122 | this.replace(nonDigits, "").replace("..", " ").split(" ").map { it.toInt() }.toIntArray() 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day18.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 18 - Settlers of The North Pole 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/18 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day18/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.util.Arrays 14 | 15 | typealias Forest = Array 16 | 17 | class Day18(rawInput: List) { 18 | 19 | private val forest: Forest = rawInput.map { it.toCharArray() }.toTypedArray() 20 | 21 | fun solvePart1(): Int = 22 | growTrees().drop(9).first().value() 23 | 24 | 25 | fun solvePart2(find: Int = 1_000_000_000): Int { 26 | val seen = mutableMapOf() 27 | var generation = 0 28 | val firstRepeating = growTrees().dropWhile { tree -> 29 | val treeHash = tree.hash() 30 | generation++ 31 | if (treeHash in seen) { 32 | false 33 | } else { 34 | seen[treeHash] = generation 35 | true 36 | } 37 | }.first() 38 | 39 | val cycleLength = generation - seen[firstRepeating.hash()]!! 40 | val remainingSteps = (find - generation) % cycleLength 41 | 42 | // Fast forward to the target 43 | return growTrees(firstRepeating).drop(remainingSteps - 1).first().value() 44 | } 45 | 46 | private fun growTrees(initial: Forest = forest): Sequence = sequence { 47 | var current = initial 48 | while (true) { 49 | current = current.nextGeneration() 50 | yield(current) 51 | } 52 | } 53 | 54 | private fun Forest.nextGeneration(): Array = 55 | this.mapIndexed { y, row -> 56 | row.mapIndexed { x, _ -> this.nextGenerationSpot(Point(x, y)) }.toCharArray() 57 | }.toTypedArray() 58 | 59 | private fun Forest.nextGenerationSpot(at: Point): Char { 60 | val neighborMap = this.countNeighbors(at) 61 | return when (val space = this[at]) { 62 | OPEN -> if (neighborMap.getOrDefault(TREE, 0) >= 3) TREE else OPEN 63 | TREE -> if (neighborMap.getOrDefault(LUMBERYARD, 0) >= 3) LUMBERYARD else TREE 64 | LUMBERYARD -> if (neighborMap.getOrDefault(LUMBERYARD, 0) >= 1 && 65 | neighborMap.getOrDefault(TREE, 0) >= 1) LUMBERYARD else OPEN 66 | else -> space 67 | } 68 | } 69 | 70 | private fun Forest.countNeighbors(at: Point): Map = 71 | at.neighbors(false) 72 | .filterNot { it.x >= this[0].size } 73 | .filterNot { it.y >= this.size } 74 | .map { this[it] } 75 | .groupingBy { it } 76 | .eachCount() 77 | 78 | private fun Forest.value(): Int = 79 | this.flatMap { row -> 80 | row.map { it } 81 | } 82 | .groupingBy { it } 83 | .eachCount() 84 | .run { 85 | getOrDefault(TREE, 0) * getOrDefault(LUMBERYARD, 0) 86 | } 87 | 88 | 89 | private fun Forest.hash(): Int = 90 | Arrays.deepHashCode(this) 91 | 92 | companion object { 93 | private const val OPEN = '.' 94 | private const val LUMBERYARD = '#' 95 | private const val TREE = '|' 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day19.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 19 - Chronal Classification 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/19 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day19/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | 14 | class Day19(rawInput: List) { 15 | 16 | private val instructionPointer: Int = rawInput.first().split(" ")[1].toInt() 17 | private val instructions: List = ElfCodeInstruction.of(rawInput.drop(1)) 18 | 19 | fun solvePart1(): Int = 20 | execute(instructions, instructionPointer).first() 21 | 22 | fun solvePart2(): Int = 23 | 10551288.factors().sum() 24 | 25 | private fun execute(instructions: List, ipBind: Int): Registers { 26 | var registers = IntArray(6) 27 | var ip = registers[ipBind] 28 | while (ip in (0 until instructions.size)) { 29 | registers[ipBind] = ip 30 | val thisInstruction = instructions[ip] 31 | registers = ElfCodeOperations[thisInstruction.name].invoke(registers, thisInstruction) 32 | ip = registers[ipBind] + 1 33 | } 34 | return registers 35 | } 36 | 37 | private fun Int.factors(): List = 38 | (1..this).mapNotNull { n -> 39 | if (this % n == 0) n else null 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day20.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 20 - A Regular Map 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/20 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day20/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.util.ArrayDeque 14 | 15 | 16 | class Day20(rawInput: String) { 17 | 18 | private val grid: Map = parseGrid(rawInput) 19 | 20 | fun solvePart1(): Int = 21 | grid.maxBy { it.value }!!.value 22 | 23 | fun solvePart2(): Int = 24 | grid.count { it.value >= 1000 } 25 | 26 | 27 | private fun parseGrid(input: String): Map { 28 | val grid = mutableMapOf(startingPoint to 0) 29 | val stack = ArrayDeque() 30 | var current = startingPoint 31 | input.forEach { 32 | when (it) { 33 | '(' -> stack.push(current) 34 | ')' -> current = stack.pop() 35 | '|' -> current = stack.peek() 36 | in movementRules -> { 37 | // If we are moving to a spot we haven't seen before, we can 38 | // record this as a new distance. 39 | val nextDistance = grid.getValue(current) + 1 40 | current = movementRules.getValue(it).invoke(current) 41 | grid[current] = minOf(grid.getOrDefault(current, Int.MAX_VALUE), nextDistance) 42 | } 43 | } 44 | } 45 | return grid 46 | } 47 | 48 | companion object { 49 | private val startingPoint = Point(0, 0) 50 | private val movementRules = mapOf( 51 | 'N' to Point::up, 52 | 'S' to Point::down, 53 | 'E' to Point::right, 54 | 'W' to Point::left 55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day21.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 21 - Chronal Conversion 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/21 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day21/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | 14 | class Day21(rawInput: List, private val magicRegister: Int = 4, private val magicInstruction: Int = 28) { 15 | 16 | private val instructionPointer: Int = rawInput.first().split(" ")[1].toInt() 17 | private val instructions: List = ElfCodeInstruction.of(rawInput.drop(1)) 18 | 19 | fun solvePart1(): Int = 20 | execute(instructions, instructionPointer).first() 21 | 22 | fun solvePart2(): Int = 23 | execute(instructions, instructionPointer).last() 24 | 25 | private fun execute(instructions: List, ipBind: Int): Sequence = sequence { 26 | var registers = IntArray(6) 27 | var ip = registers[ipBind] 28 | val seen = LinkedHashSet() 29 | while (ip in (0 until instructions.size)) { 30 | registers[ipBind] = ip 31 | val thisInstruction = instructions[ip] 32 | registers = ElfCodeOperations[thisInstruction.name].invoke(registers, thisInstruction) 33 | ip = registers[ipBind] + 1 34 | if(ip == magicInstruction) { 35 | if(registers[magicRegister] in seen) { 36 | yield(seen.last()) 37 | return@sequence 38 | } 39 | seen += registers[magicRegister] 40 | yield(registers[magicRegister]) 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day22.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 22 - Mode Maze 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/22 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day22/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.util.PriorityQueue 14 | 15 | 16 | class Day22(rawInput: List) { 17 | 18 | private val depth: Int = rawInput.first().substring(7).toInt() 19 | private val target: Point = Point.of(rawInput.drop(1).first().substring(8)) 20 | private val cave = LazyGrid(target, depth) 21 | 22 | fun solvePart1(): Int = 23 | cave.riskLevel() 24 | 25 | fun solvePart2(): Int = 26 | cave.cheapestPath()?.cost ?: throw IllegalStateException("No path?! Really?!") 27 | 28 | private class LazyGrid(val target: Point, val depth: Int) { 29 | private val erosionLevels = mutableMapOf() 30 | 31 | fun riskLevel(at: Point = target): Int = 32 | (0..at.y).flatMap { y -> 33 | (0..at.x).map { x -> 34 | Point(x, y).erosionLevel() % 3 35 | } 36 | }.sum() 37 | 38 | fun cheapestPath(to: Point = target): Traversal? { 39 | val seenMinimumCost: MutableMap, Int> = mutableMapOf(Point.origin to Tool.Torch to 0) 40 | val pathsToEvaluate = PriorityQueue().apply { 41 | add(Traversal(Point.origin, Tool.Torch)) 42 | } 43 | 44 | while (pathsToEvaluate.isNotEmpty()) { 45 | val thisPath = pathsToEvaluate.poll() 46 | 47 | // Found it, and holding the correct tool 48 | if (thisPath.end == to && thisPath.holding == Tool.Torch) { 49 | return thisPath 50 | } 51 | 52 | // Candidates for our next set of decisions 53 | val nextSteps = mutableListOf() 54 | 55 | // Move to each neighbor, holding the same tool. 56 | thisPath.end.cardinalNeighbors(false).forEach { neighbor -> 57 | // Add a Traversal for each if we can go there without changing tools 58 | if (thisPath.holding in neighbor.validTools()) { 59 | // Can keep the tool. 60 | nextSteps += thisPath.copy( 61 | end = neighbor, 62 | cost = thisPath.cost + 1 63 | ) 64 | } 65 | } 66 | 67 | // Stay where we are and switch tools to anything we aren't using (but can) 68 | thisPath.end.validTools().minus(thisPath.holding).forEach { tool -> 69 | nextSteps += Traversal( 70 | end = thisPath.end, 71 | holding = tool, 72 | cost = thisPath.cost + 7 73 | ) 74 | } 75 | 76 | // Of all possible next steps, add the ones we haven't seen, or have seen and we can now do cheaper. 77 | nextSteps.forEach { step -> 78 | val key = Pair(step.end, step.holding) 79 | if (key !in seenMinimumCost || seenMinimumCost.getValue(key) > step.cost) { 80 | pathsToEvaluate += step 81 | seenMinimumCost[key] = step.cost 82 | } 83 | } 84 | } 85 | return null // No path!? Come on... 86 | } 87 | 88 | private fun Point.erosionLevel(): Int { 89 | if (this !in erosionLevels) { 90 | val geo = when { 91 | this in erosionLevels -> erosionLevels.getValue(this) 92 | this in setOf(Point.origin, target) -> 0 93 | y == 0 -> x * 16807 94 | x == 0 -> y * 48271 95 | else -> left.erosionLevel() * up.erosionLevel() 96 | } 97 | erosionLevels[this] = (geo + depth) % 20183 98 | } 99 | return erosionLevels.getValue(this) 100 | } 101 | 102 | private fun Point.validTools(): Set = 103 | when (this) { 104 | Point.origin -> setOf(Tool.Torch) 105 | target -> setOf(Tool.Torch) 106 | else -> Terrain.byErosionLevel(erosionLevel()).tools 107 | } 108 | } 109 | 110 | private data class Traversal(val end: Point, val holding: Tool, val cost: Int = 0) : Comparable { 111 | 112 | override fun compareTo(other: Traversal): Int = 113 | this.cost.compareTo(other.cost) 114 | } 115 | 116 | private enum class Tool { 117 | Torch, 118 | Climbing, 119 | Neither 120 | } 121 | 122 | private enum class Terrain(val modVal: Int, val tools: Set) { 123 | Rocky(0, setOf(Tool.Climbing, Tool.Torch)), 124 | Wet(1, setOf(Tool.Climbing, Tool.Neither)), 125 | Narrow(2, setOf(Tool.Torch, Tool.Neither)); 126 | 127 | companion object { 128 | val values = arrayOf(Rocky, Wet, Narrow) 129 | fun byErosionLevel(level: Int): Terrain = 130 | values.first { it.modVal == level % 3 } 131 | } 132 | 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day23.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 23 - Experimental Emergency Teleportation 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/23 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day23/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import kotlin.math.abs 14 | 15 | 16 | class Day23(rawInput: List) { 17 | 18 | private val swarm: List = rawInput.map { Nanobot.of(it) } 19 | 20 | 21 | fun solvePart1(): Int { 22 | val fattestBot = swarm.maxBy { it.radius }!! 23 | return swarm.count { fattestBot.inRange(it) } 24 | } 25 | 26 | fun solvePart2(): Int { 27 | val neighbors: Map> = swarm.map { bot -> 28 | Pair(bot, swarm.filterNot { it == bot }.filter { bot.withinRangeOfSharedPoint(it) }.toSet()) 29 | }.toMap() 30 | 31 | val clique: Set = BronKerbosch(neighbors).largestClique() 32 | return clique.map { it.location.distanceTo(Point3d.origin) - it.radius }.max()!! 33 | } 34 | 35 | private data class Nanobot(val location: Point3d, val radius: Int) { 36 | 37 | fun inRange(other: Nanobot): Boolean = 38 | location.distanceTo(other.location) <= radius 39 | 40 | fun withinRangeOfSharedPoint(other: Nanobot): Boolean = 41 | location.distanceTo(other.location) <= radius + other.radius 42 | 43 | companion object { 44 | 45 | private val digitsRegex = """^pos=<(-?\d+),(-?\d+),(-?\d+)>, r=(\d+)$""".toRegex() 46 | 47 | fun of(input: String): Nanobot = 48 | digitsRegex.find(input)?.let { 49 | val (x, y, z, r) = it.destructured 50 | Nanobot(Point3d(x.toInt(), y.toInt(), z.toInt()), r.toInt()) 51 | } ?: throw IllegalArgumentException("Cannot parse $input") 52 | 53 | } 54 | } 55 | 56 | private data class Point3d(val x: Int, val y: Int, val z: Int) { 57 | fun distanceTo(other: Point3d): Int = 58 | abs(x - other.x) + abs(y - other.y) + abs(z - other.z) 59 | 60 | companion object { 61 | val origin = Point3d(0, 0, 0) 62 | } 63 | } 64 | 65 | } 66 | 67 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day24.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 24 - Immune System Simulator 20XX 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/24 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day24/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | 14 | class Day24(immuneInput: List, infectionInput: List) { 15 | 16 | private val fighters: List = immuneInput.map { Group.of(Team.ImmuneSystem, it) } + infectionInput.map { Group.of(Team.Infection, it) } 17 | 18 | fun solvePart1(): Int = 19 | fightBattle(fighters).sumBy { it.units } 20 | 21 | fun solvePart2(): Int = 22 | generateSequence(1, Int::inc).mapNotNull { boost -> 23 | val combatants = fightBattle(boostImmuneSystem(boost)) 24 | if (combatants.all { it.team == Team.ImmuneSystem }) combatants.sumBy { it.units } 25 | else null 26 | }.first() 27 | 28 | private fun boostImmuneSystem(boost: Int): List = 29 | fighters.map { 30 | it.copy(unitDamage = it.unitDamage + if (it.team == Team.ImmuneSystem) boost else 0) 31 | } 32 | 33 | // Fight the battle with the given combatants, and return the survivors 34 | private fun fightBattle(combatants: List): List { 35 | var deaths: Int? = null 36 | while (deaths != 0) { 37 | deaths = roundOfFighting(combatants) 38 | } 39 | return combatants.filter { it.alive } 40 | } 41 | 42 | private fun roundOfFighting(combatants: List): Int = 43 | findTargets(combatants) 44 | .sortedByDescending { it.first.initiative } 45 | .filterNot { it.second == null } 46 | .map { (attacker, target) -> 47 | if (attacker.alive) attacker.fight(target!!) 48 | else 0 49 | } 50 | .sum() 51 | 52 | private fun findTargets(combatants: List): Set> { 53 | val alreadyTargeted = mutableSetOf() 54 | return combatants.filter { it.alive } 55 | .sortedWith(compareByDescending { it.effectivePower() }.thenByDescending { it.initiative }) 56 | .map { group -> 57 | group to combatants 58 | .filter { it.alive } // Only fight the living 59 | .filterNot { group.team == it.team } // Only fight the other team 60 | .filterNot { it in alreadyTargeted } // Only fight somebody that isn't already a target 61 | .sortedWith(compareByDescending { group.calculateDamageTo(it) }.thenByDescending { it.effectivePower() }.thenByDescending { it.initiative }) 62 | .filterNot { group.calculateDamageTo(it) == 0 } // Remove any targets that we can't actually damage. 63 | .firstOrNull() // Account for the fact that we *may* not have a target 64 | .also { 65 | // Add our selected target to the targeted list 66 | if (it != null) alreadyTargeted.add(it) 67 | } 68 | } 69 | .toSet() 70 | } 71 | 72 | private enum class Team { 73 | ImmuneSystem, 74 | Infection 75 | } 76 | 77 | private data class Group( 78 | val team: Team, 79 | var units: Int, 80 | val unitHp: Int, 81 | val unitDamage: Int, 82 | val attackType: String, 83 | val initiative: Int, 84 | val weakTo: Set, 85 | val immuneTo: Set, 86 | var alive: Boolean = true 87 | ) { 88 | fun effectivePower(): Int = 89 | units * unitDamage 90 | 91 | fun calculateDamageTo(other: Group): Int = 92 | if (this.team == other.team) 0 93 | else effectivePower() * when (attackType) { 94 | in other.immuneTo -> 0 95 | in other.weakTo -> 2 96 | else -> 1 97 | } 98 | 99 | fun fight(other: Group): Int { 100 | val unitDeath = calculateDamageTo(other) / other.unitHp 101 | other.units -= unitDeath 102 | if (other.units <= 0) { 103 | other.alive = false 104 | } 105 | return unitDeath 106 | } 107 | 108 | companion object { 109 | private val pattern = """^(\d+) units each with (\d+) hit points (\([,; a-z]+\) )?with an attack that does (\d+) (\w+) damage at initiative (\d+)$""".toRegex() 110 | 111 | fun of(team: Team, input: String): Group { 112 | pattern.find(input)?.let { 113 | val (units, unitHp, strongWeak, unitDamage, attackType, initiative) = it.destructured 114 | return Group( 115 | team = team, 116 | units = units.toInt(), 117 | unitHp = unitHp.toInt(), 118 | unitDamage = unitDamage.toInt(), 119 | attackType = attackType, 120 | initiative = initiative.toInt(), 121 | weakTo = parseStrongWeak("weak", strongWeak), 122 | immuneTo = parseStrongWeak("immune", strongWeak) 123 | ) 124 | } 125 | } 126 | 127 | private fun parseStrongWeak(kind: String, input: String): Set = 128 | if (input.isBlank()) emptySet() 129 | else { 130 | val found = input.drop(1).dropLast(2).split("; ").filter { it.startsWith(kind) } 131 | if (found.isEmpty()) { 132 | emptySet() 133 | } else { 134 | found.first().split("to ")[1].split(",").map { it.trim() }.toSet() 135 | } 136 | } 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Day25.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2018, Day 25 - Four-Dimensional Adventure 7 | * 8 | * Problem Description: http://adventofcode.com/2018/day/25 9 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2018/day25/ 10 | */ 11 | package com.ginsberg.advent2018 12 | 13 | import java.lang.Math.abs 14 | import java.util.ArrayDeque 15 | 16 | 17 | class Day25(rawInput: List) { 18 | 19 | private val points: List = rawInput.map { Point4d.of(it) } 20 | 21 | fun solvePart1(): Int = 22 | constellations(mapNeighbors()).count() 23 | 24 | private fun mapNeighbors(): Map> = 25 | points.map { point -> 26 | Pair(point, points.filterNot { it == point }.filter { point.distanceTo(it) <= 3 }.toSet()) 27 | }.toMap() 28 | 29 | private fun constellations(neighbors: Map>): Sequence> = sequence { 30 | val allPoints = neighbors.keys.toMutableList() 31 | while (allPoints.isNotEmpty()) { 32 | val point = allPoints.removeAt(0) 33 | val thisConstellation = mutableSetOf(point) 34 | val foundNeighbors = ArrayDeque(neighbors.getValue(point)) 35 | while (foundNeighbors.isNotEmpty()) { 36 | foundNeighbors.removeFirst().also { 37 | allPoints.remove(it) // Not the basis of a new constellation 38 | thisConstellation.add(it) // Because it is part of our constellation 39 | 40 | // And all this point's neighbors are therefore part of our constellation too 41 | foundNeighbors.addAll(neighbors.getValue(it).filterNot { other -> other in thisConstellation }) 42 | } 43 | } 44 | // We've run out of found neighbors to check, this is a constellation. 45 | yield(thisConstellation) 46 | } 47 | } 48 | 49 | private data class Point4d(val x: Int, val y: Int, val z: Int, val t: Int) { 50 | 51 | fun distanceTo(other: Point4d): Int = 52 | abs(x - other.x) + abs(y - other.y) + abs(z - other.z) + abs(t - other.t) 53 | 54 | companion object { 55 | fun of(input: String): Point4d { 56 | val (x, y, z, t) = input.split(",").map { it.trim().toInt() } 57 | return Point4d(x, y, z, t) 58 | } 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/ElfCode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | data class ElfCodeInstruction(val name: String, val a: Int, val b: Int, val c: Int) { 8 | companion object { 9 | fun of(input: List): List = 10 | input.map { 11 | val (op, a, b, c) = it.split(" ") 12 | ElfCodeInstruction(op, a.toInt(), b.toInt(), c.toInt()) 13 | } 14 | } 15 | } 16 | 17 | object ElfCodeOperations { 18 | 19 | private val operations: Map Registers> = mapOf( 20 | "addr" to ::addr, 21 | "addi" to ::addi, 22 | "mulr" to ::mulr, 23 | "muli" to ::muli, 24 | "banr" to ::banr, 25 | "bani" to ::bani, 26 | "borr" to ::borr, 27 | "bori" to ::bori, 28 | "setr" to ::setr, 29 | "seti" to ::seti, 30 | "gtir" to ::gtir, 31 | "gtri" to ::gtri, 32 | "gtrr" to ::gtrr, 33 | "eqir" to ::eqir, 34 | "eqri" to ::eqri, 35 | "eqrr" to ::eqrr 36 | ) 37 | 38 | operator fun get(key: String): (Registers, ElfCodeInstruction) -> Registers = 39 | operations[key]!! 40 | 41 | private fun addr(registers: Registers, instruction: ElfCodeInstruction): Registers = 42 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] + registers[instruction.b] } 43 | 44 | private fun addi(registers: Registers, instruction: ElfCodeInstruction): Registers = 45 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] + instruction.b } 46 | 47 | private fun mulr(registers: Registers, instruction: ElfCodeInstruction): Registers = 48 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] * registers[instruction.b] } 49 | 50 | private fun muli(registers: Registers, instruction: ElfCodeInstruction): Registers = 51 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] * instruction.b } 52 | 53 | private fun banr(registers: Registers, instruction: ElfCodeInstruction): Registers = 54 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] and registers[instruction.b] } 55 | 56 | private fun bani(registers: Registers, instruction: ElfCodeInstruction): Registers = 57 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] and instruction.b } 58 | 59 | private fun borr(registers: Registers, instruction: ElfCodeInstruction): Registers = 60 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] or registers[instruction.b] } 61 | 62 | private fun bori(registers: Registers, instruction: ElfCodeInstruction): Registers = 63 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] or instruction.b } 64 | 65 | private fun setr(registers: Registers, instruction: ElfCodeInstruction): Registers = 66 | registers.copyOf().apply { this[instruction.c] = registers[instruction.a] } 67 | 68 | private fun seti(registers: Registers, instruction: ElfCodeInstruction): Registers = 69 | registers.copyOf().apply { this[instruction.c] = instruction.a } 70 | 71 | private fun gtir(registers: Registers, instruction: ElfCodeInstruction): Registers = 72 | registers.copyOf().apply { this[instruction.c] = if (instruction.a > registers[instruction.b]) 1 else 0 } 73 | 74 | private fun gtri(registers: Registers, instruction: ElfCodeInstruction): Registers = 75 | registers.copyOf().apply { this[instruction.c] = if (registers[instruction.a] > instruction.b) 1 else 0 } 76 | 77 | private fun gtrr(registers: Registers, instruction: ElfCodeInstruction): Registers = 78 | registers.copyOf().apply { this[instruction.c] = if (registers[instruction.a] > registers[instruction.b]) 1 else 0 } 79 | 80 | private fun eqir(registers: Registers, instruction: ElfCodeInstruction): Registers = 81 | registers.copyOf().apply { this[instruction.c] = if (instruction.a == registers[instruction.b]) 1 else 0 } 82 | 83 | private fun eqri(registers: Registers, instruction: ElfCodeInstruction): Registers = 84 | registers.copyOf().apply { this[instruction.c] = if (registers[instruction.a] == instruction.b) 1 else 0 } 85 | 86 | private fun eqrr(registers: Registers, instruction: ElfCodeInstruction): Registers = 87 | registers.copyOf().apply { this[instruction.c] = if (registers[instruction.a] == registers[instruction.b]) 1 else 0 } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Extensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import kotlin.math.absoluteValue 8 | 9 | /** 10 | * Constantly loop through the given List, turning it into a sequence 11 | * that does not end. 12 | */ 13 | fun List.toInfiniteSequence(): Sequence = sequence { 14 | if (this@toInfiniteSequence.isEmpty()) { 15 | return@sequence 16 | } 17 | while (true) { 18 | yieldAll(this@toInfiniteSequence) 19 | } 20 | } 21 | 22 | /** 23 | * Find the most commonly occurring element in the Iterable 24 | */ 25 | fun Iterable.mostFrequent(): T? = 26 | this.groupBy { it }.maxBy { it.value.size }?.key 27 | 28 | /** 29 | * Find the absolute span of this IntRange. 30 | * This is a property rather than a function because the answer cannot change. 31 | */ 32 | val IntRange.span: Long 33 | get() = 34 | (this.last.toLong() - this.first.toLong()).absoluteValue 35 | 36 | operator fun Array.get(point: Point): Char = 37 | this[point.y][point.x] 38 | 39 | operator fun Array.set(point: Point, to: Char) { 40 | this[point.y][point.x] = to 41 | } 42 | 43 | operator fun Array.contains(point: Point): Boolean = 44 | point.x >= 0 && point.x < this[0].size && point.y >= 0 && point.y < this.size 45 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Point.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import kotlin.math.abs 8 | 9 | data class Point(val x: Int, val y: Int) : Comparable { 10 | 11 | fun distanceTo(otherX: Int, otherY: Int): Int = 12 | abs(x - otherX) + abs(y - otherY) 13 | 14 | fun distanceTo(other: Point): Int = 15 | distanceTo(other.x, other.y) 16 | 17 | val up by lazy { Point(x, y - 1) } 18 | val down by lazy { Point(x, y + 1) } 19 | val left by lazy { Point(x - 1, y) } 20 | val right by lazy { Point(x + 1, y) } 21 | 22 | fun cardinalNeighbors(allowNegative: Boolean = true): List = 23 | // Note: Generate in reading order! 24 | listOf( 25 | Point(x, y - 1), 26 | Point(x - 1, y), 27 | Point(x + 1, y), 28 | Point(x, y + 1) 29 | ).filter { allowNegative || it.x >= 0 && it.y >= 0 } 30 | 31 | fun neighbors(allowNegative: Boolean = true): List = 32 | // Note: Generate in reading order! 33 | listOf( 34 | Point(x - 1, y - 1), 35 | Point(x, y - 1), 36 | Point(x + 1, y - 1), 37 | Point(x - 1, y), 38 | Point(x + 1, y), 39 | Point(x - 1, y + 1), 40 | Point(x, y + 1), 41 | Point(x + 1, y + 1) 42 | ).filter { allowNegative || it.x >= 0 && it.y >= 0 } 43 | 44 | override fun compareTo(other: Point): Int = 45 | when { 46 | y < other.y -> -1 47 | y > other.y -> 1 48 | x < other.x -> -1 49 | x > other.x -> 1 50 | else -> 0 51 | } 52 | 53 | companion object { 54 | val origin = Point(0, 0) 55 | 56 | fun of(input: String): Point = 57 | input.split(",") 58 | .map { it.trim().toInt() } 59 | .run { Point(this[0], this[1]) } 60 | } 61 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2018/Resources.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import java.io.File 8 | 9 | internal object Resources { 10 | fun resourceAsString(fileName: String, delimiter: String = ""): String = 11 | File(Resources.javaClass.classLoader.getResource(fileName).toURI()) 12 | .readLines() 13 | .reduce { a, b -> "$a$delimiter$b" } 14 | 15 | fun resourceAsList(fileName: String): List = 16 | File(Resources.javaClass.classLoader.getResource(fileName).toURI()) 17 | .readLines() 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/main/resources/day01_input.txt: -------------------------------------------------------------------------------- 1 | -2 2 | -3 3 | +4 4 | -15 5 | -15 6 | +18 7 | -7 8 | +11 9 | -16 10 | -14 11 | +2 12 | -6 13 | +16 14 | +6 15 | +14 16 | -15 17 | +12 18 | -5 19 | +17 20 | -10 21 | -20 22 | -19 23 | -14 24 | -10 25 | +4 26 | -11 27 | +10 28 | -1 29 | +12 30 | -17 31 | -2 32 | +1 33 | -17 34 | +9 35 | +4 36 | +19 37 | +11 38 | -17 39 | +15 40 | -12 41 | +5 42 | +4 43 | -1 44 | -10 45 | -19 46 | -16 47 | -9 48 | +18 49 | +2 50 | +4 51 | -19 52 | +16 53 | +6 54 | -16 55 | -14 56 | +7 57 | -9 58 | +7 59 | +17 60 | +17 61 | -14 62 | +6 63 | -22 64 | -13 65 | -2 66 | -1 67 | -18 68 | -3 69 | +19 70 | +19 71 | +16 72 | -22 73 | +14 74 | -2 75 | -3 76 | +2 77 | -18 78 | -15 79 | -14 80 | -4 81 | -15 82 | +1 83 | -3 84 | -8 85 | +18 86 | -11 87 | +6 88 | -7 89 | +17 90 | +7 91 | -8 92 | -13 93 | -4 94 | +7 95 | -15 96 | -11 97 | +7 98 | +9 99 | -7 100 | +1 101 | -20 102 | -19 103 | -18 104 | -17 105 | -12 106 | +7 107 | -16 108 | -11 109 | -4 110 | -8 111 | -4 112 | -3 113 | -2 114 | +3 115 | -15 116 | +18 117 | +5 118 | +14 119 | +15 120 | +2 121 | -19 122 | +5 123 | -13 124 | +19 125 | +9 126 | +8 127 | +5 128 | -1 129 | -19 130 | +11 131 | +2 132 | +13 133 | -17 134 | +9 135 | -16 136 | +14 137 | +20 138 | +12 139 | +8 140 | +10 141 | +17 142 | -15 143 | -8 144 | +15 145 | +19 146 | -14 147 | -3 148 | -10 149 | +2 150 | +4 151 | -1 152 | +14 153 | -12 154 | +15 155 | -2 156 | -11 157 | -14 158 | -18 159 | +6 160 | -12 161 | +7 162 | +18 163 | +15 164 | +6 165 | +12 166 | +3 167 | -6 168 | +17 169 | +11 170 | +14 171 | +13 172 | +3 173 | +6 174 | -11 175 | -19 176 | -5 177 | +14 178 | -10 179 | -7 180 | +18 181 | -8 182 | -13 183 | -2 184 | +19 185 | -18 186 | -17 187 | +11 188 | +14 189 | +17 190 | +1 191 | +26 192 | +6 193 | +15 194 | +21 195 | -5 196 | +12 197 | +6 198 | +4 199 | +10 200 | -8 201 | +16 202 | -14 203 | +4 204 | -1 205 | +17 206 | -15 207 | -23 208 | +15 209 | +18 210 | +19 211 | +10 212 | -18 213 | -2 214 | +15 215 | +15 216 | +13 217 | +5 218 | +10 219 | -8 220 | +2 221 | -18 222 | +13 223 | +15 224 | +8 225 | -19 226 | +2 227 | -4 228 | -3 229 | +20 230 | -3 231 | +12 232 | +6 233 | +13 234 | +13 235 | -15 236 | +6 237 | -15 238 | +3 239 | +7 240 | -19 241 | +11 242 | +17 243 | +15 244 | -4 245 | -10 246 | -14 247 | -20 248 | +18 249 | -11 250 | -17 251 | +8 252 | +12 253 | +3 254 | -11 255 | +7 256 | -13 257 | -4 258 | +19 259 | -7 260 | -17 261 | +12 262 | +9 263 | +13 264 | +7 265 | -13 266 | +24 267 | -2 268 | +14 269 | -5 270 | +10 271 | -6 272 | -1 273 | -8 274 | -5 275 | -6 276 | +5 277 | +12 278 | +16 279 | +5 280 | -14 281 | +19 282 | +18 283 | -9 284 | -6 285 | -12 286 | -2 287 | +19 288 | -12 289 | -9 290 | +5 291 | -4 292 | -9 293 | -9 294 | +16 295 | -19 296 | -14 297 | -7 298 | -24 299 | -20 300 | +16 301 | +12 302 | +19 303 | +20 304 | -15 305 | +26 306 | +21 307 | -2 308 | +12 309 | +4 310 | -2 311 | +18 312 | -17 313 | -12 314 | -20 315 | +2 316 | +9 317 | +14 318 | +16 319 | +12 320 | -9 321 | +14 322 | +17 323 | -19 324 | +11 325 | +3 326 | -13 327 | -3 328 | +11 329 | -14 330 | +18 331 | +9 332 | -16 333 | -2 334 | +19 335 | +7 336 | -10 337 | -3 338 | +4 339 | +10 340 | +15 341 | +19 342 | -2 343 | -5 344 | +2 345 | +2 346 | -11 347 | +6 348 | -17 349 | -11 350 | +6 351 | -10 352 | +16 353 | +7 354 | -1 355 | -2 356 | +19 357 | +6 358 | +16 359 | -12 360 | +14 361 | -5 362 | +19 363 | -12 364 | +1 365 | -6 366 | -6 367 | -2 368 | +7 369 | +19 370 | +17 371 | -4 372 | +3 373 | +3 374 | +17 375 | +16 376 | -2 377 | -10 378 | -1 379 | -14 380 | -2 381 | -17 382 | -11 383 | +3 384 | -21 385 | +15 386 | +11 387 | +7 388 | -3 389 | -18 390 | +1 391 | -15 392 | -11 393 | +1 394 | -18 395 | +11 396 | +15 397 | -17 398 | -16 399 | -19 400 | +9 401 | -5 402 | +16 403 | -18 404 | +13 405 | +16 406 | -17 407 | -1 408 | -3 409 | -2 410 | +20 411 | +14 412 | -13 413 | -17 414 | +13 415 | +5 416 | +2 417 | +19 418 | +22 419 | -3 420 | -22 421 | +10 422 | -13 423 | +2 424 | -29 425 | -27 426 | -16 427 | +17 428 | -27 429 | +18 430 | -13 431 | -4 432 | +6 433 | -5 434 | +12 435 | -16 436 | -9 437 | +3 438 | +1 439 | +10 440 | -25 441 | -1 442 | -19 443 | +13 444 | +12 445 | +2 446 | -6 447 | -12 448 | +3 449 | +25 450 | +28 451 | -4 452 | +2 453 | +17 454 | -9 455 | +63 456 | +23 457 | -8 458 | +9 459 | -6 460 | +15 461 | -14 462 | +12 463 | +6 464 | +18 465 | -6 466 | -15 467 | +12 468 | -16 469 | -3 470 | +15 471 | +24 472 | +19 473 | -6 474 | +4 475 | -8 476 | -19 477 | +4 478 | +4 479 | -20 480 | -1 481 | +24 482 | +10 483 | -9 484 | +13 485 | +11 486 | +2 487 | +11 488 | +14 489 | -2 490 | +18 491 | -12 492 | +1 493 | -17 494 | +6 495 | +1 496 | -16 497 | +10 498 | +4 499 | +9 500 | -6 501 | +10 502 | -14 503 | -2 504 | +22 505 | +2 506 | +6 507 | +10 508 | -19 509 | -24 510 | +10 511 | +11 512 | +14 513 | +2 514 | +5 515 | +18 516 | +29 517 | +1 518 | +20 519 | +7 520 | +3 521 | -12 522 | +25 523 | -21 524 | +24 525 | +4 526 | -18 527 | +1 528 | +51 529 | +19 530 | -17 531 | -23 532 | +31 533 | -15 534 | +27 535 | +2 536 | +19 537 | -16 538 | +1 539 | +18 540 | +9 541 | +22 542 | +6 543 | +15 544 | -19 545 | +14 546 | -7 547 | +3 548 | +14 549 | -7 550 | -15 551 | +18 552 | -8 553 | -1 554 | -14 555 | -7 556 | -16 557 | +22 558 | +22 559 | -2 560 | +18 561 | +2 562 | -15 563 | -39 564 | +5 565 | +21 566 | -5 567 | -2 568 | +4 569 | +1 570 | +9 571 | -58 572 | +6 573 | -95 574 | -85 575 | -5 576 | +1 577 | +7 578 | +9 579 | +15 580 | -117 581 | -12 582 | -14 583 | -18 584 | +70 585 | +9 586 | -17 587 | +93 588 | -37 589 | -134 590 | -90 591 | +22 592 | -19 593 | -7 594 | -59 595 | +14 596 | -13 597 | -47 598 | +213 599 | +81022 600 | +9 601 | +5 602 | +4 603 | -3 604 | -16 605 | -2 606 | +4 607 | +2 608 | +5 609 | -12 610 | -9 611 | -13 612 | +2 613 | -18 614 | -18 615 | -14 616 | +7 617 | +18 618 | -19 619 | +13 620 | -1 621 | -6 622 | +9 623 | -1 624 | -18 625 | +15 626 | -14 627 | -4 628 | +12 629 | -1 630 | +5 631 | +16 632 | -7 633 | +12 634 | +6 635 | -16 636 | +13 637 | +10 638 | +3 639 | -11 640 | -13 641 | +6 642 | -7 643 | +16 644 | +3 645 | -6 646 | +19 647 | -15 648 | +14 649 | -1 650 | +19 651 | +19 652 | +13 653 | -9 654 | -3 655 | -10 656 | -14 657 | +15 658 | -9 659 | +19 660 | -6 661 | +10 662 | -7 663 | +11 664 | -1 665 | +3 666 | +2 667 | -3 668 | +8 669 | +3 670 | +13 671 | +6 672 | +3 673 | +2 674 | +18 675 | +9 676 | -17 677 | +13 678 | +15 679 | -13 680 | +9 681 | +2 682 | +19 683 | +14 684 | -13 685 | +8 686 | +18 687 | +6 688 | -4 689 | -18 690 | +1 691 | -19 692 | -1 693 | +10 694 | -5 695 | -11 696 | -10 697 | -16 698 | -4 699 | -5 700 | +3 701 | -13 702 | -19 703 | -18 704 | +16 705 | +16 706 | -5 707 | +16 708 | -10 709 | -8 710 | +9 711 | +14 712 | +1 713 | +9 714 | -3 715 | +19 716 | -12 717 | +11 718 | +12 719 | +5 720 | +19 721 | -9 722 | +4 723 | +15 724 | +19 725 | -4 726 | -10 727 | -12 728 | -18 729 | -16 730 | +13 731 | -4 732 | -16 733 | -14 734 | -15 735 | +18 736 | +1 737 | -8 738 | -7 739 | -18 740 | +3 741 | -21 742 | +9 743 | -7 744 | +8 745 | +18 746 | +2 747 | -11 748 | +6 749 | +10 750 | +9 751 | +11 752 | -21 753 | +19 754 | +4 755 | +2 756 | +7 757 | +10 758 | -16 759 | +13 760 | +9 761 | +9 762 | +16 763 | +9 764 | +13 765 | -11 766 | +16 767 | +10 768 | +14 769 | +13 770 | -5 771 | -10 772 | -16 773 | -2 774 | -2 775 | +6 776 | +19 777 | +1 778 | -16 779 | +14 780 | -13 781 | +3 782 | -5 783 | -4 784 | +12 785 | -5 786 | +22 787 | +11 788 | -5 789 | +13 790 | +4 791 | +13 792 | +19 793 | +18 794 | -13 795 | +15 796 | +19 797 | -12 798 | -11 799 | -19 800 | -12 801 | +5 802 | -19 803 | +18 804 | -19 805 | +5 806 | -13 807 | -10 808 | +15 809 | -8 810 | -2 811 | -2 812 | -11 813 | -6 814 | +5 815 | -4 816 | +21 817 | +18 818 | -5 819 | +18 820 | -11 821 | +19 822 | +12 823 | -5 824 | +4 825 | -16 826 | -10 827 | +11 828 | -16 829 | +13 830 | +11 831 | -1 832 | +15 833 | +4 834 | +13 835 | -15 836 | +14 837 | -7 838 | +19 839 | +10 840 | -8 841 | +19 842 | +4 843 | -7 844 | +19 845 | +8 846 | +14 847 | -7 848 | +3 849 | +13 850 | +19 851 | -9 852 | +4 853 | -17 854 | -19 855 | -11 856 | -11 857 | -4 858 | -16 859 | -21 860 | -5 861 | +1 862 | +16 863 | -11 864 | -15 865 | -18 866 | -13 867 | -7 868 | -13 869 | -21 870 | -18 871 | +10 872 | +14 873 | +13 874 | -7 875 | -1 876 | -4 877 | +17 878 | +20 879 | +12 880 | -24 881 | +3 882 | -8 883 | +3 884 | +10 885 | +11 886 | +11 887 | -16 888 | +13 889 | +12 890 | +19 891 | -2 892 | +7 893 | +6 894 | +5 895 | +3 896 | +10 897 | +15 898 | +2 899 | +11 900 | +14 901 | -9 902 | -1 903 | -19 904 | -16 905 | +9 906 | +17 907 | -13 908 | +4 909 | +6 910 | +2 911 | +13 912 | +16 913 | +19 914 | +12 915 | +1 916 | +18 917 | +17 918 | +19 919 | +5 920 | -8 921 | +6 922 | +10 923 | +16 924 | -9 925 | +13 926 | -8 927 | -9 928 | +5 929 | -12 930 | -7 931 | -16 932 | +4 933 | -12 934 | +18 935 | -19 936 | -7 937 | +2 938 | +2 939 | -19 940 | +10 941 | +19 942 | +9 943 | -6 944 | -18 945 | +4 946 | +18 947 | -11 948 | -13 949 | -11 950 | -16 951 | +3 952 | -4 953 | -11 954 | -2 955 | +10 956 | -14 957 | +16 958 | +14 959 | -1 960 | +2 961 | +1 962 | +4 963 | -9 964 | +17 965 | -5 966 | -14 967 | -15 968 | -13 969 | +16 970 | -8 971 | -11 972 | +2 973 | +19 974 | +23 975 | +15 976 | -13 977 | +20 978 | +3 979 | +7 980 | +9 981 | +17 982 | +10 983 | -11 984 | -19 985 | -19 986 | +9 987 | -17 988 | +12 989 | -20 990 | -22 991 | +16 992 | -9 993 | -18 994 | -10 995 | -9 996 | -81046 997 | -------------------------------------------------------------------------------- /src/main/resources/day02_input.txt: -------------------------------------------------------------------------------- 1 | zihrtxagncfpbsnolxydujjmqv 2 | zihrtxagwcfpbsoolnydukjyqv 3 | aihrtxagwcfpbsnoleybmkjmqv 4 | zihrtxagwcfpbsnolgyduajmrv 5 | zihrtxgmwcfpbunoleydukjmqv 6 | zihqtxagwcfpbsnolesdukomqv 7 | zihgtxagwcfpbsnoleydqkjqqv 8 | dihrtxagwcqpbsnoleydpkjmqv 9 | qihrtvagwcfpbsnollydukjmqv 10 | zihrtgagwcfpbknoleyrukjmqv 11 | cinrtxagwcfpbsnoleydukjaqv 12 | zihrtxagwcfubsneleyvukjmqv 13 | zihrtxagwcfpbsvoleydukvmtv 14 | zihrtpagwcffbsnolfydukjmqv 15 | zihrtxagwcfpbsxoleydtkjyqv 16 | zohrvxugwcfpbsnoleydukjmqv 17 | zyhrtxagdcfpbsnodeydukjmqv 18 | zihrtxaghffpbsnoleyduojmqv 19 | oihrtbagwcfpbsnoleyduejmqv 20 | zihrtnagwcvpjsnoleydukjmqv 21 | iihrtxagwcfpbsnoliyaukjmqv 22 | ziartxagwcfpbsnokeydukjmpv 23 | eibrtxagwccpbsnoleydukjmqv 24 | zihrtxagwczwbsaoleydukjmqv 25 | ziiatuagwcfpbsnoleydukjmqv 26 | zzhrtxagwckpbsnsleydukjmqv 27 | cihrtxaqwcfpbsnoleydkkjmqv 28 | zihrtxaywcfpbsnoleydukzdqv 29 | zihrtxagwjfpbvnoleydukjmql 30 | zihrtxagwcfpbsnoleuduksmql 31 | zizrtxxgwcfpbsnoleydukzmqv 32 | zihrteagwcfpbsnobeydukjmqe 33 | zihrtxafwhfpbsgoleydukjmqv 34 | zitrtxagwcfpbsnoleyduvymqv 35 | zihrtxauwcfebsnoleygukjmqv 36 | zihrtxagwcfpbsnoleydubjrqh 37 | zihrtxauwmfpbsnoleydukjmqo 38 | zihrtxagwcdpbsnoleydukxmov 39 | zihrtmagwcfpbsnoleydukvmlv 40 | ziwrtxhgwcfpbsnoleodukjmqv 41 | zihytxagacfpbsnoceydukjmqv 42 | zihrtxagwcfpbsnolebdugjnqv 43 | zihrzxagwcfpbsnjleyduktmqv 44 | zihrtxygwcfpbinoleysukjmqv 45 | zihrtxagwcfpbmnoveydujjmqv 46 | zidrtxagwcfpbsnolexaukjmqv 47 | zshrtxagwcepbsnoxeydukjmqv 48 | yibrtxagwzfpbsnoleydukjmqv 49 | zehrtxagwclpbsnoleymukjmqv 50 | zihruxagwcfpbsnoleyhukwmqv 51 | zihrwxagwcfpbszolesdukjmqv 52 | zihrtpagwcfpbwnoleyuukjmqv 53 | ziortxagwcfpssnolewdukjmqv 54 | zohrtxagwcfpbwnoleydukjmjv 55 | zihrtxagwcfpbsnvleyduzcmqv 56 | zihrvxaghcfpbswoleydukjmqv 57 | zihrtxagwcfpssnolwydukzmqv 58 | zjhrttagwcfpbsnolfydukjmqv 59 | zihrtxagwjfpbsnoljydukpmqv 60 | ziwrtxagwczpbsnoljydukjmqv 61 | zinrtxagwcfpbvfoleydukjmqv 62 | zihrgragwcfpbsnoleydutjmqv 63 | zihrtxagwcfpbsnozeydukffqv 64 | zihrtxagwcfpbsmoleydxkumqv 65 | rihwtxagwcfpbsxoleydukjmqv 66 | ziqrtxagwcfpbsnqlevdukjmqv 67 | zihrtxagwchpbsnoleydufamqv 68 | sihrtxagwcfpbsnoleldukjmqp 69 | zihrtxagwcrpbsnoleydvojmqv 70 | zihrtxacwcfpbsnoweyxukjmqv 71 | zihrtxagwcfpbsnolajmukjmqv 72 | zzfrtxagwcfpbsnoleydukjmvv 73 | zixrtxagwcfpbqnoleydukjgqv 74 | zihitxaqwcfpbsnoleadukjmqv 75 | zilrtxagecfxbsnoleydukjmqv 76 | zihrtxagwcfpbypoleycukjmqv 77 | zidrtxagdtfpbsnoleydukjmqv 78 | lehrtxagxcfpbsnoleydukjmqv 79 | zihrlxagwcfpbsncneydukjmqv 80 | zihroxagbcspbsnoleydukjmqv 81 | zihrtxagwcfkzsnolemdukjmqv 82 | zihrtxagwcfpbsqeleydukkmqv 83 | zihrjxagwcfpesnolxydukjmqv 84 | zifrtxagwcfpbsooleydukkmqv 85 | zirwtxagwcfpbsnoleydukzmqv 86 | zjhntxagwcfpbsnoleydunjmqv 87 | ziorexagwcfpbsnoyeydukjmqv 88 | zhhrtlagwcfybsnoleydukjmqv 89 | zirrtxagwvfsbsnoleydukjmqv 90 | bihrtxagwofpbsnoleadukjmqv 91 | dihrtxagwcfpksnoleydukjlqv 92 | zihrrxagecfpbsnoleydukjmyv 93 | zijrtxagwmfpbsnoleyduljmqv 94 | zihrtxagwcfpbsnolecdukjpqs 95 | zchrtxagwcfpbsnolehdukjmwv 96 | rmhrtxagwcfpbsnoleydkkjmqv 97 | zohrotagwcfpbsnoleydukjmqv 98 | zihwtxagsifpbsnwleydukjmqv 99 | zihrtxagicfpbsnoleydukjxqn 100 | zihrtxsgwcfpbsntleydumjmqv 101 | zihrlxagzgfpbsnoleydukjmqv 102 | aihjtxagwdfpbsnoleydukjmqv 103 | zifrtxagwcfhbsnoleddukjmqv 104 | zihrtyagwcfpbsooleydtkjmqv 105 | zihrtxxgwcfpbsnolerhukjmqv 106 | zihqtxalwcfppsnoleydukjmqv 107 | zfkrvxagwcfpbsnoleydukjmqv 108 | zihptxagwcfpbseoleydukjmdv 109 | zihrtxagwcfpeonoleyiukjmqv 110 | nidrtxagwcfpbsnoleyhukjmqv 111 | zihrtxagwcfjbsnolsydukjmqg 112 | zghryxagwcfgbsnoleydukjmqv 113 | zihwtxagwcfpbsnoleydugjfqv 114 | zihryxagwjfpbsnoleydujjmqv 115 | zihrtxagwcfpbsnolekdukymql 116 | zfhrtxaownfpbsnoleydukjmqv 117 | zamrtxagwcfpbsnoleyduzjmqv 118 | ibhrtxagwcfpbsnoleydukjmfv 119 | zihrtxagwcfpssnoseydukjmuv 120 | zihrtxagwcfpbsnoljydukjhqs 121 | zihrtxagwqfmbsnoleidukjmqv 122 | zfdrtxagwchpbsnoleydukjmqv 123 | iihrtxagqcfpbsnoleydukjmqn 124 | mihrtxagwcfpbsqoleydukjbqv 125 | zihttxagwcfpbsnoleyduljmqk 126 | zzhrtxagwcfpzseoleydukjmqv 127 | zdhrtxagbcfpbsnoleyduyjmqv 128 | zihxtxagwcfpbsnolwrdukjmqv 129 | zghrtxagwcypbynoleydukjmqv 130 | zihrtxaiwcfppsnoleydukgmqv 131 | zitatxagwcfobsnoleydukjmqv 132 | znhrtxagwcfpysnoleydukjqqv 133 | zihrtxagwcfppsnoleoyukjmqv 134 | ziorgxagwcfpbsnolekdukjmqv 135 | zihrtxagwcfpbfnoleydwkjpqv 136 | zihrtxnrwcfpbsnolnydukjmqv 137 | rihrtxagwcfpbsnolepdjkjmqv 138 | zihrtxagwcfzbsnoceydukjmkv 139 | zihrtxagwcfpysnoaeidukjmqv 140 | zihrmxagwcfpbsnoleydukjmuq 141 | gihrtxagwcvpbsnoleydukcmqv 142 | zihrtxagocfpbsnoleydukqmnv 143 | zihrtxagwcfpesnoleyluklmqv 144 | zghrtxagwcfzbsnoleydukjmgv 145 | zihrtxugqqfpbsnoleydukjmqv 146 | zirrtcagwcfpbsnoleydfkjmqv 147 | zihitxagwcfpjsnoleydnkjmqv 148 | zihrtxqgwcfpbsnsleydukjmqy 149 | iihrtxagwyfpbsnoleydukjmqu 150 | zihrsxagwcfpbsnsleydukzmqv 151 | zihrtxawwcfpbsnoleydzkjmuv 152 | dihrkxagwcfpbsfoleydukjmqv 153 | zihrtxaqwcfpbvnoleydukjmqt 154 | zihntxdgwcfpbsnogeydukjmqv 155 | zihrtxagwcdpxsnolxydukjmqv 156 | zihrtxagwcfpbsaoleydunjaqv 157 | zihrtyagwcfpbsnoleyduqjmqt 158 | zihrtxagwtfpbsnoleoyukjmqv 159 | zihrjiagwcfpbsnobeydukjmqv 160 | zihrtxqgwcfpbsnoleydykdmqv 161 | zihrhxmgwcfpbsnmleydukjmqv 162 | zihatxlgwcfpbsnoleydukpmqv 163 | zihrtxcgwcspbsnoleypukjmqv 164 | zihrtkagqcfpbsaoleydukjmqv 165 | ziqrtxagwcfabsnoleydukrmqv 166 | zihwtxagwifpbsnwleydukjmqv 167 | zitrtnagwcfpbsnoleddukjmqv 168 | wihrtxagwcfpbsioyeydukjmqv 169 | zihrtxagwclpystoleydukjmqv 170 | zihmtxagwcfpbsnolfydukjmlv 171 | zihrtxagechpbsnoleydutjmqv 172 | zihrtxagwcfebsnolnydukjmuv 173 | zihrtxagncmpbsnoleydukjmqs 174 | zihrvxagocfpbsnoleydukcmqv 175 | zihrtxagwcjcbsnolejdukjmqv 176 | wihrtxagwcfpbogoleydukjmqv 177 | kivrtxagwcfpgsnoleydukjmqv 178 | zihrtxagwafpbhnoleydukjcqv 179 | zihrtwagtcfpbsnolxydukjmqv 180 | vihrtxagwcfpbsneletdukjmqv 181 | zihlnxagwcfpbsnoleydukjmqb 182 | zihrtxagwcfpbsnoleydukjuuc 183 | zihrtxagwcfpbwntleadukjmqv 184 | fihrtxagwcfpbsnoleydvkjmqw 185 | zihrtxaowcfpbunoleyduljmqv 186 | zthrtxagwcfpbtnoleydukomqv 187 | xihltxagwcfpbsnoleydukjrqv 188 | ziyrnxagwcfpbsnoleydukjmhv 189 | zihrtxazwcfpbsnileyduejmqv 190 | zihrtxagwcfibsnoliydukjmsv 191 | zihrtxggwcfpbsnoleydugjmqj 192 | zrartxagwcffbsnoleydukjmqv 193 | zidrtxaqwcfpbsnoleyduksmqv 194 | zirrtxagwcypbsnoleydtkjmqv 195 | rihrtxagwcrpbsnoheydukjmqv 196 | zihrtxagwcfpbsnoleydpkjmzs 197 | zihrtxagbcfpbsnodbydukjmqv 198 | fihrtxaqwcfpbsnolaydukjmqv 199 | vihrtxbgwcfpbsnolemdukjmqv 200 | zihrtxapwcfubsnoleydukmmqv 201 | zihrtxagwcfpbgnolfydunjmqv 202 | zihrtxagwcypbsnokeyduvjmqv 203 | zihntxagwcfpbsnoieydukbmqv 204 | zihbtxagwkfpbsnolpydukjmqv 205 | zihrtxagwcfibsnoleydikjmqb 206 | jihrtxvgwcfpbsnoleydukjmqp 207 | zihrtxagwcfpbjnqleydukjmlv 208 | zibrtxagwcfpbzvoleydukjmqv 209 | zihrtxagwafgbsnbleydukjmqv 210 | zihjctagwcfpbsnoleydukjmqv 211 | zahrtxagwcepbsnoleddukjmqv 212 | zihetxagwcfpbsnoleydumjmsv 213 | zihrtvagwcfpbbnoleydukdmqv 214 | zbhrxxagwkfpbsnoleydukjmqv 215 | jfhrtxagwcftbsnoleydukjmqv 216 | yihrtxagwcfvbsnoleyduksmqv 217 | ziartxaewcfpbsnoleyduhjmqv 218 | zihrtxagwcfpbsnoozyduzjmqv 219 | cihotxagwcfpysnoleydukjmqv 220 | zihrtxagwcfpusnolwydxkjmqv 221 | zihrtxagwcfpbsnoleedmgjmqv 222 | zihrtxaghcfpmsnoleydukqmqv 223 | ziortxagwcfpbsboleidukjmqv 224 | zihrtxagwcfybsnoleyqxkjmqv 225 | zihrtxamwcfpbsngleydukjmqx 226 | zihrtxagwcfpbsnoleyduusmqu 227 | zihftxagwcfpssnwleydukjmqv 228 | zihrtxagwcfkbsnomeydukjmsv 229 | zihrtxagwcvpbsnooeydwkjmqv 230 | zihrtxagwcfpbsnoleycekumqv 231 | jahrtxagwcfpbsnoleydukjmmv 232 | zihrtxabwcfpbsnzheydukjmqv 233 | zihrtxagwctpbsnoleydwkjmhv 234 | zihrtpagwcfpbsnoleydzkjmqh 235 | zihwtxagwcfpbsnollydukjrqv 236 | zihrtxagwcfpusnoleydsvjmqv 237 | zibrtxagwcfpasnoleydukjmbv 238 | zchrtmagwcfpbsnoleydukjmwv 239 | ziertxbgwyfpbsnoleydukjmqv 240 | zitrtxagwcfpbhnoweydukjmqv 241 | zisrtxkgwcfpbsnopeydukjmqv 242 | zihrtxcgwdfpbynoleydukjmqv 243 | iihrtxajwcvpbsnoleydukjmqv 244 | zihuwxapwcfpbsnoleydukjmqv 245 | zihrtxngwcfqbsnoleyiukjmqv 246 | ziqrtxagjcfpbsnoleydukjmqi 247 | zifrtxarwctpbsnoleydukjmqv 248 | zihxgxagwcfpbpnoleydukjmqv 249 | giprtxagwcdpbsnoleydukjmqv 250 | zihrtxagwmfpbsnodeydukjbqv 251 | -------------------------------------------------------------------------------- /src/main/resources/day06_input.txt: -------------------------------------------------------------------------------- 1 | 342, 203 2 | 79, 64 3 | 268, 323 4 | 239, 131 5 | 246, 87 6 | 161, 93 7 | 306, 146 8 | 43, 146 9 | 57, 112 10 | 241, 277 11 | 304, 303 12 | 143, 235 13 | 253, 318 14 | 97, 103 15 | 200, 250 16 | 67, 207 17 | 345, 149 18 | 133, 222 19 | 232, 123 20 | 156, 359 21 | 80, 224 22 | 51, 145 23 | 138, 312 24 | 339, 294 25 | 297, 256 26 | 163, 311 27 | 241, 321 28 | 126, 66 29 | 145, 171 30 | 359, 184 31 | 241, 58 32 | 108, 312 33 | 117, 118 34 | 101, 180 35 | 58, 290 36 | 324, 42 37 | 141, 190 38 | 270, 149 39 | 209, 294 40 | 296, 345 41 | 68, 266 42 | 233, 281 43 | 305, 183 44 | 245, 230 45 | 161, 295 46 | 335, 352 47 | 93, 66 48 | 227, 59 49 | 264, 249 50 | 116, 173 51 | -------------------------------------------------------------------------------- /src/main/resources/day07_input.txt: -------------------------------------------------------------------------------- 1 | Step W must be finished before step G can begin. 2 | Step N must be finished before step X can begin. 3 | Step M must be finished before step O can begin. 4 | Step S must be finished before step I can begin. 5 | Step F must be finished before step Y can begin. 6 | Step Q must be finished before step K can begin. 7 | Step K must be finished before step Y can begin. 8 | Step Z must be finished before step J can begin. 9 | Step G must be finished before step L can begin. 10 | Step J must be finished before step C can begin. 11 | Step R must be finished before step E can begin. 12 | Step X must be finished before step I can begin. 13 | Step P must be finished before step E can begin. 14 | Step V must be finished before step Y can begin. 15 | Step C must be finished before step I can begin. 16 | Step O must be finished before step H can begin. 17 | Step T must be finished before step B can begin. 18 | Step Y must be finished before step A can begin. 19 | Step E must be finished before step L can begin. 20 | Step B must be finished before step D can begin. 21 | Step L must be finished before step U can begin. 22 | Step A must be finished before step I can begin. 23 | Step I must be finished before step D can begin. 24 | Step H must be finished before step D can begin. 25 | Step U must be finished before step D can begin. 26 | Step B must be finished before step I can begin. 27 | Step S must be finished before step F can begin. 28 | Step M must be finished before step R can begin. 29 | Step A must be finished before step H can begin. 30 | Step Z must be finished before step O can begin. 31 | Step K must be finished before step I can begin. 32 | Step K must be finished before step D can begin. 33 | Step B must be finished before step A can begin. 34 | Step G must be finished before step I can begin. 35 | Step Z must be finished before step B can begin. 36 | Step R must be finished before step P can begin. 37 | Step J must be finished before step E can begin. 38 | Step R must be finished before step I can begin. 39 | Step Q must be finished before step U can begin. 40 | Step S must be finished before step Z can begin. 41 | Step E must be finished before step I can begin. 42 | Step F must be finished before step E can begin. 43 | Step F must be finished before step I can begin. 44 | Step S must be finished before step J can begin. 45 | Step O must be finished before step I can begin. 46 | Step V must be finished before step B can begin. 47 | Step A must be finished before step U can begin. 48 | Step M must be finished before step T can begin. 49 | Step K must be finished before step A can begin. 50 | Step L must be finished before step I can begin. 51 | Step I must be finished before step U can begin. 52 | Step G must be finished before step U can begin. 53 | Step B must be finished before step U can begin. 54 | Step E must be finished before step D can begin. 55 | Step J must be finished before step T can begin. 56 | Step M must be finished before step Y can begin. 57 | Step P must be finished before step B can begin. 58 | Step M must be finished before step S can begin. 59 | Step E must be finished before step U can begin. 60 | Step R must be finished before step Y can begin. 61 | Step J must be finished before step I can begin. 62 | Step J must be finished before step D can begin. 63 | Step Y must be finished before step E can begin. 64 | Step A must be finished before step D can begin. 65 | Step X must be finished before step H can begin. 66 | Step O must be finished before step E can begin. 67 | Step E must be finished before step B can begin. 68 | Step E must be finished before step A can begin. 69 | Step F must be finished before step U can begin. 70 | Step G must be finished before step J can begin. 71 | Step M must be finished before step Z can begin. 72 | Step Y must be finished before step U can begin. 73 | Step Y must be finished before step D can begin. 74 | Step S must be finished before step D can begin. 75 | Step G must be finished before step H can begin. 76 | Step C must be finished before step Y can begin. 77 | Step B must be finished before step H can begin. 78 | Step P must be finished before step V can begin. 79 | Step M must be finished before step K can begin. 80 | Step L must be finished before step A can begin. 81 | Step G must be finished before step A can begin. 82 | Step Q must be finished before step P can begin. 83 | Step P must be finished before step I can begin. 84 | Step H must be finished before step U can begin. 85 | Step G must be finished before step X can begin. 86 | Step L must be finished before step H can begin. 87 | Step X must be finished before step P can begin. 88 | Step Z must be finished before step Y can begin. 89 | Step N must be finished before step K can begin. 90 | Step Q must be finished before step X can begin. 91 | Step X must be finished before step L can begin. 92 | Step T must be finished before step Y can begin. 93 | Step P must be finished before step A can begin. 94 | Step C must be finished before step T can begin. 95 | Step J must be finished before step V can begin. 96 | Step X must be finished before step O can begin. 97 | Step S must be finished before step C can begin. 98 | Step R must be finished before step C can begin. 99 | Step E must be finished before step H can begin. 100 | Step V must be finished before step H can begin. 101 | Step L must be finished before step D can begin. 102 | -------------------------------------------------------------------------------- /src/main/resources/day09_input.txt: -------------------------------------------------------------------------------- 1 | 431 players; last marble is worth 70950 points 2 | -------------------------------------------------------------------------------- /src/main/resources/day11_input.txt: -------------------------------------------------------------------------------- 1 | 8561 -------------------------------------------------------------------------------- /src/main/resources/day12_input.txt: -------------------------------------------------------------------------------- 1 | initial state: ##.######...#.##.#...#...##.####..###.#.##.#.##...##..#...##.#..##....##...........#.#.#..###.# 2 | 3 | .###. => # 4 | #.##. => . 5 | .#.## => # 6 | ...## => . 7 | ###.# => # 8 | ##.## => . 9 | ..... => . 10 | #..#. => # 11 | ..#.. => # 12 | #.### => # 13 | ##.#. => . 14 | ..#.# => # 15 | #.#.# => # 16 | .##.# => # 17 | .#..# => # 18 | #..## => # 19 | ##..# => # 20 | #...# => . 21 | ...#. => # 22 | ##### => . 23 | ###.. => # 24 | #.#.. => . 25 | ....# => . 26 | .#### => # 27 | ..### => . 28 | ..##. => # 29 | .##.. => . 30 | #.... => . 31 | ####. => # 32 | .#.#. => . 33 | .#... => # 34 | ##... => # 35 | -------------------------------------------------------------------------------- /src/main/resources/day14_input.txt: -------------------------------------------------------------------------------- 1 | 170641 -------------------------------------------------------------------------------- /src/main/resources/day15_input.txt: -------------------------------------------------------------------------------- 1 | ################################ 2 | ##############.################# 3 | ##############...############### 4 | #..#######G.#....############### 5 | ##.#####.#G....#.############### 6 | ##..###.......################## 7 | ###.####..G.G.################## 8 | ###.##G.......################## 9 | ###.G.....#...G######.########## 10 | ###GGG..#......####E...######### 11 | ###.GG.....########..#..#..##### 12 | #########.G...G.........#....### 13 | #########.....#####............# 14 | ########...G.#######.......##..# 15 | ########....#########...#.####.# 16 | ######E#.G..#########.....#....# 17 | ######....E.#########....##...## 18 | ######......#########.....##..## 19 | ######......#########...######## 20 | #..###.......#######.....####### 21 | #..G##.G......#####..G...####### 22 | #.........#..E...........####### 23 | ####.......E............######## 24 | ####.#..E.G..............####### 25 | ###########..............####### 26 | ###########.............E...#### 27 | ##########.................##### 28 | #########.....................## 29 | ########.......#.#....E....E..## 30 | ###########...............E.#### 31 | ##########.....#....#...##.##### 32 | ################################ 33 | -------------------------------------------------------------------------------- /src/main/resources/day16_input_part2.txt: -------------------------------------------------------------------------------- 1 | 1 2 1 0 2 | 9 1 0 2 3 | 10 2 3 2 4 | 1 1 2 3 5 | 15 0 3 3 6 | 9 3 2 3 7 | 9 3 3 3 8 | 8 3 1 1 9 | 14 1 1 0 10 | 1 2 2 3 11 | 1 0 1 1 12 | 1 0 2 2 13 | 13 2 3 1 14 | 9 1 1 1 15 | 8 0 1 0 16 | 14 0 1 1 17 | 1 0 3 3 18 | 1 2 3 0 19 | 1 2 0 2 20 | 5 0 3 0 21 | 9 0 2 0 22 | 8 0 1 1 23 | 1 1 1 0 24 | 1 1 1 2 25 | 8 0 0 3 26 | 9 3 3 3 27 | 9 3 2 3 28 | 8 1 3 1 29 | 14 1 3 3 30 | 1 2 1 1 31 | 1 2 2 0 32 | 1 3 2 2 33 | 3 0 2 0 34 | 9 0 2 0 35 | 9 0 3 0 36 | 8 3 0 3 37 | 14 3 1 2 38 | 1 2 1 0 39 | 1 0 0 1 40 | 1 0 0 3 41 | 5 0 3 1 42 | 9 1 1 1 43 | 8 1 2 2 44 | 1 3 0 1 45 | 1 1 0 3 46 | 15 0 3 1 47 | 9 1 3 1 48 | 8 1 2 2 49 | 14 2 0 1 50 | 1 2 2 2 51 | 9 3 0 3 52 | 10 3 2 3 53 | 1 1 1 0 54 | 5 2 3 0 55 | 9 0 3 0 56 | 8 1 0 1 57 | 1 0 1 2 58 | 1 3 2 0 59 | 13 2 3 0 60 | 9 0 1 0 61 | 9 0 1 0 62 | 8 0 1 1 63 | 14 1 3 2 64 | 1 0 1 1 65 | 1 2 3 0 66 | 11 0 3 0 67 | 9 0 2 0 68 | 9 0 1 0 69 | 8 2 0 2 70 | 14 2 3 1 71 | 1 1 0 2 72 | 1 3 1 3 73 | 9 0 0 0 74 | 10 0 2 0 75 | 4 3 0 2 76 | 9 2 3 2 77 | 8 1 2 1 78 | 14 1 3 2 79 | 1 1 1 1 80 | 1 3 1 0 81 | 1 1 0 3 82 | 8 3 3 3 83 | 9 3 3 3 84 | 8 3 2 2 85 | 14 2 1 1 86 | 1 2 0 2 87 | 1 1 0 0 88 | 9 1 0 3 89 | 10 3 0 3 90 | 12 3 2 3 91 | 9 3 3 3 92 | 8 3 1 1 93 | 14 1 1 2 94 | 1 0 3 1 95 | 1 2 3 3 96 | 1 2 3 0 97 | 5 0 3 1 98 | 9 1 2 1 99 | 9 1 3 1 100 | 8 2 1 2 101 | 1 2 0 1 102 | 1 1 2 0 103 | 5 1 3 3 104 | 9 3 2 3 105 | 9 3 3 3 106 | 8 2 3 2 107 | 14 2 2 1 108 | 1 3 1 2 109 | 1 1 1 3 110 | 1 2 1 0 111 | 3 0 2 3 112 | 9 3 1 3 113 | 8 1 3 1 114 | 14 1 2 0 115 | 1 0 0 3 116 | 9 2 0 1 117 | 10 1 2 1 118 | 1 0 1 2 119 | 5 1 3 1 120 | 9 1 2 1 121 | 8 1 0 0 122 | 14 0 1 2 123 | 1 1 1 1 124 | 1 3 3 0 125 | 1 2 0 3 126 | 4 0 3 3 127 | 9 3 3 3 128 | 8 2 3 2 129 | 1 2 2 1 130 | 1 1 1 3 131 | 9 2 0 0 132 | 10 0 2 0 133 | 15 0 3 0 134 | 9 0 2 0 135 | 9 0 1 0 136 | 8 0 2 2 137 | 14 2 1 3 138 | 1 3 3 1 139 | 1 2 0 2 140 | 9 0 0 0 141 | 10 0 1 0 142 | 14 0 2 2 143 | 9 2 1 2 144 | 8 2 3 3 145 | 9 1 0 2 146 | 10 2 0 2 147 | 10 0 1 2 148 | 9 2 1 2 149 | 9 2 3 2 150 | 8 3 2 3 151 | 14 3 3 2 152 | 1 2 0 0 153 | 1 1 3 1 154 | 1 3 2 3 155 | 2 1 0 3 156 | 9 3 3 3 157 | 8 2 3 2 158 | 14 2 1 0 159 | 1 1 0 2 160 | 1 3 1 1 161 | 9 1 0 3 162 | 10 3 1 3 163 | 6 1 2 3 164 | 9 3 3 3 165 | 8 0 3 0 166 | 14 0 2 2 167 | 9 2 0 3 168 | 10 3 1 3 169 | 1 1 1 0 170 | 10 0 1 1 171 | 9 1 2 1 172 | 9 1 1 1 173 | 8 2 1 2 174 | 14 2 3 1 175 | 1 2 0 3 176 | 1 2 0 2 177 | 2 0 3 0 178 | 9 0 3 0 179 | 8 1 0 1 180 | 14 1 3 0 181 | 1 1 0 3 182 | 1 1 3 1 183 | 1 3 0 2 184 | 9 3 2 2 185 | 9 2 1 2 186 | 9 2 2 2 187 | 8 2 0 0 188 | 14 0 3 1 189 | 1 1 2 2 190 | 9 2 0 0 191 | 10 0 1 0 192 | 8 0 0 2 193 | 9 2 3 2 194 | 8 1 2 1 195 | 14 1 0 0 196 | 1 2 0 3 197 | 1 3 3 1 198 | 1 3 1 2 199 | 1 2 1 1 200 | 9 1 3 1 201 | 8 0 1 0 202 | 9 0 0 3 203 | 10 3 1 3 204 | 9 0 0 1 205 | 10 1 3 1 206 | 10 3 1 1 207 | 9 1 1 1 208 | 8 1 0 0 209 | 14 0 3 1 210 | 1 0 2 2 211 | 9 0 0 0 212 | 10 0 3 0 213 | 6 0 2 0 214 | 9 0 3 0 215 | 8 1 0 1 216 | 14 1 2 2 217 | 1 2 3 1 218 | 1 3 2 0 219 | 0 1 0 1 220 | 9 1 2 1 221 | 8 1 2 2 222 | 14 2 0 3 223 | 1 0 2 2 224 | 9 0 0 1 225 | 10 1 3 1 226 | 1 1 3 0 227 | 1 2 1 0 228 | 9 0 1 0 229 | 9 0 2 0 230 | 8 0 3 3 231 | 14 3 0 2 232 | 1 1 3 1 233 | 9 3 0 3 234 | 10 3 2 3 235 | 1 1 3 0 236 | 2 0 3 3 237 | 9 3 1 3 238 | 8 2 3 2 239 | 1 2 3 3 240 | 9 3 0 1 241 | 10 1 2 1 242 | 2 0 3 1 243 | 9 1 2 1 244 | 8 1 2 2 245 | 1 3 2 0 246 | 1 2 1 1 247 | 0 1 0 1 248 | 9 1 2 1 249 | 9 1 3 1 250 | 8 1 2 2 251 | 14 2 1 0 252 | 1 0 2 1 253 | 1 1 2 2 254 | 1 3 2 3 255 | 6 3 2 1 256 | 9 1 2 1 257 | 8 0 1 0 258 | 14 0 0 1 259 | 9 0 0 0 260 | 10 0 2 0 261 | 1 0 3 3 262 | 5 0 3 3 263 | 9 3 2 3 264 | 9 3 2 3 265 | 8 1 3 1 266 | 9 2 0 0 267 | 10 0 3 0 268 | 9 0 0 2 269 | 10 2 2 2 270 | 1 0 2 3 271 | 7 2 0 2 272 | 9 2 1 2 273 | 8 1 2 1 274 | 1 1 3 0 275 | 1 2 3 2 276 | 12 3 2 0 277 | 9 0 3 0 278 | 9 0 1 0 279 | 8 1 0 1 280 | 14 1 3 2 281 | 1 3 1 1 282 | 1 1 1 0 283 | 1 3 3 3 284 | 10 0 1 0 285 | 9 0 1 0 286 | 8 0 2 2 287 | 1 0 2 1 288 | 1 2 0 0 289 | 4 3 0 0 290 | 9 0 3 0 291 | 8 2 0 2 292 | 9 3 0 0 293 | 10 0 2 0 294 | 1 2 2 3 295 | 11 0 3 1 296 | 9 1 3 1 297 | 8 2 1 2 298 | 1 2 3 1 299 | 1 3 1 0 300 | 5 1 3 3 301 | 9 3 3 3 302 | 8 2 3 2 303 | 14 2 1 3 304 | 1 1 2 2 305 | 1 1 0 0 306 | 8 0 0 0 307 | 9 0 2 0 308 | 8 0 3 3 309 | 14 3 3 1 310 | 9 2 0 0 311 | 10 0 1 0 312 | 1 0 3 2 313 | 9 0 0 3 314 | 10 3 2 3 315 | 8 0 0 0 316 | 9 0 1 0 317 | 8 1 0 1 318 | 14 1 2 0 319 | 1 2 0 2 320 | 1 0 3 3 321 | 1 1 3 1 322 | 12 3 2 2 323 | 9 2 2 2 324 | 8 2 0 0 325 | 14 0 1 1 326 | 1 3 0 3 327 | 1 1 2 2 328 | 1 3 0 0 329 | 1 2 0 2 330 | 9 2 2 2 331 | 8 2 1 1 332 | 1 2 3 0 333 | 1 3 0 2 334 | 3 0 2 0 335 | 9 0 1 0 336 | 8 1 0 1 337 | 9 1 0 3 338 | 10 3 1 3 339 | 1 0 0 2 340 | 1 2 1 0 341 | 2 3 0 0 342 | 9 0 1 0 343 | 8 1 0 1 344 | 14 1 2 2 345 | 9 1 0 1 346 | 10 1 3 1 347 | 1 3 1 3 348 | 1 1 3 0 349 | 8 0 0 3 350 | 9 3 3 3 351 | 9 3 1 3 352 | 8 3 2 2 353 | 14 2 1 0 354 | 1 2 2 2 355 | 1 0 1 3 356 | 5 2 3 3 357 | 9 3 2 3 358 | 9 3 3 3 359 | 8 0 3 0 360 | 14 0 0 2 361 | 1 3 1 3 362 | 9 3 0 0 363 | 10 0 2 0 364 | 1 2 0 1 365 | 4 3 0 0 366 | 9 0 3 0 367 | 8 2 0 2 368 | 14 2 0 1 369 | 1 3 3 0 370 | 9 0 0 3 371 | 10 3 2 3 372 | 1 0 1 2 373 | 3 2 0 2 374 | 9 2 1 2 375 | 8 1 2 1 376 | 14 1 0 0 377 | 1 1 2 1 378 | 9 3 0 2 379 | 10 2 3 2 380 | 2 1 3 1 381 | 9 1 2 1 382 | 8 1 0 0 383 | 14 0 2 1 384 | 1 2 3 0 385 | 1 0 3 2 386 | 11 0 3 2 387 | 9 2 3 2 388 | 9 2 3 2 389 | 8 1 2 1 390 | 1 0 2 0 391 | 1 0 1 3 392 | 1 2 3 2 393 | 5 2 3 2 394 | 9 2 1 2 395 | 8 2 1 1 396 | 14 1 2 2 397 | 1 1 0 3 398 | 1 2 2 0 399 | 1 2 2 1 400 | 2 3 0 0 401 | 9 0 1 0 402 | 8 2 0 2 403 | 14 2 2 0 404 | 1 0 3 3 405 | 1 3 0 2 406 | 9 3 0 1 407 | 10 1 0 1 408 | 13 3 2 3 409 | 9 3 1 3 410 | 8 3 0 0 411 | 9 1 0 3 412 | 10 3 3 3 413 | 1 3 1 1 414 | 1 2 1 2 415 | 7 2 1 3 416 | 9 3 3 3 417 | 8 0 3 0 418 | 14 0 0 3 419 | 9 1 0 0 420 | 10 0 2 0 421 | 1 0 1 1 422 | 9 1 0 2 423 | 10 2 3 2 424 | 3 0 2 1 425 | 9 1 2 1 426 | 9 1 1 1 427 | 8 3 1 3 428 | 1 3 2 0 429 | 9 2 0 1 430 | 10 1 2 1 431 | 4 0 1 0 432 | 9 0 2 0 433 | 8 0 3 3 434 | 1 1 0 1 435 | 1 2 1 0 436 | 1 0 1 2 437 | 9 1 2 0 438 | 9 0 1 0 439 | 8 3 0 3 440 | 14 3 0 2 441 | 1 1 2 3 442 | 1 2 3 0 443 | 1 3 1 1 444 | 2 3 0 0 445 | 9 0 3 0 446 | 8 0 2 2 447 | 14 2 1 3 448 | 9 3 0 2 449 | 10 2 2 2 450 | 9 0 0 1 451 | 10 1 1 1 452 | 1 1 0 0 453 | 14 0 2 0 454 | 9 0 3 0 455 | 8 0 3 3 456 | 14 3 2 2 457 | 1 0 2 1 458 | 1 3 0 0 459 | 1 2 3 3 460 | 4 0 3 1 461 | 9 1 3 1 462 | 8 2 1 2 463 | 14 2 1 1 464 | 1 1 0 0 465 | 9 0 0 2 466 | 10 2 3 2 467 | 1 2 0 2 468 | 9 2 2 2 469 | 8 2 1 1 470 | 14 1 1 2 471 | 9 0 0 0 472 | 10 0 0 0 473 | 1 3 3 1 474 | 4 1 3 3 475 | 9 3 2 3 476 | 8 3 2 2 477 | 14 2 2 1 478 | 9 0 0 2 479 | 10 2 1 2 480 | 1 3 1 0 481 | 1 0 3 3 482 | 6 0 2 0 483 | 9 0 1 0 484 | 8 1 0 1 485 | 9 2 0 0 486 | 10 0 3 0 487 | 1 3 2 2 488 | 1 2 2 3 489 | 4 0 3 0 490 | 9 0 3 0 491 | 8 0 1 1 492 | 14 1 3 2 493 | 1 0 3 1 494 | 1 1 0 3 495 | 1 1 0 0 496 | 10 0 1 0 497 | 9 0 2 0 498 | 8 0 2 2 499 | 1 2 3 0 500 | 1 2 1 3 501 | 1 3 2 1 502 | 11 0 3 1 503 | 9 1 3 1 504 | 8 1 2 2 505 | 14 2 0 0 506 | 1 0 3 2 507 | 1 1 1 1 508 | 2 1 3 1 509 | 9 1 2 1 510 | 8 1 0 0 511 | 14 0 1 1 512 | 1 1 3 3 513 | 1 1 3 0 514 | 9 3 2 2 515 | 9 2 2 2 516 | 8 1 2 1 517 | 14 1 1 0 518 | 1 1 0 2 519 | 1 3 0 1 520 | 10 3 1 3 521 | 9 3 1 3 522 | 9 3 2 3 523 | 8 0 3 0 524 | 14 0 2 2 525 | 1 1 1 0 526 | 1 3 3 3 527 | 1 0 1 1 528 | 10 0 1 3 529 | 9 3 2 3 530 | 9 3 1 3 531 | 8 3 2 2 532 | 14 2 2 1 533 | 1 3 2 2 534 | 1 1 3 3 535 | 8 0 0 3 536 | 9 3 1 3 537 | 8 3 1 1 538 | 14 1 1 0 539 | 1 0 0 2 540 | 1 1 3 3 541 | 1 0 1 1 542 | 8 3 3 2 543 | 9 2 2 2 544 | 9 2 2 2 545 | 8 2 0 0 546 | 14 0 2 2 547 | 1 1 0 0 548 | 10 0 1 1 549 | 9 1 3 1 550 | 8 1 2 2 551 | 14 2 2 0 552 | 1 1 0 1 553 | 1 3 0 3 554 | 1 3 2 2 555 | 9 1 2 2 556 | 9 2 1 2 557 | 8 2 0 0 558 | 14 0 1 1 559 | 9 1 0 2 560 | 10 2 0 2 561 | 1 2 1 3 562 | 1 2 1 0 563 | 11 0 3 0 564 | 9 0 3 0 565 | 9 0 3 0 566 | 8 0 1 1 567 | 14 1 0 2 568 | 1 1 0 3 569 | 1 0 2 1 570 | 1 2 1 0 571 | 15 0 3 1 572 | 9 1 1 1 573 | 8 2 1 2 574 | 14 2 1 0 575 | 9 2 0 1 576 | 10 1 1 1 577 | 1 2 3 2 578 | 9 3 0 3 579 | 10 3 0 3 580 | 5 2 3 1 581 | 9 1 2 1 582 | 8 1 0 0 583 | 14 0 1 1 584 | 1 3 0 3 585 | 1 0 1 2 586 | 1 2 3 0 587 | 4 3 0 0 588 | 9 0 3 0 589 | 9 0 3 0 590 | 8 0 1 1 591 | 1 3 1 2 592 | 1 2 1 0 593 | 1 2 1 3 594 | 11 0 3 3 595 | 9 3 3 3 596 | 8 3 1 1 597 | 14 1 1 0 598 | 1 0 1 3 599 | 1 3 0 1 600 | 6 1 2 2 601 | 9 2 1 2 602 | 8 2 0 0 603 | 14 0 3 1 604 | 1 3 3 3 605 | 1 2 2 0 606 | 1 1 1 2 607 | 6 3 2 2 608 | 9 2 1 2 609 | 8 1 2 1 610 | 1 2 0 2 611 | 1 1 3 0 612 | 14 0 2 2 613 | 9 2 3 2 614 | 8 2 1 1 615 | 14 1 2 3 616 | 9 2 0 0 617 | 10 0 2 0 618 | 1 3 3 1 619 | 1 2 2 2 620 | 7 0 1 0 621 | 9 0 2 0 622 | 8 3 0 3 623 | 14 3 2 2 624 | 1 1 3 3 625 | 1 1 0 1 626 | 1 3 2 0 627 | 8 1 3 0 628 | 9 0 2 0 629 | 8 0 2 2 630 | 14 2 0 0 631 | 1 0 3 3 632 | 1 2 2 2 633 | 1 3 1 1 634 | 7 2 1 2 635 | 9 2 3 2 636 | 8 0 2 0 637 | 14 0 0 1 638 | 9 3 0 0 639 | 10 0 3 0 640 | 9 0 0 2 641 | 10 2 0 2 642 | 1 2 1 3 643 | 4 0 3 2 644 | 9 2 1 2 645 | 9 2 1 2 646 | 8 1 2 1 647 | 14 1 2 0 648 | 1 1 3 2 649 | 9 1 0 1 650 | 10 1 1 1 651 | 1 0 2 3 652 | 1 3 1 2 653 | 9 2 3 2 654 | 8 2 0 0 655 | 14 0 3 3 656 | 1 3 3 0 657 | 9 2 0 1 658 | 10 1 0 1 659 | 1 2 3 2 660 | 7 2 0 2 661 | 9 2 1 2 662 | 8 3 2 3 663 | 14 3 3 1 664 | 1 1 0 2 665 | 1 1 1 3 666 | 1 1 0 0 667 | 8 0 3 0 668 | 9 0 3 0 669 | 9 0 3 0 670 | 8 1 0 1 671 | 1 2 1 2 672 | 1 3 2 0 673 | 1 2 3 3 674 | 4 0 3 3 675 | 9 3 3 3 676 | 8 1 3 1 677 | 1 1 0 3 678 | 9 0 0 0 679 | 10 0 2 0 680 | 2 3 0 2 681 | 9 2 1 2 682 | 8 1 2 1 683 | 14 1 3 3 684 | 1 2 3 2 685 | 9 3 0 1 686 | 10 1 1 1 687 | 2 1 0 2 688 | 9 2 2 2 689 | 8 2 3 3 690 | 14 3 3 2 691 | 9 0 0 1 692 | 10 1 2 1 693 | 1 2 3 3 694 | 9 3 0 0 695 | 10 0 0 0 696 | 5 1 3 0 697 | 9 0 2 0 698 | 8 2 0 2 699 | 14 2 3 0 700 | 1 3 1 3 701 | 1 1 2 2 702 | 1 3 0 1 703 | 6 3 2 2 704 | 9 2 3 2 705 | 9 2 2 2 706 | 8 2 0 0 707 | 14 0 1 1 708 | 1 1 0 0 709 | 1 2 2 2 710 | 1 1 0 3 711 | 14 0 2 2 712 | 9 2 3 2 713 | 8 2 1 1 714 | 1 0 2 3 715 | 1 2 3 2 716 | 1 2 3 0 717 | 12 3 2 2 718 | 9 2 1 2 719 | 9 2 2 2 720 | 8 2 1 1 721 | 1 3 3 2 722 | 3 0 2 2 723 | 9 2 1 2 724 | 8 2 1 1 725 | 14 1 1 3 726 | 1 3 2 0 727 | 1 0 1 2 728 | 9 2 0 1 729 | 10 1 1 1 730 | 3 2 0 2 731 | 9 2 2 2 732 | 9 2 2 2 733 | 8 3 2 3 734 | 14 3 3 1 735 | 1 2 3 3 736 | 1 2 2 0 737 | 1 1 2 2 738 | 11 0 3 0 739 | 9 0 3 0 740 | 9 0 1 0 741 | 8 1 0 1 742 | 14 1 3 3 743 | 1 0 0 1 744 | 1 2 3 2 745 | 1 1 2 0 746 | 14 0 2 0 747 | 9 0 1 0 748 | 8 0 3 3 749 | 14 3 3 1 750 | 1 1 0 0 751 | 1 0 1 2 752 | 1 3 2 3 753 | 6 3 2 2 754 | 9 2 2 2 755 | 9 2 1 2 756 | 8 1 2 1 757 | 1 1 1 2 758 | 1 2 0 3 759 | 1 2 1 0 760 | 11 0 3 3 761 | 9 3 3 3 762 | 8 1 3 1 763 | 1 1 2 0 764 | 1 2 3 2 765 | 1 3 2 3 766 | 14 0 2 3 767 | 9 3 3 3 768 | 8 1 3 1 769 | 14 1 1 2 770 | 1 2 1 3 771 | 1 0 1 1 772 | 10 0 1 3 773 | 9 3 3 3 774 | 8 2 3 2 775 | 1 1 3 3 776 | 8 3 3 3 777 | 9 3 3 3 778 | 8 2 3 2 779 | 14 2 2 3 780 | 1 0 3 2 781 | 1 1 2 1 782 | 9 1 2 1 783 | 9 1 3 1 784 | 8 1 3 3 785 | 14 3 3 0 786 | 1 2 1 3 787 | 1 2 2 1 788 | 1 3 0 2 789 | 0 1 2 1 790 | 9 1 3 1 791 | 8 0 1 0 792 | 14 0 1 2 793 | 1 2 1 0 794 | 1 1 2 1 795 | 11 0 3 3 796 | 9 3 3 3 797 | 8 2 3 2 798 | 14 2 2 1 799 | 1 0 3 2 800 | 9 1 0 3 801 | 10 3 2 3 802 | 13 2 3 2 803 | 9 2 3 2 804 | 8 1 2 1 805 | 14 1 1 2 806 | 9 1 0 1 807 | 10 1 1 1 808 | 1 1 1 3 809 | 15 0 3 1 810 | 9 1 1 1 811 | 8 2 1 2 812 | 14 2 2 1 813 | 9 3 0 3 814 | 10 3 2 3 815 | 9 0 0 2 816 | 10 2 3 2 817 | 0 0 2 3 818 | 9 3 2 3 819 | 8 1 3 1 820 | 14 1 2 2 821 | 1 3 3 1 822 | 1 1 2 3 823 | 1 1 3 0 824 | 10 3 1 0 825 | 9 0 1 0 826 | 9 0 1 0 827 | 8 0 2 2 828 | 1 2 3 1 829 | 9 1 0 0 830 | 10 0 3 0 831 | 1 3 2 3 832 | 0 1 0 1 833 | 9 1 3 1 834 | 8 2 1 2 835 | 14 2 2 3 836 | 1 3 1 1 837 | 1 3 2 2 838 | 1 2 2 0 839 | 7 0 1 1 840 | 9 1 2 1 841 | 9 1 2 1 842 | 8 3 1 3 843 | 14 3 0 1 844 | 1 1 3 2 845 | 1 0 2 3 846 | 1 3 0 0 847 | 6 0 2 3 848 | 9 3 1 3 849 | 9 3 1 3 850 | 8 1 3 1 851 | 14 1 1 3 852 | 1 3 3 1 853 | 1 2 3 0 854 | 4 1 0 1 855 | 9 1 2 1 856 | 8 1 3 3 857 | 14 3 0 2 858 | 1 1 2 3 859 | 9 3 0 1 860 | 10 1 0 1 861 | 15 0 3 3 862 | 9 3 2 3 863 | 9 3 3 3 864 | 8 3 2 2 865 | 14 2 1 0 866 | 1 1 3 3 867 | 1 2 2 2 868 | 1 3 0 1 869 | 10 3 1 1 870 | 9 1 3 1 871 | 9 1 2 1 872 | 8 1 0 0 873 | 14 0 2 1 874 | 1 1 3 0 875 | 1 3 0 2 876 | 9 2 3 2 877 | 8 1 2 1 878 | 14 1 3 0 879 | 1 3 3 1 880 | 1 0 2 3 881 | 1 3 1 2 882 | 6 1 2 1 883 | 9 1 2 1 884 | 8 1 0 0 885 | 14 0 3 3 886 | 1 3 0 1 887 | 1 1 1 0 888 | 9 0 2 2 889 | 9 2 3 2 890 | 8 2 3 3 891 | 14 3 3 1 892 | 1 2 1 0 893 | 1 0 1 2 894 | 1 3 0 3 895 | 6 3 2 2 896 | 9 2 1 2 897 | 8 1 2 1 898 | 14 1 1 0 899 | -------------------------------------------------------------------------------- /src/main/resources/day18_input.txt: -------------------------------------------------------------------------------- 1 | ..|..|.|.|.||..#.#|...|..#.|.........|.......|..#. 2 | #.|.........|||....#....|....##||.....|.|......... 3 | ..||......#.#||#.#.......#..#.#.###...|.#..#...#.. 4 | |....#....|.##.##.....##...##|..|....|..|#||...### 5 | #|...|.#|..|......#.##....#|....|...|#......|.#|.| 6 | ..|....##.##.#..||##...#..##|......|...|#.||.#.#.. 7 | .#...#||...........#|.....|##....#.#...|#.|###..|. 8 | ||....#.#.|...||...###|.|#.....#.|#.|#...#.#.|...# 9 | ...#.....||.......#....#|###|####..|#|.###..||.#.# 10 | |#|...||..##.||.||..#.#.|..#...#..|........#..|#.. 11 | #....||.|.....|.|.#|.##.|..|.#.....|..|.....#|.|.. 12 | |..||#........|#.|..|.|...#..#....#.|.....||#.#... 13 | ..|...||.|##||##..|...#|.....|#.|....#....||#.##.. 14 | #|..#|..||...|..|.|#|..##.#.......#|#....#||...#.. 15 | |#|.|...|..##...|.#||#..#...#....||.#.|...##..|..# 16 | |..||.#.#..|....#...#.#..#..#...||.|.#.#.#.....#|. 17 | .|##.####..||.#.|#.###....#...#.|..#.#.##.|..##..# 18 | #|.......#......|.#..|.....||.|.#||#.#.##.#|....|. 19 | .|..#.|#.##|....#......|.#||..|#..##.|..#......### 20 | ..###....#.||.#..|##.##..#|.#...|#|...#.|.|...#|#. 21 | ........||......|##||##..###|..|.##.#..#|##...|..# 22 | .#....|....|...##.#.||##.....#|...|#.#||...#.....| 23 | #...#|...###.|.|..|..#.|###.|.#.|.####|...|.#..|#. 24 | ...#..|.....|.#.##.|.#.#..|..##.##.#..|...#...|#.. 25 | ..###.#|##|#.#.......|.|...||###|.#.........#..|.. 26 | ..|#...||.#.#..|...|..#||...|.#.#......#...|..#... 27 | .||..........|.#....|.||...|#.|.|||..||........|#. 28 | #.##.#||..|.|#...|..#|.|#......|.||.......|...|#.. 29 | #.||.||#...#|||.....|.|.|.|...||.#..#.#.#|..|||.|. 30 | .#...#...||||#...##.#.#......#|......#.|.....|#||. 31 | .#|.###|#||.|#...#.|..|.|#.|#..#..#...|.|.|...|.|. 32 | ..#|.|#|..##|.||.|.....|#...#..|.|#....|.|..|..|#. 33 | #....|..#.#.......#||..#....|.|..#.#|..#...|#.#.|. 34 | #.#.|..|...#|.###||.#.....#|#|#.##..|.|#|....|.... 35 | ....|#.#.||..|..#...|...|..|...|..#..#......#|.#.. 36 | ..#..#|.|.|#.#.|.|.#.#.....#..|..#..|.......||#|#. 37 | #|......|#..|.#...##|....|..|#||..|..||...||.#.... 38 | #..|#.......||.....|.||||#.|#.|....#|#....|#.#.... 39 | #.##.#.#..||......#...|......|#|...|.||.#.|..|.... 40 | ####.|...||##|#|.......|||.#.#.....#...##.#|..#... 41 | ..|..|||..|.||#|#.|..#.|..#.|........###......#..| 42 | ..#|.....|||||#..||.....##..#...|||.....#......#.# 43 | .#.|.||#.##.......||.#.||..#...|##..|.#.#...|...|. 44 | .##........|..||.|.#|.|.||||..#...#..|..|#|#..|#|. 45 | .#.#.....#|||..|...#.|...|...#.||..||###|.#|...... 46 | |.|#..#.#.|||||.#|.|......#.|#.||.....#..#...|#.|. 47 | ...|....#.###|.#.##......|#.##.....#.|.##.#......# 48 | .#.#.....|..#.##..#|#|..#.#|##..##|..##.#..#....|| 49 | ..#.#.|.....#.|..#.|.|#...|....#...|..|.|..#||...| 50 | |.||.|...|...|##..||....|#.|..#..##....|#.#|##..|. 51 | -------------------------------------------------------------------------------- /src/main/resources/day19_input.txt: -------------------------------------------------------------------------------- 1 | #ip 2 2 | addi 2 16 2 3 | seti 1 2 4 4 | seti 1 8 1 5 | mulr 4 1 5 6 | eqrr 5 3 5 7 | addr 5 2 2 8 | addi 2 1 2 9 | addr 4 0 0 10 | addi 1 1 1 11 | gtrr 1 3 5 12 | addr 2 5 2 13 | seti 2 6 2 14 | addi 4 1 4 15 | gtrr 4 3 5 16 | addr 5 2 2 17 | seti 1 2 2 18 | mulr 2 2 2 19 | addi 3 2 3 20 | mulr 3 3 3 21 | mulr 2 3 3 22 | muli 3 11 3 23 | addi 5 2 5 24 | mulr 5 2 5 25 | addi 5 8 5 26 | addr 3 5 3 27 | addr 2 0 2 28 | seti 0 4 2 29 | setr 2 5 5 30 | mulr 5 2 5 31 | addr 2 5 5 32 | mulr 2 5 5 33 | muli 5 14 5 34 | mulr 5 2 5 35 | addr 3 5 3 36 | seti 0 8 0 37 | seti 0 5 2 38 | -------------------------------------------------------------------------------- /src/main/resources/day21_input.txt: -------------------------------------------------------------------------------- 1 | #ip 1 2 | seti 123 0 4 # 0 register[4] = 123 3 | bani 4 456 4 # 1 register[4] = register[4] & 456 4 | eqri 4 72 4 # 2 register[4] = if(register[4] == 72) 1 else 0 5 | addr 4 1 1 # 3 register[1] = register[4](1) + register[1] - Jump over next instruction 6 | seti 0 0 1 # 4 register[1] = 0 - So this loops back to 0 7 | seti 0 2 4 # 5 register[4] = 0 8 | bori 4 65536 3 # 6 register[3] = register[4] | 65536 9 | seti 10552971 1 4 # 7 register[4] = 10552971 10 | bani 3 255 5 # 8 register[5] = register[3] & 255 11 | addr 4 5 4 # 9 register[4] = register[4] + register[5] 12 | bani 4 16777215 4 # 10 register[4] = register[4] & 16777215 13 | muli 4 65899 4 # 11 register[4] = register[4] * 65899 14 | bani 4 16777215 4 # 12 register[4] = register[4] & 16777215 15 | gtir 256 3 5 # 13 register[5] = if(256 > register[3]) 1 else 0 16 | addr 5 1 1 # 14 register[1] = register[5] + register[1] - ??? 17 | addi 1 1 1 # 15 register[1] = register[1] + 1 - ??? 18 | seti 27 7 1 # 16 register[1] = 27 19 | seti 0 1 5 # 17 register[5] = 0 20 | addi 5 1 2 # 18 register[2] = register[5] + 1 21 | muli 2 256 2 # 19 register[2] = register[2] * 256 22 | gtrr 2 3 2 # 20 register[2] = if(register[2] > register[3]) 1 else 0 23 | addr 2 1 1 # 21 register[1] = register[2] + register[1] - ??? 24 | addi 1 1 1 # 22 register[1] = register[1] + 1 -??? 25 | seti 25 0 1 # 23 register[1] = 25 26 | addi 5 1 5 # 24 register[5] = register[5] + 1 27 | seti 17 2 1 # 25 register[1] = 17 28 | setr 5 7 3 # 26 register[3] = register[5] + 7 29 | seti 7 8 1 # 27 register[1] = 7 30 | eqrr 4 0 5 # 28 register[5] = if(register[4] == register[0]) 1 else 0 31 | addr 5 1 1 # 29 register[1] = register[5] + 1 32 | seti 5 0 1 # 30 register[1] = 5 33 | -------------------------------------------------------------------------------- /src/main/resources/day22_input.txt: -------------------------------------------------------------------------------- 1 | depth: 4848 2 | target: 15,700 3 | -------------------------------------------------------------------------------- /src/main/resources/day24_input.txt: -------------------------------------------------------------------------------- 1 | Immune System: 2 | 8808 units each with 5616 hit points (immune to cold; weak to radiation) with an attack that does 5 bludgeoning damage at initiative 10 3 | 900 units each with 13511 hit points (weak to radiation) with an attack that does 107 radiation damage at initiative 20 4 | 581 units each with 10346 hit points (weak to radiation; immune to slashing) with an attack that does 140 fire damage at initiative 14 5 | 57 units each with 9991 hit points (immune to slashing, radiation, fire; weak to bludgeoning) with an attack that does 1690 fire damage at initiative 4 6 | 4074 units each with 6549 hit points (weak to fire) with an attack that does 15 radiation damage at initiative 2 7 | 929 units each with 5404 hit points (immune to bludgeoning, radiation) with an attack that does 45 fire damage at initiative 16 8 | 2196 units each with 3186 hit points (weak to fire; immune to radiation) with an attack that does 10 fire damage at initiative 11 9 | 4420 units each with 9691 hit points (weak to radiation; immune to fire) with an attack that does 21 fire damage at initiative 7 10 | 3978 units each with 2306 hit points (weak to cold, radiation) with an attack that does 4 fire damage at initiative 12 11 | 1284 units each with 4487 hit points (weak to radiation, bludgeoning) with an attack that does 32 slashing damage at initiative 19 12 | 13 | Infection: 14 | 4262 units each with 23427 hit points (weak to slashing; immune to fire) with an attack that does 9 slashing damage at initiative 8 15 | 217 units each with 9837 hit points (weak to bludgeoning) with an attack that does 73 bludgeoning damage at initiative 1 16 | 5497 units each with 33578 hit points (weak to radiation, cold) with an attack that does 11 slashing damage at initiative 17 17 | 866 units each with 41604 hit points (weak to cold) with an attack that does 76 radiation damage at initiative 15 18 | 1823 units each with 19652 hit points (weak to fire, cold) with an attack that does 20 slashing damage at initiative 13 19 | 2044 units each with 23512 hit points (weak to cold) with an attack that does 22 slashing damage at initiative 9 20 | 373 units each with 40861 hit points (immune to cold) with an attack that does 215 slashing damage at initiative 18 21 | 5427 units each with 43538 hit points (immune to radiation; weak to bludgeoning) with an attack that does 15 slashing damage at initiative 5 22 | 3098 units each with 19840 hit points (weak to bludgeoning, cold) with an attack that does 12 radiation damage at initiative 3 23 | 785 units each with 14669 hit points with an attack that does 30 fire damage at initiative 6 24 | -------------------------------------------------------------------------------- /src/main/resources/day24_input_immune.txt: -------------------------------------------------------------------------------- 1 | 8808 units each with 5616 hit points (immune to cold; weak to radiation) with an attack that does 5 bludgeoning damage at initiative 10 2 | 900 units each with 13511 hit points (weak to radiation) with an attack that does 107 radiation damage at initiative 20 3 | 581 units each with 10346 hit points (weak to radiation; immune to slashing) with an attack that does 140 fire damage at initiative 14 4 | 57 units each with 9991 hit points (immune to slashing, radiation, fire; weak to bludgeoning) with an attack that does 1690 fire damage at initiative 4 5 | 4074 units each with 6549 hit points (weak to fire) with an attack that does 15 radiation damage at initiative 2 6 | 929 units each with 5404 hit points (immune to bludgeoning, radiation) with an attack that does 45 fire damage at initiative 16 7 | 2196 units each with 3186 hit points (weak to fire; immune to radiation) with an attack that does 10 fire damage at initiative 11 8 | 4420 units each with 9691 hit points (weak to radiation; immune to fire) with an attack that does 21 fire damage at initiative 7 9 | 3978 units each with 2306 hit points (weak to cold, radiation) with an attack that does 4 fire damage at initiative 12 10 | 1284 units each with 4487 hit points (weak to radiation, bludgeoning) with an attack that does 32 slashing damage at initiative 19 -------------------------------------------------------------------------------- /src/main/resources/day24_input_infection.txt: -------------------------------------------------------------------------------- 1 | 4262 units each with 23427 hit points (weak to slashing; immune to fire) with an attack that does 9 slashing damage at initiative 8 2 | 217 units each with 9837 hit points (weak to bludgeoning) with an attack that does 73 bludgeoning damage at initiative 1 3 | 5497 units each with 33578 hit points (weak to radiation, cold) with an attack that does 11 slashing damage at initiative 17 4 | 866 units each with 41604 hit points (weak to cold) with an attack that does 76 radiation damage at initiative 15 5 | 1823 units each with 19652 hit points (weak to fire, cold) with an attack that does 20 slashing damage at initiative 13 6 | 2044 units each with 23512 hit points (weak to cold) with an attack that does 22 slashing damage at initiative 9 7 | 373 units each with 40861 hit points (immune to cold) with an attack that does 215 slashing damage at initiative 18 8 | 5427 units each with 43538 hit points (immune to radiation; weak to bludgeoning) with an attack that does 15 slashing damage at initiative 5 9 | 3098 units each with 19840 hit points (weak to bludgeoning, cold) with an attack that does 12 radiation damage at initiative 3 10 | 785 units each with 14669 hit points with an attack that does 30 fire damage at initiative 6 -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day01Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 1") 13 | class Day01Test { 14 | 15 | // Given 16 | val sampleInput = listOf("+1", "-2", "+3", "+1") 17 | val actualInput = Resources.resourceAsList("day01_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // When 26 | val day = Day01(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(3) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day01(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(599) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // When 49 | val day = Day01(sampleInput) 50 | 51 | // Then 52 | assertThat(day.solvePart2()).isEqualTo(2) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // When 58 | val day = Day01(actualInput) 59 | 60 | // Then 61 | assertThat(day.solvePart2()).isEqualTo(81204) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day02Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 2") 13 | class Day02Test { 14 | 15 | // Given 16 | val sampleInputPart1 = listOf("abcdef", "bababc", "abbcde", "abcccd", "aabcdd", "abcdee", "ababab") 17 | val sampleInputPart2 = listOf("abcde", "fghij", "klmno", "pqrst", "fguij", "axcye", "wvxyz") 18 | val actualInput = Resources.resourceAsList("day02_input.txt") 19 | 20 | @Nested 21 | @DisplayName("Part 1") 22 | inner class Part1 { 23 | 24 | @Test 25 | fun `Matches example`() { 26 | // When 27 | val day = Day02(sampleInputPart1) 28 | 29 | // Then 30 | assertThat(day.solvePart1()).isEqualTo(12) 31 | } 32 | 33 | @Test 34 | fun `Actual answer`() { 35 | // When 36 | val day = Day02(actualInput) 37 | 38 | // Then 39 | assertThat(day.solvePart1()).isEqualTo(8892) 40 | } 41 | } 42 | 43 | @Nested 44 | @DisplayName("Part 2") 45 | inner class Part2 { 46 | 47 | @Test 48 | fun `Matches example`() { 49 | // When 50 | val day = Day02(sampleInputPart2) 51 | 52 | // Then 53 | assertThat(day.solvePart2()).isEqualTo("fgij") 54 | } 55 | 56 | @Test 57 | fun `Actual answer`() { 58 | // When 59 | val day = Day02(actualInput) 60 | 61 | // Then 62 | assertThat(day.solvePart2()).isEqualTo("zihwtxagifpbsnwleydukjmqv") 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day03Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 3") 13 | class Day03Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | "#1 @ 1,3: 4x4", 18 | "#2 @ 3,1: 4x4", 19 | "#3 @ 5,5: 2x2" 20 | ) 21 | val actualInput = Resources.resourceAsList("day03_input.txt") 22 | 23 | @Nested 24 | @DisplayName("Part 1") 25 | inner class Part1 { 26 | 27 | @Test 28 | fun `Matches example`() { 29 | // When 30 | val day = Day03(sampleInput) 31 | 32 | // Then 33 | assertThat(day.solvePart1()).isEqualTo(4) 34 | } 35 | 36 | @Test 37 | fun `Actual answer`() { 38 | // When 39 | val day = Day03(actualInput) 40 | 41 | // Then 42 | assertThat(day.solvePart1()).isEqualTo(121163) 43 | } 44 | } 45 | 46 | @Nested 47 | @DisplayName("Part 2") 48 | inner class Part2 { 49 | 50 | @Test 51 | fun `Matches example`() { 52 | // When 53 | val day = Day03(sampleInput) 54 | 55 | // Then 56 | assertThat(day.solvePart2()).isEqualTo(3) 57 | } 58 | 59 | @Test 60 | fun `Actual answer`() { 61 | // When 62 | val day = Day03(actualInput) 63 | 64 | // Then 65 | assertThat(day.solvePart2()).isEqualTo(943) 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day04Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 4") 13 | class Day04Test { 14 | 15 | // Given 16 | val sampleInput = """ 17 | [1518-11-01 00:00] Guard #10 begins shift 18 | [1518-11-01 00:05] falls asleep 19 | [1518-11-01 00:25] wakes up 20 | [1518-11-01 00:30] falls asleep 21 | [1518-11-01 00:55] wakes up 22 | [1518-11-01 23:58] Guard #99 begins shift 23 | [1518-11-02 00:40] falls asleep 24 | [1518-11-02 00:50] wakes up 25 | [1518-11-03 00:05] Guard #10 begins shift 26 | [1518-11-03 00:24] falls asleep 27 | [1518-11-03 00:29] wakes up 28 | [1518-11-04 00:02] Guard #99 begins shift 29 | [1518-11-04 00:36] falls asleep 30 | [1518-11-04 00:46] wakes up 31 | [1518-11-05 00:03] Guard #99 begins shift 32 | [1518-11-05 00:45] falls asleep 33 | [1518-11-05 00:55] wakes up 34 | """.trimIndent().lines() 35 | val actualInput = Resources.resourceAsList("day04_input.txt") 36 | 37 | @Nested 38 | @DisplayName("Part 1") 39 | inner class Part1 { 40 | 41 | @Test 42 | fun `Matches example`() { 43 | // When 44 | val day = Day04(sampleInput) 45 | 46 | // Then 47 | assertThat(day.solvePart1()).isEqualTo(240) 48 | } 49 | 50 | @Test 51 | fun `Actual answer`() { 52 | // When 53 | val day = Day04(actualInput) 54 | 55 | // Then 56 | assertThat(day.solvePart1()).isEqualTo(146622) 57 | } 58 | } 59 | 60 | @Nested 61 | @DisplayName("Part 2") 62 | inner class Part2 { 63 | 64 | @Test 65 | fun `Matches example`() { 66 | // When 67 | val day = Day04(sampleInput) 68 | 69 | // Then 70 | assertThat(day.solvePart2()).isEqualTo(4455) 71 | } 72 | 73 | @Test 74 | fun `Actual answer`() { 75 | // When 76 | val day = Day04(actualInput) 77 | 78 | // Then 79 | assertThat(day.solvePart2()).isEqualTo(31848) 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day05Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 5") 13 | class Day05Test { 14 | 15 | // Given 16 | val sampleInput = "dabAcCaCBAcCcaDA" 17 | val actualInput = Resources.resourceAsString("day05_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // When 26 | val day = Day05(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(10) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day05(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(9808) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // When 49 | val day = Day05(sampleInput) 50 | 51 | // Then 52 | assertThat(day.solvePart2()).isEqualTo(4) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // When 58 | val day = Day05(actualInput) 59 | 60 | // Then 61 | assertThat(day.solvePart2()).isEqualTo(6484) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day06Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 6") 13 | class Day06Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | "1, 1", 18 | "1, 6", 19 | "8, 3", 20 | "3, 4", 21 | "5, 5", 22 | "8, 9" 23 | ) 24 | val actualInput = Resources.resourceAsList("day06_input.txt") 25 | 26 | @Nested 27 | @DisplayName("Part 1") 28 | inner class Part1 { 29 | 30 | @Test 31 | fun `Matches example`() { 32 | // When 33 | val day = Day06(sampleInput) 34 | 35 | // Then 36 | assertThat(day.solvePart1()).isEqualTo(17) 37 | } 38 | 39 | @Test 40 | fun `Actual answer`() { 41 | // When 42 | val day = Day06(actualInput) 43 | 44 | // Then 45 | assertThat(day.solvePart1()).isEqualTo(3223) 46 | } 47 | } 48 | 49 | @Nested 50 | @DisplayName("Part 2") 51 | inner class Part2 { 52 | 53 | @Test 54 | fun `Matches example`() { 55 | // When 56 | val day = Day06(sampleInput) 57 | 58 | // Then 59 | assertThat(day.solvePart2(32)).isEqualTo(16) 60 | } 61 | 62 | @Test 63 | fun `Actual answer`() { 64 | // When 65 | val day = Day06(actualInput) 66 | 67 | // Then 68 | assertThat(day.solvePart2()).isEqualTo(40495) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day07Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 7") 13 | class Day07Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | "Step C must be finished before step A can begin.", 18 | "Step C must be finished before step F can begin.", 19 | "Step A must be finished before step B can begin.", 20 | "Step A must be finished before step D can begin.", 21 | "Step B must be finished before step E can begin.", 22 | "Step D must be finished before step E can begin.", 23 | "Step F must be finished before step E can begin." 24 | ) 25 | val actualInput = Resources.resourceAsList("day07_input.txt") 26 | 27 | @Nested 28 | @DisplayName("Part 1") 29 | inner class Part1 { 30 | 31 | @Test 32 | fun `Matches example`() { 33 | // When 34 | val day = Day07(sampleInput) 35 | 36 | // Then 37 | assertThat(day.solvePart1()).isEqualTo("CABDFE") 38 | } 39 | 40 | @Test 41 | fun `Actual answer`() { 42 | // When 43 | val day = Day07(actualInput) 44 | 45 | // Then 46 | assertThat(day.solvePart1()).isEqualTo("MNQKRSFWGXPZJCOTVYEBLAHIUD") 47 | } 48 | } 49 | 50 | @Nested 51 | @DisplayName("Part 2") 52 | inner class Part2 { 53 | 54 | @Test 55 | fun `Matches example`() { 56 | // When 57 | val day = Day07(sampleInput) 58 | 59 | // Then 60 | assertThat(day.solvePart2(2, Day07.Companion::exampleCostFunction)).isEqualTo(15) 61 | } 62 | 63 | @Test 64 | fun `Actual answer`() { 65 | // When 66 | val day = Day07(actualInput) 67 | 68 | // Then 69 | assertThat(day.solvePart2(5, Day07.Companion::actualCostFunction)).isEqualTo(948) 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day08Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 8") 13 | class Day08Test { 14 | 15 | // Given 16 | val sampleInput = "2 3 0 3 10 11 12 1 1 0 1 99 2 1 1 2" 17 | val actualInput = Resources.resourceAsString("day08_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // When 26 | val day = Day08(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(138) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day08(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(36891) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // When 49 | val day = Day08(sampleInput) 50 | 51 | // Then 52 | assertThat(day.solvePart2()).isEqualTo(66) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // When 58 | val day = Day08(actualInput) 59 | 60 | // Then 61 | assertThat(day.solvePart2()).isEqualTo(20083) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day09Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 9") 13 | class Day09Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | Triple(9, 25, 32L), 18 | Triple(10, 1618, 8317L), 19 | Triple(13, 7999, 146373L), 20 | Triple(17, 1104, 2764L), 21 | Triple(21, 6111, 54718L), 22 | Triple(30, 5807, 37305L) 23 | ) 24 | val actualInput = Resources.resourceAsString("day09_input.txt") 25 | .split(" ") 26 | .run { this[0].toInt() to this[6].toInt() } 27 | 28 | @Nested 29 | @DisplayName("Part 1") 30 | inner class Part1 { 31 | 32 | @Test 33 | fun `Matches example`() { 34 | sampleInput.forEach { input -> 35 | // When 36 | val day = Day09(input.first, input.second) 37 | 38 | // Then 39 | assertThat(day.solvePart1()).isEqualTo(input.third) 40 | } 41 | 42 | } 43 | 44 | @Test 45 | fun `Actual answer`() { 46 | // When 47 | val day = Day09(actualInput.first, actualInput.second) 48 | 49 | // Then 50 | assertThat(day.solvePart1()).isEqualTo(404_611) 51 | } 52 | } 53 | 54 | @Nested 55 | @DisplayName("Part 2") 56 | inner class Part2 { 57 | 58 | @Test 59 | fun `Actual answer`() { 60 | // When 61 | val day = Day09(actualInput.first, actualInput.second) 62 | 63 | // Then 64 | assertThat(day.solvePart2()).isEqualTo(3_350_093_681) 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day10Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 10") 13 | class Day10Test { 14 | 15 | // Given 16 | val sampleInput = Resources.resourceAsList("day10_input_sample.txt") 17 | val actualInput = Resources.resourceAsList("day10_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // Given 26 | val answer = Resources.resourceAsString("day10_part1_sample_answer.txt", "\n") 27 | 28 | // When 29 | val day = Day10(sampleInput) 30 | 31 | // Then 32 | assertThat(day.solvePart1()).isEqualTo(answer) 33 | } 34 | 35 | @Test 36 | fun `Actual answer`() { 37 | // Given 38 | val answer = Resources.resourceAsString("day10_part1_answer.txt", "\n") 39 | 40 | // When 41 | val day = Day10(actualInput) 42 | 43 | // Then 44 | assertThat(day.solvePart1()).isEqualTo(answer) 45 | } 46 | } 47 | 48 | @Nested 49 | @DisplayName("Part 2") 50 | inner class Part2 { 51 | 52 | @Test 53 | fun `Matches example`() { 54 | // When 55 | val day = Day10(sampleInput) 56 | 57 | // Then 58 | assertThat(day.solvePart2()).isEqualTo(3) 59 | } 60 | 61 | @Test 62 | fun `Actual answer`() { 63 | // When 64 | val day = Day10(actualInput) 65 | 66 | // Then 67 | assertThat(day.solvePart2()).isEqualTo(10813) 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day11Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 11") 13 | class Day11Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | intArrayOf(18, 33, 45, 90, 269, 16), 18 | intArrayOf(42, 21, 61, 232, 251, 12) 19 | 20 | ) 21 | val actualInput = Resources.resourceAsString("day11_input.txt").toInt() 22 | 23 | @Nested 24 | @DisplayName("Part 1") 25 | inner class Part1 { 26 | 27 | @Test 28 | fun `Matches examples`() { 29 | // Given 30 | sampleInput.forEach { input -> 31 | // When 32 | val day = Day11(input.first()) 33 | 34 | // Then 35 | assertThat(day.solvePart1()).isEqualTo(Pair(input[1], input[2])) 36 | } 37 | 38 | } 39 | 40 | @Test 41 | fun `Actual answer`() { 42 | // When 43 | val day = Day11(actualInput) 44 | 45 | // Then 46 | assertThat(day.solvePart1()).isEqualTo(Pair(21, 37)) 47 | } 48 | } 49 | 50 | @Nested 51 | @DisplayName("Part 2") 52 | inner class Part2 { 53 | 54 | @Test 55 | fun `Matches example`() { 56 | // Given 57 | sampleInput.forEach { input -> 58 | // When 59 | val day = Day11(input.first()) 60 | 61 | // Then 62 | assertThat(day.solvePart2()).isEqualTo(Triple(input[3], input[4], input[5])) 63 | } 64 | 65 | } 66 | 67 | @Test 68 | fun `Actual answer`() { 69 | // When 70 | val day = Day11(actualInput) 71 | 72 | // Then 73 | assertThat(day.solvePart2()).isEqualTo(Triple(236, 146, 12)) 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day12Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 12") 13 | class Day12Test { 14 | 15 | // Given 16 | val sampleInput = Resources.resourceAsList("day12_input_sample.txt") 17 | val actualInput = Resources.resourceAsList("day12_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // When 26 | val day = Day12(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(325L) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day12(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(3472L) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Actual answer`() { 48 | // When 49 | val day = Day12(actualInput) 50 | 51 | // Then 52 | assertThat(day.solvePart2()).isEqualTo(2600000000919L) 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day13Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 13") 13 | class Day13Test { 14 | 15 | // Given 16 | val actualInput = Resources.resourceAsList("day13_input.txt") 17 | 18 | @Nested 19 | @DisplayName("Part 1") 20 | inner class Part1 { 21 | val sampleInput = Resources.resourceAsList("day13_input_sample_part1.txt") 22 | 23 | @Test 24 | fun `Matches examples`() { 25 | // When 26 | val day = Day13(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(Point(7,3)) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day13(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(Point(117,62)) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | val sampleInput = Resources.resourceAsList("day13_input_sample_part2.txt") 46 | 47 | @Test 48 | fun `Matches examples`() { 49 | // When 50 | val day = Day13(sampleInput) 51 | 52 | // Then 53 | assertThat(day.solvePart2()).isEqualTo(Point(6,4)) 54 | } 55 | 56 | @Test 57 | fun `Actual answer`() { 58 | // When 59 | val day = Day13(actualInput) 60 | 61 | // Then 62 | assertThat(day.solvePart2()).isEqualTo(Point(69,67)) 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day14Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 14") 13 | class Day14Test { 14 | 15 | // Given 16 | val actualInput = Resources.resourceAsString("day14_input.txt") 17 | 18 | @Nested 19 | @DisplayName("Part 1") 20 | inner class Part1 { 21 | 22 | @Test 23 | fun `Matches examples`() { 24 | // When 25 | val day = Day14("9") 26 | 27 | // Then 28 | assertThat(day.solvePart1()).isEqualTo("5158916779") 29 | } 30 | 31 | @Test 32 | fun `Actual answer`() { 33 | // When 34 | val day = Day14(actualInput) 35 | 36 | // Then 37 | assertThat(day.solvePart1()).isEqualTo("2103141159") 38 | } 39 | } 40 | 41 | @Nested 42 | @DisplayName("Part 2") 43 | inner class Part2 { 44 | 45 | private val sampleInputs = listOf( 46 | Pair("51589", 9), 47 | Pair("01245", 5), 48 | Pair("92510", 18), 49 | Pair("59414", 2018) 50 | ) 51 | 52 | @Test 53 | fun `Matches examples`() { 54 | sampleInputs.forEach { input -> 55 | // When 56 | val day = Day14(input.first) 57 | 58 | // Then 59 | assertThat(day.solvePart2()).isEqualTo(input.second) 60 | } 61 | 62 | } 63 | 64 | @Test 65 | fun `Actual answer`() { 66 | // When 67 | val day = Day14(actualInput) 68 | 69 | // Then 70 | assertThat(day.solvePart2()).isEqualTo(20_165_733) 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day15Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 15") 13 | class Day15Test { 14 | 15 | // Given 16 | val actualInput = Resources.resourceAsList("day15_input.txt") 17 | 18 | @Nested 19 | @DisplayName("Part 1") 20 | inner class Part1 { 21 | // Given 22 | val sampleInput = listOf( 23 | Pair(Resources.resourceAsList("day15_input_sample1.txt"), 27730), 24 | Pair(Resources.resourceAsList("day15_input_sample2.txt"), 36334), 25 | Pair(Resources.resourceAsList("day15_input_sample3.txt"), 39514), 26 | Pair(Resources.resourceAsList("day15_input_sample4.txt"), 27755), 27 | Pair(Resources.resourceAsList("day15_input_sample5.txt"), 28944), 28 | Pair(Resources.resourceAsList("day15_input_sample6.txt"), 18740), 29 | Pair(Resources.resourceAsList("day15_input_sample7.txt"), 13400), 30 | Pair(Resources.resourceAsList("day15_input_sample8.txt"), 13987) 31 | ) 32 | 33 | @Test 34 | fun `Matches examples`() { 35 | sampleInput.forEach { input -> 36 | // When 37 | val day = Day15(input.first) 38 | 39 | // Then 40 | assertThat(day.solvePart1()).isEqualTo(input.second) 41 | } 42 | } 43 | 44 | @Test 45 | fun `Actual answer`() { 46 | // When 47 | val day = Day15(actualInput) 48 | 49 | // Then 50 | assertThat(day.solvePart1()).isEqualTo(245280) 51 | } 52 | } 53 | 54 | @Nested 55 | @DisplayName("Part 2") 56 | inner class Part2 { 57 | // Given 58 | val sampleInput = listOf( 59 | Pair(Resources.resourceAsList("day15_input_sample1.txt"), 4988), 60 | Pair(Resources.resourceAsList("day15_input_sample3.txt"), 31284), 61 | Pair(Resources.resourceAsList("day15_input_sample4.txt"), 3478), 62 | Pair(Resources.resourceAsList("day15_input_sample5.txt"), 6474), 63 | Pair(Resources.resourceAsList("day15_input_sample6.txt"), 1140) 64 | ) 65 | 66 | @Test 67 | fun `Matches examples`() { 68 | sampleInput.forEach { input -> 69 | // When 70 | val day = Day15(input.first) 71 | 72 | // Then 73 | assertThat(day.solvePart2()).isEqualTo(input.second) 74 | } 75 | } 76 | 77 | @Test 78 | fun `Actual answer`() { 79 | // When 80 | val day = Day15(actualInput) 81 | 82 | // Then 83 | assertThat(day.solvePart2()).isEqualTo(74984) 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day16Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 16") 13 | class Day16Test { 14 | 15 | 16 | // Given 17 | val sampleInputPart1 = Resources.resourceAsList("day16_input_sample_part1.txt") 18 | val actualInputPart1 = Resources.resourceAsList("day16_input_part1.txt") 19 | val actualInputPart2 = Resources.resourceAsList("day16_input_part2.txt") 20 | 21 | @Nested 22 | @DisplayName("Part 1") 23 | inner class Part1 { 24 | 25 | @Test 26 | fun `Matches examples`() { 27 | // When 28 | val day = Day16(sampleInputPart1, listOf()) 29 | 30 | // Then 31 | assertThat(day.solvePart1()).isEqualTo(1) 32 | } 33 | 34 | @Test 35 | fun `Actual answer`() { 36 | // When 37 | val day = Day16(actualInputPart1, actualInputPart2) 38 | 39 | // Then 40 | assertThat(day.solvePart1()).isEqualTo(588) 41 | } 42 | } 43 | 44 | @Nested 45 | @DisplayName("Part 2") 46 | inner class Part2 { 47 | 48 | 49 | @Test 50 | fun `Actual answer`() { 51 | // When 52 | val day = Day16(actualInputPart1, actualInputPart2) 53 | 54 | // Then 55 | assertThat(day.solvePart2()).isEqualTo(627) 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day17Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 17") 13 | class Day17Test { 14 | 15 | // Given 16 | val sampleInput = Resources.resourceAsList("day17_input_sample.txt") 17 | val actualInput = Resources.resourceAsList("day17_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches examples`() { 25 | // When 26 | val day = Day17(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(57) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day17(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(31949) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches examples`() { 48 | // When 49 | val day = Day17(sampleInput) 50 | 51 | // Then 52 | assertThat(day.solvePart2()).isEqualTo(29) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // When 58 | val day = Day17(actualInput) 59 | 60 | // Then 61 | assertThat(day.solvePart2()).isEqualTo(26384) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day18Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 18") 13 | class Day18Test { 14 | 15 | // Given 16 | val sampleInput = Resources.resourceAsList("day18_input_sample.txt") 17 | val actualInput = Resources.resourceAsList("day18_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches examples`() { 25 | // When 26 | val day = Day18(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(1147) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day18(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(481290) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | 47 | @Test 48 | fun `Actual answer`() { 49 | // When 50 | val day = Day18(actualInput) 51 | 52 | // Then 53 | assertThat(day.solvePart2()).isEqualTo(180752) 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day19Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 19") 13 | class Day19Test { 14 | 15 | // Given 16 | val sampleInput = Resources.resourceAsList("day19_input_sample.txt") 17 | val actualInput = Resources.resourceAsList("day19_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches examples`() { 25 | // When 26 | val day = Day19(sampleInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(6) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // When 35 | val day = Day19(actualInput) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(2280) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | 47 | @Test 48 | fun `Actual answer`() { 49 | // When 50 | val day = Day19(actualInput) 51 | 52 | // Then 53 | assertThat(day.solvePart2()).isEqualTo(30481920) 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day20Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 20") 13 | class Day20Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | """^WNE$""" to 3, 18 | """^ENWWW(NEEE|SSE(EE|N))$""" to 10, 19 | """^ENNWSWW(NEWS|)SSSEEN(WNSE|)EE(SWEN|)NNN$""" to 18 20 | ) 21 | val actualInput = Resources.resourceAsString("day20_input.txt") 22 | 23 | @Nested 24 | @DisplayName("Part 1") 25 | inner class Part1 { 26 | 27 | @Test 28 | fun `Matches examples`() { 29 | // Given 30 | sampleInput.forEach { input -> 31 | 32 | // When 33 | val day = Day20(input.first) 34 | 35 | // Then 36 | assertThat(day.solvePart1()).isEqualTo(input.second) 37 | } 38 | } 39 | 40 | @Test 41 | fun `Actual answer`() { 42 | // When 43 | val day = Day20(actualInput) 44 | 45 | // Then 46 | assertThat(day.solvePart1()).isEqualTo(3699) 47 | } 48 | } 49 | 50 | @Nested 51 | @DisplayName("Part 2") 52 | inner class Part2 { 53 | 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // When 58 | val day = Day20(actualInput) 59 | 60 | // Then 61 | assertThat(day.solvePart2()).isEqualTo(8517) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day21Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.Disabled 9 | import org.junit.jupiter.api.DisplayName 10 | import org.junit.jupiter.api.Nested 11 | import org.junit.jupiter.api.Test 12 | 13 | @DisplayName("Day 21") 14 | class Day21Test { 15 | 16 | // Given 17 | val actualInput = Resources.resourceAsList("day21_input.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Actual answer`() { 25 | // When 26 | val day = Day21(actualInput) 27 | 28 | // Then 29 | assertThat(day.solvePart1()).isEqualTo(103548) 30 | } 31 | } 32 | 33 | @Nested 34 | @DisplayName("Part 2") 35 | @Disabled("This is suuuuuuper slow (~1m37s)") 36 | inner class Part2 { 37 | 38 | 39 | @Test 40 | fun `Actual answer`() { 41 | // When 42 | val day = Day21(actualInput) 43 | 44 | // Then 45 | assertThat(day.solvePart2()).isEqualTo(14256686) 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day22Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 22") 13 | class Day22Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | "depth: 510", 18 | "target: 10,10" 19 | ) 20 | val actualInput = Resources.resourceAsList("day22_input.txt") 21 | 22 | @Nested 23 | @DisplayName("Part 1") 24 | inner class Part1 { 25 | 26 | @Test 27 | fun `Matches examples`() { 28 | 29 | // When 30 | val day = Day22(sampleInput) 31 | 32 | // Then 33 | assertThat(day.solvePart1()).isEqualTo(114) 34 | 35 | } 36 | 37 | @Test 38 | fun `Actual answer`() { 39 | // When 40 | val day = Day22(actualInput) 41 | 42 | // Then 43 | assertThat(day.solvePart1()).isEqualTo(11359) 44 | } 45 | } 46 | 47 | @Nested 48 | @DisplayName("Part 2") 49 | inner class Part2 { 50 | 51 | @Test 52 | fun `Matches examples`() { 53 | 54 | // When 55 | val day = Day22(sampleInput) 56 | 57 | // Then 58 | assertThat(day.solvePart2()).isEqualTo(45) 59 | 60 | } 61 | 62 | @Test 63 | fun `Actual answer`() { 64 | // When 65 | val day = Day22(actualInput) 66 | 67 | // Then 68 | assertThat(day.solvePart2()).isEqualTo(976) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day23Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 23") 13 | class Day23Test { 14 | 15 | // Given 16 | val actualInput = Resources.resourceAsList("day23_input.txt") 17 | 18 | @Nested 19 | @DisplayName("Part 1") 20 | inner class Part1 { 21 | 22 | val sampleInput = Resources.resourceAsList("day23_input_sample_part1.txt") 23 | 24 | @Test 25 | fun `Matches examples`() { 26 | 27 | // When 28 | val day = Day23(sampleInput) 29 | 30 | // Then 31 | assertThat(day.solvePart1()).isEqualTo(7) 32 | 33 | } 34 | 35 | @Test 36 | fun `Actual answer`() { 37 | // When 38 | val day = Day23(actualInput) 39 | 40 | // Then 41 | assertThat(day.solvePart1()).isEqualTo(326) 42 | } 43 | } 44 | 45 | @Nested 46 | @DisplayName("Part 2") 47 | inner class Part2 { 48 | 49 | val sampleInput = Resources.resourceAsList("day23_input_sample_part2.txt") 50 | 51 | @Test 52 | fun `Matches examples`() { 53 | 54 | // When 55 | val day = Day23(sampleInput) 56 | 57 | // Then 58 | assertThat(day.solvePart2()).isEqualTo(36) 59 | 60 | } 61 | 62 | @Test 63 | fun `Actual answer`() { 64 | // When 65 | val day = Day23(actualInput) 66 | 67 | // Then 68 | assertThat(day.solvePart2()).isEqualTo(142473501) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day24Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 24") 13 | class Day24Test { 14 | 15 | // Given 16 | val sampleInputImmune = listOf( 17 | "17 units each with 5390 hit points (weak to radiation, bludgeoning) with an attack that does 4507 fire damage at initiative 2", 18 | "989 units each with 1274 hit points (immune to fire; weak to bludgeoning, slashing) with an attack that does 25 slashing damage at initiative 3" 19 | ) 20 | val sampleInputInfection = listOf( 21 | "801 units each with 4706 hit points (weak to radiation) with an attack that does 116 bludgeoning damage at initiative 1", 22 | "4485 units each with 2961 hit points (immune to radiation; weak to fire, cold) with an attack that does 12 slashing damage at initiative 4" 23 | ) 24 | val actualInputImmuneSystem = Resources.resourceAsList("day24_input_immune.txt") 25 | val actualInputInfection = Resources.resourceAsList("day24_input_infection.txt") 26 | 27 | @Nested 28 | @DisplayName("Part 1") 29 | inner class Part1 { 30 | 31 | @Test 32 | fun `Matches examples`() { 33 | 34 | // When 35 | val day = Day24(sampleInputImmune, sampleInputInfection) 36 | 37 | // Then 38 | assertThat(day.solvePart1()).isEqualTo(5216) 39 | 40 | } 41 | 42 | @Test 43 | fun `Actual answer`() { 44 | // When 45 | val day = Day24(actualInputImmuneSystem, actualInputInfection) 46 | 47 | // Then 48 | assertThat(day.solvePart1()).isEqualTo(21127) 49 | } 50 | } 51 | 52 | @Nested 53 | @DisplayName("Part 2") 54 | inner class Part2 { 55 | 56 | @Test 57 | fun `Matches examples`() { 58 | 59 | // When 60 | val day = Day24(sampleInputImmune, sampleInputInfection) 61 | 62 | // Then 63 | assertThat(day.solvePart2()).isEqualTo(51) 64 | 65 | } 66 | 67 | @Test 68 | fun `Actual answer`() { 69 | // When 70 | val day = Day24(actualInputImmuneSystem, actualInputInfection) 71 | 72 | // Then 73 | assertThat(day.solvePart2()).isEqualTo(2456) 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/Day25Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Day 25") 13 | class Day25Test { 14 | 15 | // Given 16 | val sampleInput = listOf( 17 | Pair("day25_input_sample_1.txt", 2), 18 | Pair("day25_input_sample_2.txt", 4), 19 | Pair("day25_input_sample_3.txt", 3), 20 | Pair("day25_input_sample_4.txt", 8) 21 | ) 22 | val actualInput = Resources.resourceAsList("day25_input.txt") 23 | 24 | @Nested 25 | @DisplayName("Part 1") 26 | inner class Part1 { 27 | 28 | @Test 29 | fun `Matches examples`() { 30 | // Given 31 | sampleInput.forEach { (file, answer) -> 32 | 33 | // When 34 | val day = Day25(Resources.resourceAsList(file)) 35 | 36 | // Then 37 | assertThat(day.solvePart1()).isEqualTo(answer) 38 | } 39 | 40 | } 41 | 42 | @Test 43 | fun `Actual answer`() { 44 | // When 45 | val day = Day25(actualInput) 46 | 47 | // Then 48 | assertThat(day.solvePart1()).isEqualTo(388) 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/ExtensionsTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import org.assertj.core.api.Assertions.assertThat 8 | import org.junit.jupiter.api.DisplayName 9 | import org.junit.jupiter.api.Nested 10 | import org.junit.jupiter.api.Test 11 | 12 | @DisplayName("Extension Tests") 13 | internal class ExtensionsTest { 14 | 15 | @DisplayName("Infinite Sequence from List") 16 | @Nested 17 | inner class ListToSequence { 18 | 19 | @Test 20 | @DisplayName("Sequence loops around on list") 21 | fun loopAround() { 22 | // Given 23 | val input = listOf(1, 2, 3) 24 | 25 | // Then 26 | assertThat(input.toInfiniteSequence().take(7).toList()) 27 | .isEqualTo(listOf(1, 2, 3, 1, 2, 3, 1)) 28 | } 29 | 30 | @Test 31 | @DisplayName("Detects empty list") 32 | fun emptyList() { 33 | // Given 34 | val input = emptyList() 35 | 36 | // Then 37 | assertThat(input.toInfiniteSequence().toList()) 38 | .isEmpty() 39 | } 40 | } 41 | 42 | @DisplayName("Most Frequent Element") 43 | @Nested 44 | inner class MostFrequentElement { 45 | 46 | @Test 47 | @DisplayName("Empty means null") 48 | fun emptyList() { 49 | // Given 50 | val input = emptyList() 51 | 52 | // Then 53 | assertThat(input.mostFrequent()).isNull() 54 | } 55 | 56 | @Test 57 | @DisplayName("Finds most frequent") 58 | fun findsMostFrequent() { 59 | // Given 60 | val input = listOf(1, 1, 2, 2, 2) 61 | 62 | // Then 63 | assertThat(input.mostFrequent()).isEqualTo(2) 64 | } 65 | } 66 | 67 | @DisplayName("IntRange Span") 68 | @Nested 69 | inner class IntRangeSpan { 70 | 71 | @Test 72 | @DisplayName("Zero range is zero") 73 | fun zeroMeansZero() { 74 | // Given 75 | val range = IntRange(0, 0) 76 | 77 | // Then 78 | assertThat(range.span).isEqualTo(0L) 79 | } 80 | 81 | @Test 82 | @DisplayName("Both Positive") 83 | fun bothPositive() { 84 | // Given 85 | val range = IntRange(10, 20) 86 | 87 | // Then 88 | assertThat(range.span).isEqualTo(10) 89 | } 90 | 91 | @Test 92 | @DisplayName("Both Negative") 93 | fun bothNegative() { 94 | // Given 95 | val range = IntRange(-20, -10) 96 | 97 | // Then 98 | assertThat(range.span).isEqualTo(10) 99 | } 100 | 101 | @Test 102 | @DisplayName("Negative through Positive") 103 | fun negativeThroughPositive() { 104 | // Given 105 | val range = IntRange(-20, 20) 106 | 107 | // Then 108 | assertThat(range.span).isEqualTo(40) 109 | } 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2018/ResourcesTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2018 6 | 7 | import com.ginsberg.advent2018.Resources.resourceAsList 8 | import com.ginsberg.advent2018.Resources.resourceAsString 9 | import org.assertj.core.api.Assertions.assertThat 10 | import org.junit.jupiter.api.Test 11 | 12 | internal class ResourcesTest { 13 | 14 | @Test 15 | fun `resourceAsString concatenates lines without delimiter`() { 16 | assertThat(resourceAsString("read_file_test_1.txt")) 17 | .isEqualTo("ABC") 18 | } 19 | 20 | @Test 21 | fun `resourceAsString concatenates lines with delimiter`() { 22 | assertThat(resourceAsString(fileName = "read_file_test_1.txt", delimiter = ":::")) 23 | .isEqualTo("A:::B:::C") 24 | } 25 | 26 | @Test 27 | fun `resourceAsList reads lines`() { 28 | assertThat(resourceAsList("read_file_test_1.txt")) 29 | .hasSize(3) 30 | .containsExactly("A", "B", "C") 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /src/test/resources/day10_input_sample.txt: -------------------------------------------------------------------------------- 1 | position=< 9, 1> velocity=< 0, 2> 2 | position=< 7, 0> velocity=<-1, 0> 3 | position=< 3, -2> velocity=<-1, 1> 4 | position=< 6, 10> velocity=<-2, -1> 5 | position=< 2, -4> velocity=< 2, 2> 6 | position=<-6, 10> velocity=< 2, -2> 7 | position=< 1, 8> velocity=< 1, -1> 8 | position=< 1, 7> velocity=< 1, 0> 9 | position=<-3, 11> velocity=< 1, -2> 10 | position=< 7, 6> velocity=<-1, -1> 11 | position=<-2, 3> velocity=< 1, 0> 12 | position=<-4, 3> velocity=< 2, 0> 13 | position=<10, -3> velocity=<-1, 1> 14 | position=< 5, 11> velocity=< 1, -2> 15 | position=< 4, 7> velocity=< 0, -1> 16 | position=< 8, -2> velocity=< 0, 1> 17 | position=<15, 0> velocity=<-2, 0> 18 | position=< 1, 6> velocity=< 1, 0> 19 | position=< 8, 9> velocity=< 0, -1> 20 | position=< 3, 3> velocity=<-1, 1> 21 | position=< 0, 5> velocity=< 0, -1> 22 | position=<-2, 2> velocity=< 2, 0> 23 | position=< 5, -2> velocity=< 1, 2> 24 | position=< 1, 4> velocity=< 2, 1> 25 | position=<-2, 7> velocity=< 2, -2> 26 | position=< 3, 6> velocity=<-1, -1> 27 | position=< 5, 0> velocity=< 1, 0> 28 | position=<-6, 0> velocity=< 2, 0> 29 | position=< 5, 9> velocity=< 1, -2> 30 | position=<14, 7> velocity=<-2, 0> 31 | position=<-3, 6> velocity=< 2, -1> 32 | -------------------------------------------------------------------------------- /src/test/resources/day10_part1_answer.txt: -------------------------------------------------------------------------------- 1 | ######..#####....####...#....#..#.........##.......###..#..... 2 | #.......#....#..#....#..#....#..#........#..#.......#...#..... 3 | #.......#....#..#........#..#...#.......#....#......#...#..... 4 | #.......#....#..#........#..#...#.......#....#......#...#..... 5 | #####...#####...#.........##....#.......#....#......#...#..... 6 | #.......#..#....#.........##....#.......######......#...#..... 7 | #.......#...#...#........#..#...#.......#....#......#...#..... 8 | #.......#...#...#........#..#...#.......#....#..#...#...#..... 9 | #.......#....#..#....#..#....#..#.......#....#..#...#...#..... 10 | ######..#....#...####...#....#..######..#....#...###....###### -------------------------------------------------------------------------------- /src/test/resources/day10_part1_sample_answer.txt: -------------------------------------------------------------------------------- 1 | #...#..### 2 | #...#...#. 3 | #...#...#. 4 | #####...#. 5 | #...#...#. 6 | #...#...#. 7 | #...#...#. 8 | #...#..### -------------------------------------------------------------------------------- /src/test/resources/day12_input_sample.txt: -------------------------------------------------------------------------------- 1 | initial state: #..#.#..##......###...### 2 | 3 | ...## => # 4 | ..#.. => # 5 | .#... => # 6 | .#.#. => # 7 | .#.## => # 8 | .##.. => # 9 | .#### => # 10 | #.#.# => # 11 | #.### => # 12 | ##.#. => # 13 | ##.## => # 14 | ###.. => # 15 | ###.# => # 16 | ####. => # -------------------------------------------------------------------------------- /src/test/resources/day13_input_sample_part1.txt: -------------------------------------------------------------------------------- 1 | /->-\ 2 | | | /----\ 3 | | /-+--+-\ | 4 | | | | | v | 5 | \-+-/ \-+--/ 6 | \------/ -------------------------------------------------------------------------------- /src/test/resources/day13_input_sample_part2.txt: -------------------------------------------------------------------------------- 1 | />-<\ 2 | | | 3 | | /<+-\ 4 | | | | v 5 | \>+/ -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample1.txt: -------------------------------------------------------------------------------- 1 | ####### 2 | #.G...# 3 | #...EG# 4 | #.#.#G# 5 | #..G#E# 6 | #.....# 7 | ####### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample2.txt: -------------------------------------------------------------------------------- 1 | ####### 2 | #G..#E# 3 | #E#E.E# 4 | #G.##.# 5 | #...#E# 6 | #...E.# 7 | ####### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample3.txt: -------------------------------------------------------------------------------- 1 | ####### 2 | #E..EG# 3 | #.#G.E# 4 | #E.##E# 5 | #G..#.# 6 | #..E#.# 7 | ####### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample4.txt: -------------------------------------------------------------------------------- 1 | ####### 2 | #E.G#.# 3 | #.#G..# 4 | #G.#.G# 5 | #G..#.# 6 | #...E.# 7 | ####### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample5.txt: -------------------------------------------------------------------------------- 1 | ####### 2 | #.E...# 3 | #.#..G# 4 | #.###.# 5 | #E#G#G# 6 | #...#G# 7 | ####### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample6.txt: -------------------------------------------------------------------------------- 1 | ######### 2 | #G......# 3 | #.E.#...# 4 | #..##..G# 5 | #...##..# 6 | #...#...# 7 | #.G...G.# 8 | #.....G.# 9 | ######### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample7.txt: -------------------------------------------------------------------------------- 1 | #### 2 | ##E# 3 | #GG# 4 | #### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample8.txt: -------------------------------------------------------------------------------- 1 | ##### 2 | #GG## 3 | #.### 4 | #..E# 5 | #.#G# 6 | #.E## 7 | ##### -------------------------------------------------------------------------------- /src/test/resources/day15_input_sample9.txt: -------------------------------------------------------------------------------- 1 | ####### 2 | #.E..G# 3 | #.##### 4 | #G##### 5 | ####### -------------------------------------------------------------------------------- /src/test/resources/day16_input_sample_part1.txt: -------------------------------------------------------------------------------- 1 | Before: [3, 2, 1, 1] 2 | 9 2 1 2 3 | After: [3, 2, 2, 1] 4 | 5 | -------------------------------------------------------------------------------- /src/test/resources/day17_input_sample.txt: -------------------------------------------------------------------------------- 1 | x=495, y=2..7 2 | y=7, x=495..501 3 | x=501, y=3..7 4 | x=498, y=2..4 5 | x=506, y=1..2 6 | x=498, y=10..13 7 | x=504, y=10..13 8 | y=13, x=498..504 -------------------------------------------------------------------------------- /src/test/resources/day18_input_sample.txt: -------------------------------------------------------------------------------- 1 | .#.#...|#. 2 | .....#|##| 3 | .|..|...#. 4 | ..|#.....# 5 | #.#|||#|#| 6 | ...#.||... 7 | .|....|... 8 | ||...#|.#| 9 | |.||||..|. 10 | ...#.|..|. -------------------------------------------------------------------------------- /src/test/resources/day19_input_sample.txt: -------------------------------------------------------------------------------- 1 | #ip 0 2 | seti 5 0 1 3 | seti 6 0 2 4 | addi 0 1 0 5 | addr 1 2 3 6 | setr 1 0 0 7 | seti 8 0 4 8 | seti 9 0 5 -------------------------------------------------------------------------------- /src/test/resources/day23_input_sample_part1.txt: -------------------------------------------------------------------------------- 1 | pos=<0,0,0>, r=4 2 | pos=<1,0,0>, r=1 3 | pos=<4,0,0>, r=3 4 | pos=<0,2,0>, r=1 5 | pos=<0,5,0>, r=3 6 | pos=<0,0,3>, r=1 7 | pos=<1,1,1>, r=1 8 | pos=<1,1,2>, r=1 9 | pos=<1,3,1>, r=1 -------------------------------------------------------------------------------- /src/test/resources/day23_input_sample_part2.txt: -------------------------------------------------------------------------------- 1 | pos=<10,12,12>, r=2 2 | pos=<12,14,12>, r=2 3 | pos=<16,12,12>, r=4 4 | pos=<14,14,14>, r=6 5 | pos=<50,50,50>, r=200 6 | pos=<10,10,10>, r=5 -------------------------------------------------------------------------------- /src/test/resources/day25_input_sample_1.txt: -------------------------------------------------------------------------------- 1 | 0,0,0,0 2 | 3,0,0,0 3 | 0,3,0,0 4 | 0,0,3,0 5 | 0,0,0,3 6 | 0,0,0,6 7 | 9,0,0,0 8 | 12,0,0,0 -------------------------------------------------------------------------------- /src/test/resources/day25_input_sample_2.txt: -------------------------------------------------------------------------------- 1 | -1,2,2,0 2 | 0,0,2,-2 3 | 0,0,0,-2 4 | -1,2,0,0 5 | -2,-2,-2,2 6 | 3,0,2,-1 7 | -1,3,2,2 8 | -1,0,-1,0 9 | 0,2,1,-2 10 | 3,0,0,0 -------------------------------------------------------------------------------- /src/test/resources/day25_input_sample_3.txt: -------------------------------------------------------------------------------- 1 | 1,-1,0,1 2 | 2,0,-1,0 3 | 3,2,-1,0 4 | 0,0,3,1 5 | 0,0,-1,-1 6 | 2,3,-2,0 7 | -2,2,0,0 8 | 2,-2,0,-1 9 | 1,-1,0,-1 10 | 3,2,0,2 -------------------------------------------------------------------------------- /src/test/resources/day25_input_sample_4.txt: -------------------------------------------------------------------------------- 1 | 1,-1,-1,-2 2 | -2,-2,0,1 3 | 0,2,1,3 4 | -2,3,-2,1 5 | 0,2,3,-2 6 | -1,-1,1,-2 7 | 0,-2,-1,0 8 | -2,2,3,-1 9 | 1,2,2,0 10 | -1,-2,0,-2 -------------------------------------------------------------------------------- /src/test/resources/read_file_test_1.txt: -------------------------------------------------------------------------------- 1 | A 2 | B 3 | C --------------------------------------------------------------------------------