├── src ├── test │ ├── resources │ │ ├── read_file_test_1.txt │ │ ├── day23_sample.txt │ │ ├── day13_sample.txt │ │ ├── day07_sample.txt │ │ ├── day11_sample.txt │ │ └── day10_sample.txt │ └── kotlin │ │ └── com │ │ └── ginsberg │ │ └── advent2022 │ │ ├── Day22Test.kt │ │ ├── Day25Test.kt │ │ ├── Day06Test.kt │ │ ├── Day23Test.kt │ │ ├── Day13Test.kt │ │ ├── Day07Test.kt │ │ ├── Day17Test.kt │ │ ├── Day10Test.kt │ │ ├── Day11Test.kt │ │ ├── Day02Test.kt │ │ ├── Day08Test.kt │ │ ├── Day14Test.kt │ │ ├── Day12Test.kt │ │ ├── Day04Test.kt │ │ ├── Day20Test.kt │ │ ├── Day24Test.kt │ │ ├── Day01Test.kt │ │ ├── Day03Test.kt │ │ ├── Day18Test.kt │ │ ├── Day05Test.kt │ │ ├── Day19Test.kt │ │ ├── Day21Test.kt │ │ ├── Day09Test.kt │ │ ├── Day16Test.kt │ │ ├── Day15Test.kt │ │ └── ResourcesTest.kt └── main │ ├── kotlin │ └── com │ │ └── ginsberg │ │ └── advent2022 │ │ ├── Point3D.kt │ │ ├── Day01.kt │ │ ├── Day06.kt │ │ ├── Day25.kt │ │ ├── Resources.kt │ │ ├── Extensions.kt │ │ ├── Day03.kt │ │ ├── Day04.kt │ │ ├── Day02.kt │ │ ├── Day20.kt │ │ ├── Point2D.kt │ │ ├── Day10.kt │ │ ├── Day18.kt │ │ ├── Day08.kt │ │ ├── Day05.kt │ │ ├── Day14.kt │ │ ├── Day09.kt │ │ ├── Day07.kt │ │ ├── Day15.kt │ │ ├── Day13.kt │ │ ├── Day23.kt │ │ ├── Day12.kt │ │ ├── Day11.kt │ │ ├── Day16.kt │ │ ├── Day21.kt │ │ ├── Day17.kt │ │ ├── Day24.kt │ │ └── Day19.kt │ └── resources │ ├── day11.txt │ ├── day10.txt │ ├── day25.txt │ ├── day15.txt │ ├── day16.txt │ ├── day24.txt │ ├── day12.txt │ ├── day06.txt │ ├── day19.txt │ ├── day23.txt │ ├── day17.txt │ ├── day08.txt │ └── day03.txt ├── settings.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github └── workflows │ └── build.yml ├── .gitignore ├── gradlew.bat ├── gradlew ├── README.md └── LICENSE /src/test/resources/read_file_test_1.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | rootProject.name = "advent-2022-kotlin" 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tginsberg/advent-2022-kotlin/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/test/resources/day23_sample.txt: -------------------------------------------------------------------------------- 1 | .............. 2 | .............. 3 | .......#...... 4 | .....###.#.... 5 | ...#...#.#.... 6 | ....#...##.... 7 | ...#.###...... 8 | ...##.#.##.... 9 | ....#..#...... 10 | .............. 11 | .............. 12 | .............. -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2022 by Todd Ginsberg 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /src/test/resources/day13_sample.txt: -------------------------------------------------------------------------------- 1 | [1,1,3,1,1] 2 | [1,1,5,1,1] 3 | 4 | [[1],[2,3,4]] 5 | [[1],4] 6 | 7 | [9] 8 | [[8,7,6]] 9 | 10 | [[4,4],4,4] 11 | [[4,4],4,4,4] 12 | 13 | [7,7,7,7] 14 | [7,7,7] 15 | 16 | [] 17 | [3] 18 | 19 | [[[]]] 20 | [[]] 21 | 22 | [1,[2,[3,[4,[5,6,7]]]],8,9] 23 | [1,[2,[3,[4,[5,6,0]]]],8,9] -------------------------------------------------------------------------------- /src/test/resources/day07_sample.txt: -------------------------------------------------------------------------------- 1 | $ cd / 2 | $ ls 3 | dir a 4 | 14848514 b.txt 5 | 8504156 c.dat 6 | dir d 7 | $ cd a 8 | $ ls 9 | dir e 10 | 29116 f 11 | 2557 g 12 | 62596 h.lst 13 | $ cd e 14 | $ ls 15 | 584 i 16 | $ cd .. 17 | $ cd .. 18 | $ cd d 19 | $ ls 20 | 4060174 j 21 | 8033020 d.log 22 | 5626152 d.ext 23 | 7214296 k -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Test 2 | on: [ push ] 3 | jobs: 4 | build-test: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | 9 | - uses: actions/setup-java@v1 10 | with: 11 | java-version: 17 12 | 13 | - uses: gradle/gradle-build-action@v2 14 | with: 15 | gradle-version: wrapper 16 | arguments: build test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | build/ 26 | .gradle/ 27 | .idea/ 28 | out/ 29 | 30 | # Allow the gradle wrapper 31 | !/gradle/wrapper/gradle-wrapper.jar 32 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Point3D.kt: -------------------------------------------------------------------------------- 1 | package com.ginsberg.advent2022 2 | 3 | data class Point3D(val x: Int = 0, val y: Int = 0, val z: Int = 0) { 4 | fun cardinalNeighbors(): Set = 5 | setOf( 6 | copy(x = x - 1), 7 | copy(x = x + 1), 8 | copy(y = y - 1), 9 | copy(y = y + 1), 10 | copy(z = z - 1), 11 | copy(z = z + 1) 12 | ) 13 | 14 | companion object { 15 | fun of(input: String): Point3D = 16 | input.split(",").let { (x, y, z) -> Point3D(x.toInt(), y.toInt(), z.toInt()) } 17 | } 18 | } -------------------------------------------------------------------------------- /src/test/resources/day11_sample.txt: -------------------------------------------------------------------------------- 1 | Monkey 0: 2 | Starting items: 79, 98 3 | Operation: new = old * 19 4 | Test: divisible by 23 5 | If true: throw to monkey 2 6 | If false: throw to monkey 3 7 | 8 | Monkey 1: 9 | Starting items: 54, 65, 75, 74 10 | Operation: new = old + 6 11 | Test: divisible by 19 12 | If true: throw to monkey 2 13 | If false: throw to monkey 0 14 | 15 | Monkey 2: 16 | Starting items: 79, 60, 97 17 | Operation: new = old * old 18 | Test: divisible by 13 19 | If true: throw to monkey 1 20 | If false: throw to monkey 3 21 | 22 | Monkey 3: 23 | Starting items: 74 24 | Operation: new = old + 3 25 | Test: divisible by 17 26 | If true: throw to monkey 0 27 | If false: throw to monkey 1 -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day01.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 1 - Calorie Counting 7 | * Problem Description: http://adventofcode.com/2022/day/1 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day1/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day01(input: String) { 13 | 14 | private val calories = parseInput(input) 15 | 16 | fun solvePart1(): Int = 17 | calories.first() 18 | 19 | fun solvePart2(): Int = 20 | calories.take(3).sum() 21 | 22 | private fun parseInput(input: String): List = 23 | input 24 | .trim() 25 | .split("\n\n") 26 | .map { it.lines().sumOf(String::toInt) } 27 | .sortedDescending() 28 | 29 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day06.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 6 - Tuning Trouble 7 | * Problem Description: http://adventofcode.com/2022/day/6 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day6/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day06(private val input: String) { 13 | 14 | fun solvePart1(): Int = 15 | input.findStartMarker(4) 16 | 17 | fun solvePart2(): Int = 18 | input.findStartMarker(14) 19 | 20 | private fun String.findStartMarker(startMarkerSize: Int): Int = 21 | withIndex() 22 | .windowed(startMarkerSize, 1) 23 | .first { window -> 24 | window.map { it.value }.toSet().size == startMarkerSize 25 | }.last().index + 1 26 | } 27 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day25.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 25 - Full of Hot Air 7 | * Problem Description: http://adventofcode.com/2022/day/24 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day24/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day25(private val input: List) { 13 | 14 | fun solvePart1(): String= 15 | input.sumOf { it.fromSnafu() }.toSnafu() 16 | 17 | private fun String.fromSnafu(): Long = 18 | fold(0) { carry, char -> 19 | (carry * 5) + when(char) { 20 | '-' -> -1 21 | '=' -> -2 22 | else -> char.digitToInt() 23 | } 24 | } 25 | 26 | private fun Long.toSnafu(): String = 27 | generateSequence(this) { (it + 2) / 5 } 28 | .takeWhile { it != 0L } 29 | .map { "012=-"[(it % 5).toInt()] } 30 | .joinToString("") 31 | .reversed() 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Resources.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import java.io.File 8 | import java.net.URI 9 | 10 | internal object Resources { 11 | fun resourceAsString(fileName: String, delimiter: String = ""): String = 12 | resourceAsListOfString(fileName).reduce { a, b -> "$a$delimiter$b" } 13 | 14 | fun resourceAsText(fileName: String): String = 15 | File(fileName.toURI()).readText() 16 | 17 | fun resourceAsListOfString(fileName: String): List = 18 | File(fileName.toURI()).readLines() 19 | 20 | fun resourceAsListOfInt(fileName: String): List = 21 | resourceAsListOfString(fileName).map { it.toInt() } 22 | 23 | fun resourceAsListOfLong(fileName: String): List = 24 | resourceAsListOfString(fileName).map { it.toLong() } 25 | 26 | private fun String.toURI(): URI = 27 | Resources.javaClass.classLoader.getResource(this)?.toURI() 28 | ?: throw IllegalArgumentException("Cannot find Resource: $this") 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Extensions.kt: -------------------------------------------------------------------------------- 1 | package com.ginsberg.advent2022 2 | 3 | 4 | // Modified version of takeWhile from the Kotlin Standard Library 5 | inline fun Iterable.takeUntil(predicate: (T) -> Boolean): List { 6 | val list = ArrayList() 7 | for (item in this) { 8 | list.add(item) 9 | if (predicate(item)) 10 | break 11 | } 12 | return list 13 | } 14 | 15 | fun Iterable.product(): Int = 16 | reduce { a, b -> a * b } 17 | 18 | fun List.reduce(): List = 19 | if (this.size <= 1) this 20 | else { 21 | val sorted = this.sortedBy { it.first } 22 | sorted.drop(1).fold(mutableListOf(sorted.first())) { reduced, range -> 23 | val lastRange = reduced.last() 24 | if (range.first <= lastRange.last) 25 | reduced[reduced.lastIndex] = (lastRange.first..maxOf(lastRange.last, range.last)) 26 | else 27 | reduced.add(range) 28 | reduced 29 | } 30 | } 31 | 32 | fun List.nth(n: Int): T = 33 | this[n % size] -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day22Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 22") 14 | class Day22Test { 15 | 16 | @Nested 17 | @DisplayName("Part 1") 18 | inner class Part1 { 19 | 20 | @Test 21 | fun `Actual answer`() { 22 | // Act 23 | val answer = Day22(resourceAsListOfString("day22.txt")).solvePart1() 24 | 25 | // Assert 26 | assertThat(answer).isEqualTo(162186) 27 | } 28 | } 29 | 30 | @Nested 31 | @DisplayName("Part 2") 32 | inner class Part2 { 33 | 34 | @Test 35 | fun `Actual answer`() { 36 | // Act 37 | val answer = Day22(resourceAsListOfString("day22.txt")).solvePart2() 38 | 39 | // Assert 40 | assertThat(answer).isEqualTo(55267) 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day03.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 3 - Rucksack Reorganization 7 | * Problem Description: http://adventofcode.com/2022/day/3 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day3/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day03(private val input: List) { 13 | 14 | fun solvePart1(): Int = 15 | input.sumOf { it.sharedItem().priority() } 16 | 17 | fun solvePart2(): Int = 18 | input.chunked(3).sumOf { it.sharedItem().priority() } 19 | 20 | private fun Char.priority(): Int = 21 | when (this) { 22 | in 'a'..'z' -> (this - 'a') + 1 23 | in 'A'..'Z' -> (this - 'A') + 27 24 | else -> throw IllegalArgumentException("Letter not in range: $this") 25 | } 26 | 27 | private fun String.sharedItem(): Char = 28 | listOf( 29 | substring(0..length / 2), 30 | substring(length / 2) 31 | ).sharedItem() 32 | 33 | private fun List.sharedItem(): Char = 34 | map { it.toSet() } 35 | .reduce { left, right -> left intersect right} 36 | .first() 37 | } 38 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day04.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 4 - Camp Cleanup 7 | * Problem Description: http://adventofcode.com/2022/day/4 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day4/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day04(input: List) { 13 | 14 | private val ranges: List> = input.map { it.asRanges() } 15 | 16 | fun solvePart1(): Int = 17 | ranges.count { it.first fullyOverlaps it.second || it.second fullyOverlaps it.first } 18 | 19 | fun solvePart2(): Int = 20 | ranges.count { it.first overlaps it.second } 21 | 22 | private infix fun IntRange.fullyOverlaps(other: IntRange): Boolean = 23 | first <= other.first && last >= other.last 24 | 25 | private infix fun IntRange.overlaps(other: IntRange): Boolean = 26 | first <= other.last && other.first <= last 27 | 28 | private fun String.asRanges(): Pair = 29 | substringBefore(",").asIntRange() to substringAfter(",").asIntRange() 30 | 31 | private fun String.asIntRange(): IntRange = 32 | substringBefore("-").toInt() .. substringAfter("-").toInt() 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day02.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 2 - Rock Paper Scissors 7 | * Problem Description: http://adventofcode.com/2022/day/2 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day2/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day02(private val input: List) { 13 | 14 | private val part1Scores: Map = 15 | mapOf( 16 | "A X" to 1 + 3, 17 | "A Y" to 2 + 6, 18 | "A Z" to 3 + 0, 19 | "B X" to 1 + 0, 20 | "B Y" to 2 + 3, 21 | "B Z" to 3 + 6, 22 | "C X" to 1 + 6, 23 | "C Y" to 2 + 0, 24 | "C Z" to 3 + 3, 25 | ) 26 | 27 | private val part2Scores: Map = 28 | mapOf( 29 | "A X" to 3 + 0, 30 | "A Y" to 1 + 3, 31 | "A Z" to 2 + 6, 32 | "B X" to 1 + 0, 33 | "B Y" to 2 + 3, 34 | "B Z" to 3 + 6, 35 | "C X" to 2 + 0, 36 | "C Y" to 3 + 3, 37 | "C Z" to 1 + 6, 38 | ) 39 | 40 | fun solvePart1(): Int = 41 | input.sumOf { part1Scores[it] ?: 0 } 42 | 43 | fun solvePart2(): Int = 44 | input.sumOf { part2Scores[it] ?: 0 } 45 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day25Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 25") 14 | class Day25Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 1=-0-2 19 | 12111 20 | 2=0= 21 | 21 22 | 2=01 23 | 111 24 | 20012 25 | 112 26 | 1=-1= 27 | 1-12 28 | 12 29 | 1= 30 | 122 31 | """.trimIndent().lines() 32 | 33 | @Nested 34 | @DisplayName("Part 1") 35 | inner class Part1 { 36 | 37 | @Test 38 | fun `Matches example`() { 39 | // Act 40 | val answer = Day25(input).solvePart1() 41 | 42 | // Assert 43 | assertThat(answer).isEqualTo("2=-1=0") 44 | } 45 | 46 | @Test 47 | fun `Actual answer`() { 48 | // Act 49 | val answer = Day25(resourceAsListOfString("day25.txt")).solvePart1() 50 | 51 | // Assert 52 | assertThat(answer).isEqualTo("2-02===-21---2002==0") 53 | } 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /src/main/resources/day11.txt: -------------------------------------------------------------------------------- 1 | Monkey 0: 2 | Starting items: 54, 53 3 | Operation: new = old * 3 4 | Test: divisible by 2 5 | If true: throw to monkey 2 6 | If false: throw to monkey 6 7 | 8 | Monkey 1: 9 | Starting items: 95, 88, 75, 81, 91, 67, 65, 84 10 | Operation: new = old * 11 11 | Test: divisible by 7 12 | If true: throw to monkey 3 13 | If false: throw to monkey 4 14 | 15 | Monkey 2: 16 | Starting items: 76, 81, 50, 93, 96, 81, 83 17 | Operation: new = old + 6 18 | Test: divisible by 3 19 | If true: throw to monkey 5 20 | If false: throw to monkey 1 21 | 22 | Monkey 3: 23 | Starting items: 83, 85, 85, 63 24 | Operation: new = old + 4 25 | Test: divisible by 11 26 | If true: throw to monkey 7 27 | If false: throw to monkey 4 28 | 29 | Monkey 4: 30 | Starting items: 85, 52, 64 31 | Operation: new = old + 8 32 | Test: divisible by 17 33 | If true: throw to monkey 0 34 | If false: throw to monkey 7 35 | 36 | Monkey 5: 37 | Starting items: 57 38 | Operation: new = old + 2 39 | Test: divisible by 5 40 | If true: throw to monkey 1 41 | If false: throw to monkey 3 42 | 43 | Monkey 6: 44 | Starting items: 60, 95, 76, 66, 91 45 | Operation: new = old * old 46 | Test: divisible by 13 47 | If true: throw to monkey 2 48 | If false: throw to monkey 5 49 | 50 | Monkey 7: 51 | Starting items: 65, 84, 76, 72, 79, 65 52 | Operation: new = old + 5 53 | Test: divisible by 19 54 | If true: throw to monkey 6 55 | If false: throw to monkey 0 56 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day20.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 20 - Grove Positioning System 7 | * Problem Description: http://adventofcode.com/2022/day/20 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day20/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day20(private val input: List) { 13 | 14 | private data class MappedNumber(val originalIndex: Int, val value: Long) 15 | 16 | fun solvePart1(): Long { 17 | val theList = parseInput() 18 | theList.decrypt() 19 | return theList.groveCoordinates() 20 | } 21 | 22 | fun solvePart2(): Long { 23 | val theList = parseInput(811_589_153) 24 | repeat(10) { 25 | theList.decrypt() 26 | } 27 | return theList.groveCoordinates() 28 | } 29 | 30 | private fun parseInput(decryptionKey: Long = 1L): MutableList = 31 | input.mapIndexed { index, value -> MappedNumber(index, decryptionKey * value.toLong()) }.toMutableList() 32 | 33 | private fun List.groveCoordinates(): Long { 34 | val zero = indexOfFirst { it.value == 0L } 35 | return listOf(1000, 2000, 3000).sumOf { this[(zero + it) % size].value } 36 | } 37 | 38 | private fun MutableList.decrypt() { 39 | indices.forEach { originalIndex -> 40 | val index = indexOfFirst { it.originalIndex == originalIndex } 41 | val toBeMoved = removeAt(index) 42 | add((index + toBeMoved.value).mod(size), toBeMoved) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Point2D.kt: -------------------------------------------------------------------------------- 1 | package com.ginsberg.advent2022 2 | 3 | import kotlin.math.absoluteValue 4 | import kotlin.math.sign 5 | 6 | data class Point2D(val x: Int = 0, val y: Int = 0) { 7 | fun cardinalNeighbors(): Set = 8 | setOf( 9 | copy(x = x - 1), 10 | copy(x = x + 1), 11 | copy(y = y - 1), 12 | copy(y = y + 1) 13 | ) 14 | 15 | fun neighbors(): Set = 16 | setOf( 17 | Point2D(x - 1, y - 1), 18 | Point2D(x, y - 1), 19 | Point2D(x + 1, y - 1), 20 | Point2D(x - 1, y), 21 | Point2D(x + 1, y), 22 | Point2D(x - 1, y + 1), 23 | Point2D(x, y + 1), 24 | Point2D(x + 1, y + 1) 25 | ) 26 | 27 | operator fun plus(other: Point2D): Point2D = 28 | Point2D(this.x + other.x, this.y + other.y) 29 | 30 | operator fun minus(other: Point2D): Point2D = 31 | Point2D(this.x - other.x, this.y - other.y) 32 | 33 | fun distanceTo(other: Point2D): Int = 34 | (x - other.x).absoluteValue + (y - other.y).absoluteValue 35 | 36 | fun lineTo(other: Point2D): List { 37 | val xDelta = (other.x - x).sign 38 | val yDelta = (other.y - y).sign 39 | val steps = maxOf((x - other.x).absoluteValue, (y - other.y).absoluteValue) 40 | return (1..steps).scan(this) { last, _ -> Point2D(last.x + xDelta, last.y + yDelta) } 41 | } 42 | 43 | companion object { 44 | fun of(input: String): Point2D = 45 | input.split(",").let { (x, y) -> Point2D(x.toInt(), y.toInt()) } 46 | } 47 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day10.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 10 - Cathode-Ray Tube 7 | * Problem Description: http://adventofcode.com/2022/day/10 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day10/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import kotlin.math.absoluteValue 13 | 14 | class Day10(input: List) { 15 | 16 | private val signals: List = parseInput(input).runningReduce(Int::plus) 17 | 18 | fun solvePart1(): Int = 19 | signals.sampleSignals().sum() 20 | 21 | fun solvePart2(): Unit = 22 | signals.screen().print() 23 | 24 | private fun List.sampleSignals(): List = 25 | (60 .. size step 40).map {cycle -> 26 | cycle * this[cycle - 1] 27 | } + this[19] * 20 28 | 29 | private fun List.screen(): List = 30 | this.mapIndexed { pixel, signal -> 31 | (signal-(pixel%40)).absoluteValue <= 1 32 | } 33 | 34 | private fun List.print() { 35 | this.windowed(40, 40, false).forEach { row -> 36 | row.forEach { pixel -> 37 | print(if(pixel) '#' else ' ') 38 | } 39 | println() 40 | } 41 | } 42 | 43 | private fun parseInput(input: List): List = 44 | buildList { 45 | add(1) 46 | input.forEach { line -> 47 | add(0) 48 | if (line.startsWith("addx")) { 49 | add(line.substringAfter(" ").toInt()) 50 | } 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day18.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 18 - Boiling Boulders 7 | * Problem Description: http://adventofcode.com/2022/day/18 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day18/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day18(input: List) { 13 | 14 | private val points: Set = input.map { Point3D.of(it) }.toSet() 15 | 16 | fun solvePart1(): Int = 17 | points.sumOf { point -> 18 | 6 - point.cardinalNeighbors().count { neighbor -> neighbor in points } 19 | } 20 | 21 | fun solvePart2(): Int { 22 | val xRange = points.rangeOf { it.x } 23 | val yRange = points.rangeOf { it.y } 24 | val zRange = points.rangeOf { it.z } 25 | 26 | val queue = ArrayDeque().apply { add(Point3D(xRange.first, yRange.first, zRange.first)) } 27 | val seen = mutableSetOf() 28 | var sidesFound = 0 29 | queue.forEach { lookNext -> 30 | if (lookNext !in seen) { 31 | lookNext.cardinalNeighbors() 32 | .filter { it.x in xRange && it.y in yRange && it.z in zRange } 33 | .forEach { neighbor -> 34 | seen += lookNext 35 | if (neighbor in points) sidesFound++ 36 | else queue.add(neighbor) 37 | } 38 | } 39 | } 40 | return sidesFound 41 | } 42 | 43 | private fun Set.rangeOf(function: (Point3D) -> Int): IntRange = 44 | this.minOf(function) - 1..this.maxOf(function) + 1 45 | } 46 | -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day06Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsString 8 | import org.assertj.core.api.Assertions.assertThat 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 6") 14 | class Day06Test { 15 | 16 | // Arrange 17 | private val input = "zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw" 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | @Test 23 | fun `Matches example`() { 24 | // Act 25 | val answer = Day06(input).solvePart1() 26 | 27 | // Assert 28 | assertThat(answer).isEqualTo(11) 29 | } 30 | 31 | @Test 32 | fun `Actual answer`() { 33 | // Act 34 | val answer = Day06(resourceAsString("day06.txt")).solvePart1() 35 | 36 | // Assert 37 | assertThat(answer).isEqualTo(1623) 38 | } 39 | } 40 | 41 | @Nested 42 | @DisplayName("Part 2") 43 | inner class Part2 { 44 | @Test 45 | fun `Matches example`() { 46 | // Act 47 | val answer = Day06("mjqjpqmgbljsphdztnvjfqwrcgsmlb").solvePart2() 48 | 49 | // Assert 50 | assertThat(answer).isEqualTo(19) 51 | } 52 | 53 | @Test 54 | fun `Actual answer`() { 55 | // Act 56 | val answer = Day06(resourceAsString("day06.txt")).solvePart2() 57 | 58 | // Assert 59 | assertThat(answer).isEqualTo(3774) 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day23Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 23") 14 | class Day23Test { 15 | 16 | // Arrange 17 | private val input = resourceAsListOfString("day23_sample.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // Act 26 | val answer = Day23(input).solvePart1() 27 | 28 | // Assert 29 | assertThat(answer).isEqualTo(110) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // Act 35 | val answer = Day23(resourceAsListOfString("day23.txt")).solvePart1() 36 | 37 | // Assert 38 | assertThat(answer).isEqualTo(4247) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // Act 49 | val answer = Day23(input).solvePart2() 50 | 51 | // Assert 52 | assertThat(answer).isEqualTo(20) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // Act 58 | val answer = Day23(resourceAsListOfString("day23.txt")).solvePart2() 59 | 60 | // Assert 61 | assertThat(answer).isEqualTo(1049) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day13Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 13") 14 | class Day13Test { 15 | 16 | // Arrange 17 | private val input = resourceAsListOfString("day13_sample.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // Act 26 | val answer = Day13(input).solvePart1() 27 | 28 | // Assert 29 | assertThat(answer).isEqualTo(13) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // Act 35 | val answer = Day13(resourceAsListOfString("day13.txt")).solvePart1() 36 | 37 | // Assert 38 | assertThat(answer).isEqualTo(4_734) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // Act 49 | val answer = Day13(input).solvePart2() 50 | 51 | // Assert 52 | assertThat(answer).isEqualTo(140) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // Act 58 | val answer = Day13(resourceAsListOfString("day13.txt")).solvePart2() 59 | 60 | // Assert 61 | assertThat(answer).isEqualTo(21_836) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day07Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 7") 14 | class Day07Test { 15 | 16 | // Arrange 17 | private val input = resourceAsListOfString("day07_sample.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | @Test 23 | fun `Matches example`() { 24 | // Act 25 | val answer = Day07(input).solvePart1() 26 | 27 | // Assert 28 | assertThat(answer).isEqualTo(95437) 29 | } 30 | 31 | @Test 32 | fun `Actual answer`() { 33 | // Act 34 | val answer = Day07(resourceAsListOfString("day07.txt")).solvePart1() 35 | 36 | // Assert 37 | assertThat(answer).isEqualTo(1_118_405) 38 | } 39 | } 40 | 41 | @Nested 42 | @DisplayName("Part 2") 43 | inner class Part2 { 44 | @Test 45 | fun `Matches example`() { 46 | // Act 47 | val answer = Day07(input).solvePart2() 48 | 49 | // Assert 50 | assertThat(answer).isEqualTo(24_933_642) 51 | } 52 | 53 | @Test 54 | fun `Actual answer`() { 55 | // Act 56 | val answer = Day07(resourceAsListOfString("day07.txt")).solvePart2() 57 | 58 | // Assert 59 | assertThat(answer).isEqualTo(12_545_514) 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day17Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsString 8 | import org.assertj.core.api.Assertions.assertThat 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 17") 14 | class Day17Test { 15 | 16 | // Arrange 17 | private val input = ">>><<><>><<<>><>>><<<>>><<<><<<>><>><<>>" 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // Act 26 | val answer = Day17(input).solvePart1() 27 | 28 | // Assert 29 | assertThat(answer).isEqualTo(3068) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // Act 35 | val answer = Day17(resourceAsString("day17.txt")).solvePart1() 36 | 37 | // Assert 38 | assertThat(answer).isEqualTo(3151) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // Act 49 | val answer = Day17(input).solvePart2() 50 | 51 | // Assert 52 | assertThat(answer).isEqualTo(1_514_285_714_288L) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // Act 58 | val answer = Day17(resourceAsString("day17.txt")).solvePart2() 59 | 60 | // Assert 61 | assertThat(answer).isEqualTo(1560919540245L) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day10Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 10") 14 | class Day10Test { 15 | 16 | @Nested 17 | @DisplayName("Part 1") 18 | inner class Part1 { 19 | 20 | @Test 21 | fun `Matches example`() { 22 | // Act 23 | val answer = Day10(resourceAsListOfString("day10_sample.txt")).solvePart1() 24 | 25 | // Assert 26 | assertThat(answer).isEqualTo(13140) 27 | } 28 | 29 | @Test 30 | fun `Actual answer`() { 31 | // Act 32 | val answer = Day10(resourceAsListOfString("day10.txt")).solvePart1() 33 | 34 | // Assert 35 | assertThat(answer).isEqualTo(15_020) 36 | } 37 | } 38 | 39 | @Nested 40 | @DisplayName("Part 2") 41 | inner class Part2 { 42 | 43 | // Yeah, yeah, these don't _actually_ test anything because the answers are printed as 44 | // a side effect. However, I still need something to run my solution as I develop it 45 | // so here we are. 46 | 47 | @Test 48 | fun `Matches example`() { 49 | // Act 50 | Day10(resourceAsListOfString("day10_sample.txt")).solvePart2() 51 | } 52 | 53 | @Test 54 | fun `Actual answer`() { 55 | // Act 56 | Day10(resourceAsListOfString("day10.txt")).solvePart2() 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day11Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 11") 14 | class Day11Test { 15 | 16 | // Arrange 17 | private val input = resourceAsListOfString("day11_sample.txt") 18 | 19 | @Nested 20 | @DisplayName("Part 1") 21 | inner class Part1 { 22 | 23 | @Test 24 | fun `Matches example`() { 25 | // Act 26 | val answer = Day11(input).solvePart1() 27 | 28 | // Assert 29 | assertThat(answer).isEqualTo(10_605L) 30 | } 31 | 32 | @Test 33 | fun `Actual answer`() { 34 | // Act 35 | val answer = Day11(resourceAsListOfString("day11.txt")).solvePart1() 36 | 37 | // Assert 38 | assertThat(answer).isEqualTo(111_210) 39 | } 40 | } 41 | 42 | @Nested 43 | @DisplayName("Part 2") 44 | inner class Part2 { 45 | 46 | @Test 47 | fun `Matches example`() { 48 | // Act 49 | val answer = Day11(input).solvePart2() 50 | 51 | // Assert 52 | assertThat(answer).isEqualTo(2_713_310_158) 53 | } 54 | 55 | @Test 56 | fun `Actual answer`() { 57 | // Act 58 | val answer = Day11(resourceAsListOfString("day11.txt")).solvePart2() 59 | 60 | // Assert 61 | assertThat(answer).isEqualTo(15_447_387_620) 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day02Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 2") 14 | class Day02Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | A Y 19 | B X 20 | C Z 21 | """.trimIndent() 22 | .lines() 23 | 24 | @Nested 25 | @DisplayName("Part 1") 26 | inner class Part1 { 27 | @Test 28 | fun `Matches example`() { 29 | // Act 30 | val answer = Day02(input).solvePart1() 31 | 32 | // Assert 33 | assertThat(answer).isEqualTo(15) 34 | } 35 | 36 | @Test 37 | fun `Actual answer`() { 38 | // Act 39 | val answer = Day02(resourceAsListOfString("day02.txt")).solvePart1() 40 | 41 | // Assert 42 | assertThat(answer).isEqualTo(15_572) 43 | } 44 | } 45 | 46 | @Nested 47 | @DisplayName("Part 2") 48 | inner class Part2 { 49 | @Test 50 | fun `Matches example`() { 51 | // Act 52 | val answer = Day02(input).solvePart2() 53 | 54 | // Assert 55 | assertThat(answer).isEqualTo(12) 56 | } 57 | 58 | @Test 59 | fun `Actual answer`() { 60 | // Act 61 | val answer = Day02(resourceAsListOfString("day02.txt")).solvePart2() 62 | 63 | // Assert 64 | assertThat(answer).isEqualTo(16_098) 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/resources/day10.txt: -------------------------------------------------------------------------------- 1 | addx 1 2 | addx 4 3 | addx 1 4 | noop 5 | addx 4 6 | addx 3 7 | addx -2 8 | addx 5 9 | addx -1 10 | noop 11 | addx 3 12 | noop 13 | addx 7 14 | addx -1 15 | addx 1 16 | noop 17 | addx 6 18 | addx -1 19 | addx 5 20 | noop 21 | noop 22 | noop 23 | addx -37 24 | addx 7 25 | noop 26 | noop 27 | noop 28 | addx 5 29 | noop 30 | noop 31 | noop 32 | addx 9 33 | addx -8 34 | addx 2 35 | addx 5 36 | addx 2 37 | addx 5 38 | noop 39 | noop 40 | addx -2 41 | noop 42 | addx 3 43 | addx 2 44 | noop 45 | addx 3 46 | addx 2 47 | noop 48 | addx 3 49 | addx -36 50 | noop 51 | addx 26 52 | addx -21 53 | noop 54 | noop 55 | noop 56 | addx 3 57 | addx 5 58 | addx 2 59 | addx -4 60 | noop 61 | addx 9 62 | addx 5 63 | noop 64 | noop 65 | noop 66 | addx -6 67 | addx 7 68 | addx 2 69 | noop 70 | addx 3 71 | addx 2 72 | addx 5 73 | addx -39 74 | addx 34 75 | addx 5 76 | addx -35 77 | noop 78 | addx 26 79 | addx -21 80 | addx 5 81 | addx 2 82 | addx 2 83 | noop 84 | addx 3 85 | addx 12 86 | addx -7 87 | noop 88 | noop 89 | noop 90 | noop 91 | noop 92 | addx 5 93 | addx 2 94 | addx 3 95 | noop 96 | noop 97 | noop 98 | noop 99 | addx -37 100 | addx 21 101 | addx -14 102 | addx 16 103 | addx -11 104 | noop 105 | addx -2 106 | addx 3 107 | addx 2 108 | addx 5 109 | addx 2 110 | addx -15 111 | addx 6 112 | addx 12 113 | addx -2 114 | addx 9 115 | addx -6 116 | addx 7 117 | addx 2 118 | noop 119 | noop 120 | noop 121 | addx -33 122 | addx 1 123 | noop 124 | addx 2 125 | addx 13 126 | addx 15 127 | addx -21 128 | addx 21 129 | addx -15 130 | noop 131 | noop 132 | addx 4 133 | addx 1 134 | noop 135 | addx 4 136 | addx 8 137 | addx 6 138 | addx -11 139 | addx 5 140 | addx 2 141 | addx -35 142 | addx -1 143 | noop 144 | noop 145 | -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day08Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 8") 14 | class Day08Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 30373 19 | 25512 20 | 65332 21 | 33549 22 | 35390 23 | """.trimIndent().lines() 24 | 25 | @Nested 26 | @DisplayName("Part 1") 27 | inner class Part1 { 28 | @Test 29 | fun `Matches example`() { 30 | // Act 31 | val answer = Day08(input).solvePart1() 32 | 33 | // Assert 34 | assertThat(answer).isEqualTo(21) 35 | } 36 | 37 | @Test 38 | fun `Actual answer`() { 39 | // Act 40 | val answer = Day08(resourceAsListOfString("day08.txt")).solvePart1() 41 | 42 | // Assert 43 | assertThat(answer).isEqualTo(1_647) 44 | } 45 | } 46 | 47 | @Nested 48 | @DisplayName("Part 2") 49 | inner class Part2 { 50 | @Test 51 | fun `Matches example`() { 52 | // Act 53 | val answer = Day08(input).solvePart2() 54 | 55 | // Assert 56 | assertThat(answer).isEqualTo(8) 57 | } 58 | 59 | @Test 60 | fun `Actual answer`() { 61 | // Act 62 | val answer = Day08(resourceAsListOfString("day08.txt")).solvePart2() 63 | 64 | // Assert 65 | assertThat(answer).isEqualTo(392_080) 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day14Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 14") 14 | class Day14Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 498,4 -> 498,6 -> 496,6 19 | 503,4 -> 502,4 -> 502,9 -> 494,9 20 | """.trimIndent().lines() 21 | 22 | @Nested 23 | @DisplayName("Part 1") 24 | inner class Part1 { 25 | 26 | @Test 27 | fun `Matches example`() { 28 | // Act 29 | val answer = Day14(input).solvePart1() 30 | 31 | // Assert 32 | assertThat(answer).isEqualTo(24) 33 | } 34 | 35 | @Test 36 | fun `Actual answer`() { 37 | // Act 38 | val answer = Day14(resourceAsListOfString("day14.txt")).solvePart1() 39 | 40 | // Assert 41 | assertThat(answer).isEqualTo(795) 42 | } 43 | } 44 | 45 | @Nested 46 | @DisplayName("Part 2") 47 | inner class Part2 { 48 | 49 | @Test 50 | fun `Matches example`() { 51 | // Act 52 | val answer = Day14(input).solvePart2() 53 | 54 | // Assert 55 | assertThat(answer).isEqualTo(93) 56 | } 57 | 58 | @Test 59 | fun `Actual answer`() { 60 | // Act 61 | val answer = Day14(resourceAsListOfString("day14.txt")).solvePart2() 62 | 63 | // Assert 64 | assertThat(answer).isEqualTo(30_214) 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/test/resources/day10_sample.txt: -------------------------------------------------------------------------------- 1 | addx 15 2 | addx -11 3 | addx 6 4 | addx -3 5 | addx 5 6 | addx -1 7 | addx -8 8 | addx 13 9 | addx 4 10 | noop 11 | addx -1 12 | addx 5 13 | addx -1 14 | addx 5 15 | addx -1 16 | addx 5 17 | addx -1 18 | addx 5 19 | addx -1 20 | addx -35 21 | addx 1 22 | addx 24 23 | addx -19 24 | addx 1 25 | addx 16 26 | addx -11 27 | noop 28 | noop 29 | addx 21 30 | addx -15 31 | noop 32 | noop 33 | addx -3 34 | addx 9 35 | addx 1 36 | addx -3 37 | addx 8 38 | addx 1 39 | addx 5 40 | noop 41 | noop 42 | noop 43 | noop 44 | noop 45 | addx -36 46 | noop 47 | addx 1 48 | addx 7 49 | noop 50 | noop 51 | noop 52 | addx 2 53 | addx 6 54 | noop 55 | noop 56 | noop 57 | noop 58 | noop 59 | addx 1 60 | noop 61 | noop 62 | addx 7 63 | addx 1 64 | noop 65 | addx -13 66 | addx 13 67 | addx 7 68 | noop 69 | addx 1 70 | addx -33 71 | noop 72 | noop 73 | noop 74 | addx 2 75 | noop 76 | noop 77 | noop 78 | addx 8 79 | noop 80 | addx -1 81 | addx 2 82 | addx 1 83 | noop 84 | addx 17 85 | addx -9 86 | addx 1 87 | addx 1 88 | addx -3 89 | addx 11 90 | noop 91 | noop 92 | addx 1 93 | noop 94 | addx 1 95 | noop 96 | noop 97 | addx -13 98 | addx -19 99 | addx 1 100 | addx 3 101 | addx 26 102 | addx -30 103 | addx 12 104 | addx -1 105 | addx 3 106 | addx 1 107 | noop 108 | noop 109 | noop 110 | addx -9 111 | addx 18 112 | addx 1 113 | addx 2 114 | noop 115 | noop 116 | addx 9 117 | noop 118 | noop 119 | noop 120 | addx -1 121 | addx 2 122 | addx -37 123 | addx 1 124 | addx 3 125 | noop 126 | addx 15 127 | addx -21 128 | addx 22 129 | addx -6 130 | addx 1 131 | noop 132 | addx 2 133 | addx 1 134 | noop 135 | addx -10 136 | noop 137 | noop 138 | addx 20 139 | addx 1 140 | addx 2 141 | addx 2 142 | addx -6 143 | addx -11 144 | noop 145 | noop 146 | noop -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day12Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 12") 14 | class Day12Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | Sabqponm 19 | abcryxxl 20 | accszExk 21 | acctuvwj 22 | abdefghi 23 | """.trimIndent().lines() 24 | 25 | @Nested 26 | @DisplayName("Part 1") 27 | inner class Part1 { 28 | 29 | @Test 30 | fun `Matches example`() { 31 | // Act 32 | val answer = Day12(input).solvePart1() 33 | 34 | // Assert 35 | assertThat(answer).isEqualTo(31) 36 | } 37 | 38 | @Test 39 | fun `Actual answer`() { 40 | // Act 41 | val answer = Day12(resourceAsListOfString("day12.txt")).solvePart1() 42 | 43 | // Assert 44 | assertThat(answer).isEqualTo(408) 45 | } 46 | } 47 | 48 | @Nested 49 | @DisplayName("Part 2") 50 | inner class Part2 { 51 | 52 | @Test 53 | fun `Matches example`() { 54 | // Act 55 | val answer = Day12(input).solvePart2() 56 | 57 | // Assert 58 | assertThat(answer).isEqualTo(29) 59 | } 60 | 61 | @Test 62 | fun `Actual answer`() { 63 | // Act 64 | val answer = Day12(resourceAsListOfString("day12.txt")).solvePart2() 65 | 66 | // Assert 67 | assertThat(answer).isEqualTo(399) 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day04Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 4") 14 | class Day04Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 2-4,6-8 19 | 2-3,4-5 20 | 5-7,7-9 21 | 2-8,3-7 22 | 6-6,4-6 23 | 2-6,4-8 24 | """.trimIndent() 25 | .lines() 26 | 27 | @Nested 28 | @DisplayName("Part 1") 29 | inner class Part1 { 30 | @Test 31 | fun `Matches example`() { 32 | // Act 33 | val answer = Day04(input).solvePart1() 34 | 35 | // Assert 36 | assertThat(answer).isEqualTo(2) 37 | } 38 | 39 | @Test 40 | fun `Actual answer`() { 41 | // Act 42 | val answer = Day04(resourceAsListOfString("day04.txt")).solvePart1() 43 | 44 | // Assert 45 | assertThat(answer).isEqualTo(456) 46 | } 47 | } 48 | 49 | @Nested 50 | @DisplayName("Part 2") 51 | inner class Part2 { 52 | @Test 53 | fun `Matches example`() { 54 | // Act 55 | val answer = Day04(input).solvePart2() 56 | 57 | // Assert 58 | assertThat(answer).isEqualTo(4) 59 | } 60 | 61 | @Test 62 | fun `Actual answer`() { 63 | // Act 64 | val answer = Day04(resourceAsListOfString("day04.txt")).solvePart2() 65 | 66 | // Assert 67 | assertThat(answer).isEqualTo(808) 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day20Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 20") 14 | class Day20Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 1 19 | 2 20 | -3 21 | 3 22 | -2 23 | 0 24 | 4 25 | """.trimIndent().lines() 26 | 27 | @Nested 28 | @DisplayName("Part 1") 29 | inner class Part1 { 30 | 31 | @Test 32 | fun `Matches example`() { 33 | // Act 34 | val answer = Day20(input).solvePart1() 35 | 36 | // Assert 37 | assertThat(answer).isEqualTo(3L) 38 | } 39 | 40 | @Test 41 | fun `Actual answer`() { 42 | // Act 43 | val answer = Day20(resourceAsListOfString("day20.txt")).solvePart1() 44 | 45 | // Assert 46 | assertThat(answer).isEqualTo(8764L) 47 | } 48 | } 49 | 50 | @Nested 51 | @DisplayName("Part 2") 52 | inner class Part2 { 53 | 54 | @Test 55 | fun `Matches example`() { 56 | // Act 57 | val answer = Day20(input).solvePart2() 58 | 59 | // Assert 60 | assertThat(answer).isEqualTo(1623178306L) 61 | } 62 | 63 | @Test 64 | fun `Actual answer`() { 65 | // Act 66 | val answer = Day20(resourceAsListOfString("day20.txt")).solvePart2() 67 | 68 | // Assert 69 | assertThat(answer).isEqualTo(535648840980L) 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day24Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 24") 14 | class Day24Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | #.###### 19 | #>>.<^<# 20 | #.<..<<# 21 | #>v.><># 22 | #<^v^^># 23 | ######.# 24 | """.trimIndent().lines() 25 | 26 | @Nested 27 | @DisplayName("Part 1") 28 | inner class Part1 { 29 | 30 | @Test 31 | fun `Matches example`() { 32 | // Act 33 | val answer = Day24(input).solvePart1() 34 | 35 | // Assert 36 | assertThat(answer).isEqualTo(18) 37 | } 38 | 39 | @Test 40 | fun `Actual answer`() { 41 | // Act 42 | val answer = Day24(resourceAsListOfString("day24.txt")).solvePart1() 43 | 44 | // Assert 45 | assertThat(answer).isEqualTo(245) 46 | } 47 | } 48 | 49 | @Nested 50 | @DisplayName("Part 2") 51 | inner class Part2 { 52 | 53 | @Test 54 | fun `Matches example`() { 55 | // Act 56 | val answer = Day24(input).solvePart2() 57 | 58 | // Assert 59 | assertThat(answer).isEqualTo(54) 60 | } 61 | 62 | @Test 63 | fun `Actual answer`() { 64 | // Act 65 | val answer = Day24(resourceAsListOfString("day24.txt")).solvePart2() 66 | 67 | // Assert 68 | assertThat(answer).isEqualTo(798) 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day08.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 8 - Treetop Tree House 7 | * Problem Description: http://adventofcode.com/2022/day/8 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day8/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day08(input: List) { 13 | 14 | private val grid: Array = parseInput(input) 15 | private val gridHeight: Int = grid.size 16 | private val gridWidth: Int = grid.first().size 17 | 18 | fun solvePart1(): Int = (1 until gridHeight - 1).sumOf { y -> 19 | (1 until gridWidth - 1).count { x -> 20 | grid.isVisible(x, y) 21 | } 22 | } + (2 * gridHeight) + (2 * gridWidth) - 4 23 | 24 | fun solvePart2(): Int = (1 until gridHeight - 1).maxOf { y -> 25 | (1 until gridWidth - 1).maxOf { x -> 26 | grid.scoreAt(x, y) 27 | } 28 | } 29 | 30 | private fun Array.isVisible(x: Int, y: Int): Boolean = 31 | viewFrom(x, y).any { direction -> 32 | direction.all { it < this[y][x] } 33 | } 34 | 35 | private fun Array.scoreAt(x: Int, y: Int): Int = 36 | viewFrom(x, y).map { direction -> 37 | direction.takeUntil { it >= this[y][x] }.count() 38 | }.product() 39 | 40 | private fun Array.viewFrom(x: Int, y: Int): List> = 41 | listOf( 42 | (y - 1 downTo 0).map { this[it][x] }, // Up 43 | (y + 1 until gridHeight).map { this[it][x] }, // Down 44 | this[y].take(x).asReversed(), // Left 45 | this[y].drop(x + 1) // Right 46 | ) 47 | 48 | private fun parseInput(input: List): Array = input.map { row -> 49 | row.map(Char::digitToInt).toIntArray() 50 | }.toTypedArray() 51 | } 52 | -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day01Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsText 8 | import org.assertj.core.api.Assertions.assertThat 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 1") 14 | class Day01Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 1000 19 | 2000 20 | 3000 21 | 22 | 4000 23 | 24 | 5000 25 | 6000 26 | 27 | 7000 28 | 8000 29 | 9000 30 | 31 | 10000 32 | 33 | """.trimIndent() 34 | 35 | @Nested 36 | @DisplayName("Part 1") 37 | inner class Part1 { 38 | @Test 39 | fun `Matches example`() { 40 | // Act 41 | val answer = Day01(input).solvePart1() 42 | 43 | // Assert 44 | assertThat(answer).isEqualTo(24_000) 45 | } 46 | 47 | @Test 48 | fun `Actual answer`() { 49 | // Act 50 | val answer = Day01(resourceAsText("day01.txt")).solvePart1() 51 | 52 | // Assert 53 | assertThat(answer).isEqualTo(68_923) 54 | } 55 | } 56 | 57 | @Nested 58 | @DisplayName("Part 2") 59 | inner class Part2 { 60 | @Test 61 | fun `Matches example`() { 62 | // Act 63 | val answer = Day01(input).solvePart2() 64 | 65 | // Assert 66 | assertThat(answer).isEqualTo(45_000) 67 | } 68 | 69 | @Test 70 | fun `Actual answer`() { 71 | // Act 72 | val answer = Day01(resourceAsText("day01.txt")).solvePart2() 73 | 74 | // Assert 75 | assertThat(answer).isEqualTo(200_044) 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day03Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 3") 14 | class Day03Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | vJrwpWtwJgWrhcsFMMfFFhFp 19 | jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL 20 | PmmdzqPrVvPwwTWBwg 21 | wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn 22 | ttgJtRGJQctTZtZT 23 | CrZsJsPPZsGzwwsLwLmpwMDw 24 | """.trimIndent() 25 | .lines() 26 | 27 | @Nested 28 | @DisplayName("Part 1") 29 | inner class Part1 { 30 | @Test 31 | fun `Matches example`() { 32 | // Act 33 | val answer = Day03(input).solvePart1() 34 | 35 | // Assert 36 | assertThat(answer).isEqualTo(157) 37 | } 38 | 39 | @Test 40 | fun `Actual answer`() { 41 | // Act 42 | val answer = Day03(resourceAsListOfString("day03.txt")).solvePart1() 43 | 44 | // Assert 45 | assertThat(answer).isEqualTo(7_597) 46 | } 47 | } 48 | 49 | @Nested 50 | @DisplayName("Part 2") 51 | inner class Part2 { 52 | @Test 53 | fun `Matches example`() { 54 | // Act 55 | val answer = Day03(input).solvePart2() 56 | 57 | // Assert 58 | assertThat(answer).isEqualTo(70) 59 | } 60 | 61 | @Test 62 | fun `Actual answer`() { 63 | // Act 64 | val answer = Day03(resourceAsListOfString("day03.txt")).solvePart2() 65 | 66 | // Assert 67 | assertThat(answer).isEqualTo(2_607) 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day18Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 18") 14 | class Day18Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | 2,2,2 19 | 1,2,2 20 | 3,2,2 21 | 2,1,2 22 | 2,3,2 23 | 2,2,1 24 | 2,2,3 25 | 2,2,4 26 | 2,2,6 27 | 1,2,5 28 | 3,2,5 29 | 2,1,5 30 | 2,3,5 31 | """.trimIndent().lines() 32 | 33 | @Nested 34 | @DisplayName("Part 1") 35 | inner class Part1 { 36 | 37 | @Test 38 | fun `Matches example`() { 39 | // Act 40 | val answer = Day18(input).solvePart1() 41 | 42 | // Assert 43 | assertThat(answer).isEqualTo(64) 44 | } 45 | 46 | @Test 47 | fun `Actual answer`() { 48 | // Act 49 | val answer = Day18(resourceAsListOfString("day18.txt")).solvePart1() 50 | 51 | // Assert 52 | assertThat(answer).isEqualTo(4_418) 53 | } 54 | } 55 | 56 | @Nested 57 | @DisplayName("Part 2") 58 | inner class Part2 { 59 | 60 | @Test 61 | fun `Matches example`() { 62 | // Act 63 | val answer = Day18(input).solvePart2() 64 | 65 | // Assert 66 | assertThat(answer).isEqualTo(58) 67 | } 68 | 69 | @Test 70 | fun `Actual answer`() { 71 | // Act 72 | val answer = Day18(resourceAsListOfString("day18.txt")).solvePart2() 73 | 74 | // Assert 75 | assertThat(answer).isEqualTo(2486) 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day05Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 5") 14 | class Day05Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | [D] 19 | [N] [C] 20 | [Z] [M] [P] 21 | 1 2 3 22 | 23 | move 1 from 2 to 1 24 | move 3 from 1 to 3 25 | move 2 from 2 to 1 26 | move 1 from 1 to 2 27 | """.trimIndent() 28 | .lines() 29 | 30 | @Nested 31 | @DisplayName("Part 1") 32 | inner class Part1 { 33 | @Test 34 | fun `Matches example`() { 35 | // Act 36 | val answer = Day05(input).solvePart1() 37 | 38 | // Assert 39 | assertThat(answer).isEqualTo("CMZ") 40 | } 41 | 42 | @Test 43 | fun `Actual answer`() { 44 | // Act 45 | val answer = Day05(resourceAsListOfString("day05.txt")).solvePart1() 46 | 47 | // Assert 48 | assertThat(answer).isEqualTo("CWMTGHBDW") 49 | } 50 | } 51 | 52 | @Nested 53 | @DisplayName("Part 2") 54 | inner class Part2 { 55 | @Test 56 | fun `Matches example`() { 57 | // Act 58 | val answer = Day05(input).solvePart2() 59 | 60 | // Assert 61 | assertThat(answer).isEqualTo("MCD") 62 | } 63 | 64 | @Test 65 | fun `Actual answer`() { 66 | // Act 67 | val answer = Day05(resourceAsListOfString("day05.txt")).solvePart2() 68 | 69 | // Assert 70 | assertThat(answer).isEqualTo("SSCGWJCRB") 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day19Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 19") 14 | class Day19Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | Blueprint 1: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 3 ore and 14 clay. Each geode robot costs 2 ore and 7 obsidian. 19 | Blueprint 2: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 8 clay. Each geode robot costs 3 ore and 12 obsidian. 20 | """.trimIndent().lines() 21 | 22 | @Nested 23 | @DisplayName("Part 1") 24 | inner class Part1 { 25 | 26 | @Test 27 | fun `Matches example`() { 28 | // Act 29 | val answer = Day19(input).solvePart1() 30 | 31 | // Assert 32 | assertThat(answer).isEqualTo(33) 33 | } 34 | 35 | @Test 36 | fun `Actual answer`() { 37 | // Act 38 | val answer = Day19(resourceAsListOfString("day19.txt")).solvePart1() 39 | 40 | // Assert 41 | assertThat(answer).isEqualTo(1_092) 42 | } 43 | } 44 | 45 | @Nested 46 | @DisplayName("Part 2") 47 | inner class Part2 { 48 | 49 | @Test 50 | fun `Matches example`() { 51 | // Act 52 | val answer = Day19(input).solvePart2() 53 | 54 | // Assert 55 | assertThat(answer).isEqualTo(3_472) 56 | } 57 | 58 | @Test 59 | fun `Actual answer`() { 60 | // Act 61 | val answer = Day19(resourceAsListOfString("day19.txt")).solvePart2() 62 | 63 | // Assert 64 | assertThat(answer).isEqualTo(3_542) 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day21Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 | // Arrange 17 | private val input = """ 18 | root: pppw + sjmn 19 | dbpl: 5 20 | cczh: sllz + lgvd 21 | zczc: 2 22 | ptdq: humn - dvpt 23 | dvpt: 3 24 | lfqf: 4 25 | humn: 5 26 | ljgn: 2 27 | sjmn: drzm * dbpl 28 | sllz: 4 29 | pppw: cczh / lfqf 30 | lgvd: ljgn * ptdq 31 | drzm: hmdt - zczc 32 | hmdt: 32 33 | """.trimIndent().lines() 34 | 35 | @Nested 36 | @DisplayName("Part 1") 37 | inner class Part1 { 38 | 39 | @Test 40 | fun `Matches example`() { 41 | // Act 42 | val answer = Day21(input).solvePart1() 43 | 44 | // Assert 45 | assertThat(answer).isEqualTo(152) 46 | } 47 | 48 | @Test 49 | fun `Actual answer`() { 50 | // Act 51 | val answer = Day21(resourceAsListOfString("day21.txt")).solvePart1() 52 | 53 | // Assert 54 | assertThat(answer).isEqualTo(66174565793494) 55 | } 56 | } 57 | 58 | @Nested 59 | @DisplayName("Part 2") 60 | inner class Part2 { 61 | 62 | @Test 63 | fun `Matches example`() { 64 | // Act 65 | val answer = Day21(input).solvePart2() 66 | 67 | // Assert 68 | assertThat(answer).isEqualTo(301) 69 | } 70 | 71 | @Test 72 | fun `Actual answer`() { 73 | // Act 74 | val answer = Day21(resourceAsListOfString("day21.txt")).solvePart2() 75 | 76 | // Assert 77 | assertThat(answer).isEqualTo(3327575724809L) 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day09Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 9") 14 | class Day09Test { 15 | 16 | @Nested 17 | @DisplayName("Part 1") 18 | inner class Part1 { 19 | // Arrange 20 | private val input = """ 21 | R 4 22 | U 4 23 | L 3 24 | D 1 25 | R 4 26 | D 1 27 | L 5 28 | R 2 29 | """.trimIndent().lines() 30 | 31 | @Test 32 | fun `Matches example`() { 33 | // Act 34 | val answer = Day09(input).solvePart1() 35 | 36 | // Assert 37 | assertThat(answer).isEqualTo(13) 38 | } 39 | 40 | @Test 41 | fun `Actual answer`() { 42 | // Act 43 | val answer = Day09(resourceAsListOfString("day09.txt")).solvePart1() 44 | 45 | // Assert 46 | assertThat(answer).isEqualTo(6_464) 47 | } 48 | } 49 | 50 | @Nested 51 | @DisplayName("Part 2") 52 | inner class Part2 { 53 | // Arrange 54 | private val input = """ 55 | R 5 56 | U 8 57 | L 8 58 | D 3 59 | R 17 60 | D 10 61 | L 25 62 | U 20 63 | """.trimIndent().lines() 64 | 65 | @Test 66 | fun `Matches example`() { 67 | // Act 68 | val answer = Day09(input).solvePart2() 69 | 70 | // Assert 71 | assertThat(answer).isEqualTo(36) 72 | } 73 | 74 | @Test 75 | fun `Actual answer`() { 76 | // Act 77 | val answer = Day09(resourceAsListOfString("day09.txt")).solvePart2() 78 | 79 | // Assert 80 | assertThat(answer).isEqualTo(2_604) 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day05.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 5 - Supply Stacks 7 | * Problem Description: http://adventofcode.com/2022/day/5 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day5/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day05(input: List) { 13 | 14 | private val stacks: List> = createStacks(input) 15 | private val instructions: List = parseInstructions(input) 16 | 17 | fun solvePart1(): String { 18 | performInstructions(true) 19 | return stacks.tops() 20 | } 21 | 22 | fun solvePart2(): String { 23 | performInstructions(false) 24 | return stacks.tops() 25 | } 26 | 27 | private fun performInstructions(reverse: Boolean) { 28 | instructions.forEach { (amount, source, destination) -> 29 | val toBeMoved = stacks[source].take(amount) 30 | repeat(amount) { stacks[source].removeFirst() } 31 | stacks[destination].addAll(0, if (reverse) toBeMoved.reversed() else toBeMoved) 32 | } 33 | } 34 | 35 | private fun Iterable>.tops(): String = 36 | map { it.first() }.joinToString("") 37 | 38 | private fun createStacks(input: List): List> { 39 | val stackRows = input.takeWhile { it.contains('[') } 40 | return (1..stackRows.last().length step 4).map { index -> 41 | stackRows 42 | .mapNotNull { it.getOrNull(index) } 43 | .filter { it.isUpperCase() } 44 | .toMutableList() 45 | } 46 | } 47 | 48 | private fun parseInstructions(input: List): List = 49 | input 50 | .dropWhile { !it.startsWith("move") } 51 | .map { row -> 52 | row.split(" ").let { parts -> 53 | Instruction(parts[1].toInt(), parts[3].toInt() - 1, parts[5].toInt() - 1) 54 | } 55 | } 56 | 57 | private data class Instruction(val amount: Int, val source: Int, val target: Int) 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/resources/day25.txt: -------------------------------------------------------------------------------- 1 | 1-201-=2 2 | 210--1211001 3 | 120 4 | 1==1-=1=-1=-=1-==- 5 | 1-- 6 | 1-1-2221=- 7 | 1021= 8 | 2-=-21==02 9 | 1- 10 | 1-222122-0==020 11 | 1-20122---12=2112-2= 12 | 221 13 | 12=220-2-=1= 14 | 21 15 | 1-20 16 | 1-0=-0-2--- 17 | 10-=221=-0102 18 | 212-020-1=00 19 | 201=020=-1= 20 | 2=0=01=2== 21 | 2=1=0=11-2===20-- 22 | 2-0-221 23 | 1--10=--1-0-2 24 | 100=-11222=1 25 | 11-=1 26 | 11=--=1012--02- 27 | 121 28 | 1=11=1 29 | 1==2---002--11=-1- 30 | 11=0==--0 31 | 2==0110=2=1== 32 | 221=-=-=-02 33 | 12-10 34 | 2= 35 | 2-0-=2 36 | 1=0-0=2 37 | 10==-2210=-=202 38 | 2=-21 39 | 2=-=1220 40 | 201=2==1 41 | 1==1=00-1-= 42 | 1200-00-00-21-=-=0 43 | 1=0=-22-200=-2-=-- 44 | 1==-=--12-1112-22 45 | 1=0=-00====102 46 | 20222010-1 47 | 1--- 48 | 20--==2-201- 49 | 1=1 50 | 120=02=-=1-0=1 51 | 1=-210-1=1 52 | 1110--2 53 | 1102-1=2----201=- 54 | 1=01=2-01 55 | 12=2--0-1001 56 | 12=1 57 | 102 58 | 2=1=-11 59 | 12=001022 60 | 2=1=1=-01== 61 | 101---=1-- 62 | 10=00001-0122=0 63 | 12=-=--11=112=0202 64 | 1-122====012100 65 | 212=020=1022-0 66 | 10=22=2 67 | 1===212-02=1 68 | 2=-2===-01010-121 69 | 122=10 70 | 2-0-1=-0--1001=-2 71 | 1121 72 | 1-21--100=1=2=1=2- 73 | 1==0 74 | 1=-0=0-2=0-=1===0 75 | 2-02-== 76 | 20-=-2022===-222 77 | 1=1100-1 78 | 12=-1=-02-2-20-=1-= 79 | 10= 80 | 1=1-==2 81 | 101-=01221-==-2-=- 82 | 12-=111=2=11-=1212 83 | 12==202=121 84 | 22022=000-121001- 85 | 12=2 86 | 1==0==1--1 87 | 222 88 | 10 89 | 12-0122=01- 90 | 10-0=01120 91 | 210-0===-011=-=12= 92 | 1=-1=0=2-102--0 93 | 10111000--0-===0 94 | 1=0-=-2- 95 | 2-==22100 96 | 1-2=-2-1-020=-2- 97 | 1=001-1=02=--2 98 | 1==0-211-21=- 99 | 1-02=2=--221=-012== 100 | 1-011-221-0= 101 | 10-20= 102 | 1=-0--= 103 | 10-=022101=1--22 104 | 2-0-1202==-==- 105 | 1=0- 106 | 11= 107 | 2200 108 | 2-22-212==-0==2= 109 | 1012 110 | 1=2=12===2-= 111 | 1==211-02- 112 | 1-001==2101220 113 | 2-001 114 | 10-=2-= 115 | 102110==21=12--02 116 | 1-=1122212002=010 117 | 1-10-201=221=021- 118 | 2-00=2221 119 | 2--1 120 | 11=12=0 121 | 2-21=- 122 | 20--2-1=22220-0 123 | 2=22=1-02=21 124 | 10==10112=1 125 | 1-2=0=0=02== 126 | 2201=2 127 | 10-=00121 128 | 10-012-12 -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day14.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 14 - Regolith Reservoir 7 | * Problem Description: http://adventofcode.com/2022/day/14 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day14/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day14(input: List) { 13 | 14 | private val cave: MutableSet = parseInput(input) 15 | private val sandSource: Point2D = Point2D(500, 0) 16 | private val maxY: Int = cave.maxOf { it.y } 17 | 18 | fun solvePart1(): Int = 19 | dropSand(maxY + 1) 20 | 21 | fun solvePart2(): Int { 22 | val minX: Int = cave.minOf { it.x } 23 | val maxX: Int = cave.maxOf { it.x } 24 | cave.addAll(Point2D(minX - maxY, maxY + 2).lineTo(Point2D(maxX + maxY, maxY + 2))) 25 | return dropSand(maxY + 3) + 1 26 | } 27 | 28 | private fun dropSand(voidStartsAt: Int): Int { 29 | var start = sandSource 30 | var landed = 0 31 | while (true) { 32 | val next = listOf(start.down(), start.downLeft(), start.downRight()).firstOrNull { it !in cave } 33 | start = when { 34 | next == null && start == sandSource -> return landed 35 | next == null -> { 36 | cave.add(start) 37 | landed += 1 38 | sandSource 39 | } 40 | 41 | next.y == voidStartsAt -> return landed 42 | else -> next 43 | } 44 | } 45 | } 46 | 47 | private fun Point2D.down(): Point2D = Point2D(x, y + 1) 48 | private fun Point2D.downLeft(): Point2D = Point2D(x - 1, y + 1) 49 | private fun Point2D.downRight(): Point2D = Point2D(x + 1, y + 1) 50 | 51 | private fun parseInput(input: List): MutableSet = 52 | input.flatMap { row -> 53 | row.split(" -> ") 54 | .map { Point2D.of(it) } 55 | .zipWithNext() 56 | .flatMap { (from, to) -> 57 | from.lineTo(to) 58 | } 59 | }.toMutableSet() 60 | } 61 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day09.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 9 - Rope Bridge 7 | * Problem Description: http://adventofcode.com/2022/day/9 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day9/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import kotlin.math.absoluteValue 13 | import kotlin.math.sign 14 | 15 | class Day09(input: List) { 16 | 17 | private val headPath: String = parseInput(input) 18 | 19 | fun solvePart1(): Int = 20 | followPath(2) 21 | 22 | fun solvePart2(): Int = 23 | followPath(10) 24 | 25 | private fun followPath(knots: Int): Int { 26 | val rope = Array(knots) { Point() } 27 | val tailVisits = mutableSetOf(Point()) 28 | 29 | headPath.forEach { direction -> 30 | rope[0] = rope[0].move(direction) 31 | rope.indices.windowed(2, 1) { (head, tail) -> 32 | if (!rope[head].touches(rope[tail])) { 33 | rope[tail] = rope[tail].moveTowards(rope[head]) 34 | } 35 | } 36 | tailVisits += rope.last() 37 | } 38 | return tailVisits.size 39 | } 40 | 41 | private data class Point(val x: Int = 0, val y: Int = 0) { 42 | fun move(direction: Char): Point = 43 | when (direction) { 44 | 'U' -> copy(y = y - 1) 45 | 'D' -> copy(y = y + 1) 46 | 'L' -> copy(x = x - 1) 47 | 'R' -> copy(x = x + 1) 48 | else -> throw IllegalArgumentException("Unknown Direction: $direction") 49 | } 50 | 51 | fun moveTowards(other: Point): Point = 52 | Point( 53 | (other.x - x).sign + x, 54 | (other.y - y).sign + y 55 | ) 56 | 57 | fun touches(other: Point): Boolean = 58 | (x - other.x).absoluteValue <= 1 && (y - other.y).absoluteValue <= 1 59 | 60 | } 61 | 62 | private fun parseInput(input: List): String = 63 | input.joinToString("") { row -> 64 | val direction = row.substringBefore(" ") 65 | val numberOfMoves = row.substringAfter(' ').toInt() 66 | direction.repeat(numberOfMoves) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day16Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 16") 14 | class Day16Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | Valve AA has flow rate=0; tunnels lead to valves DD, II, BB 19 | Valve BB has flow rate=13; tunnels lead to valves CC, AA 20 | Valve CC has flow rate=2; tunnels lead to valves DD, BB 21 | Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE 22 | Valve EE has flow rate=3; tunnels lead to valves FF, DD 23 | Valve FF has flow rate=0; tunnels lead to valves EE, GG 24 | Valve GG has flow rate=0; tunnels lead to valves FF, HH 25 | Valve HH has flow rate=22; tunnel leads to valve GG 26 | Valve II has flow rate=0; tunnels lead to valves AA, JJ 27 | Valve JJ has flow rate=21; tunnel leads to valve II 28 | """.trimIndent().lines() 29 | 30 | @Nested 31 | @DisplayName("Part 1") 32 | inner class Part1 { 33 | 34 | @Test 35 | fun `Matches example`() { 36 | // Act 37 | val answer = Day16(input).solvePart1() 38 | 39 | // Assert 40 | assertThat(answer).isEqualTo(1_651) 41 | } 42 | 43 | @Test 44 | fun `Actual answer`() { 45 | // Act 46 | val answer = Day16(resourceAsListOfString("day16.txt")).solvePart1() 47 | 48 | // Assert 49 | assertThat(answer).isEqualTo(1_741) 50 | } 51 | } 52 | 53 | @Nested 54 | @DisplayName("Part 2") 55 | inner class Part2 { 56 | 57 | @Test 58 | fun `Matches example`() { 59 | // Act 60 | val answer = Day16(input).solvePart2() 61 | 62 | // Assert 63 | assertThat(answer).isEqualTo(1_707) 64 | } 65 | 66 | @Test 67 | fun `Actual answer`() { 68 | // Act 69 | val answer = Day16(resourceAsListOfString("day16.txt")).solvePart2() 70 | 71 | // Assert 72 | assertThat(answer).isEqualTo(2_316) 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day07.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 7 - No Space Left On Device 7 | * Problem Description: http://adventofcode.com/2022/day/7 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day7/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day07(input: List) { 13 | 14 | private val rootDirectory: Directory = parseInput(input) 15 | 16 | fun solvePart1(): Int = 17 | rootDirectory.find { it.size <= 100_000 }.sumOf { it.size } 18 | 19 | fun solvePart2(): Int { 20 | val unusedSpace = 70_000_000 - rootDirectory.size 21 | val deficit = 30_000_000 - unusedSpace 22 | return rootDirectory.find { it.size >= deficit }.minBy { it.size }.size 23 | } 24 | 25 | private fun parseInput(input: List): Directory { 26 | val callStack = ArrayDeque().apply { add(Directory("/")) } 27 | input.forEach { item -> 28 | when { 29 | item == "$ ls" -> {}// Noop 30 | item.startsWith("dir") -> {} // Noop 31 | item == "$ cd /" -> callStack.removeIf { it.name != "/" } 32 | item == "$ cd .." -> callStack.removeFirst() 33 | item.startsWith("$ cd") -> { 34 | val name = item.substringAfterLast(" ") 35 | callStack.addFirst(callStack.first().traverse(name)) 36 | } 37 | else -> { 38 | val size = item.substringBefore(" ").toInt() 39 | callStack.first().addFile(size) 40 | } 41 | } 42 | } 43 | return callStack.last() 44 | } 45 | 46 | class Directory(val name: String) { 47 | private val subDirs: MutableMap = mutableMapOf() 48 | private var sizeOfFiles: Int = 0 49 | 50 | val size: Int 51 | get() = sizeOfFiles + subDirs.values.sumOf { it.size } 52 | 53 | fun addFile(size: Int) { 54 | sizeOfFiles += size 55 | } 56 | 57 | fun traverse(dir: String): Directory = 58 | subDirs.getOrPut(dir) { Directory(dir) } 59 | 60 | fun find(predicate: (Directory) -> Boolean): List = 61 | subDirs.values.filter(predicate) + 62 | subDirs.values.flatMap { it.find(predicate) } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/resources/day15.txt: -------------------------------------------------------------------------------- 1 | Sensor at x=3842919, y=126080: closest beacon is at x=3943893, y=1918172 2 | Sensor at x=406527, y=2094318: closest beacon is at x=-1066, y=1333278 3 | Sensor at x=2208821, y=3683408: closest beacon is at x=2914373, y=3062268 4 | Sensor at x=39441, y=1251806: closest beacon is at x=-1066, y=1333278 5 | Sensor at x=3093352, y=2404566: closest beacon is at x=2810772, y=2699609 6 | Sensor at x=3645473, y=2234498: closest beacon is at x=3943893, y=1918172 7 | Sensor at x=3645012, y=2995540: closest beacon is at x=4001806, y=2787325 8 | Sensor at x=18039, y=3083937: closest beacon is at x=103421, y=3007511 9 | Sensor at x=2375680, y=551123: closest beacon is at x=2761373, y=2000000 10 | Sensor at x=776553, y=123250: closest beacon is at x=-1066, y=1333278 11 | Sensor at x=2884996, y=2022644: closest beacon is at x=2761373, y=2000000 12 | Sensor at x=1886537, y=2659379: closest beacon is at x=2810772, y=2699609 13 | Sensor at x=3980015, y=3987237: closest beacon is at x=3844688, y=3570059 14 | Sensor at x=3426483, y=3353349: closest beacon is at x=3844688, y=3570059 15 | Sensor at x=999596, y=1165648: closest beacon is at x=-1066, y=1333278 16 | Sensor at x=2518209, y=2287271: closest beacon is at x=2761373, y=2000000 17 | Sensor at x=3982110, y=3262128: closest beacon is at x=3844688, y=3570059 18 | Sensor at x=3412896, y=3999288: closest beacon is at x=3844688, y=3570059 19 | Sensor at x=2716180, y=2798731: closest beacon is at x=2810772, y=2699609 20 | Sensor at x=3575486, y=1273265: closest beacon is at x=3943893, y=1918172 21 | Sensor at x=7606, y=2926795: closest beacon is at x=103421, y=3007511 22 | Sensor at x=2719370, y=2062251: closest beacon is at x=2761373, y=2000000 23 | Sensor at x=1603268, y=1771299: closest beacon is at x=2761373, y=2000000 24 | Sensor at x=3999678, y=1864727: closest beacon is at x=3943893, y=1918172 25 | Sensor at x=3157947, y=2833781: closest beacon is at x=2914373, y=3062268 26 | Sensor at x=3904662, y=2601010: closest beacon is at x=4001806, y=2787325 27 | Sensor at x=3846359, y=1608423: closest beacon is at x=3943893, y=1918172 28 | Sensor at x=2831842, y=3562642: closest beacon is at x=2914373, y=3062268 29 | Sensor at x=3157592, y=1874755: closest beacon is at x=2761373, y=2000000 30 | Sensor at x=934300, y=2824967: closest beacon is at x=103421, y=3007511 31 | Sensor at x=3986911, y=1907590: closest beacon is at x=3943893, y=1918172 32 | Sensor at x=200888, y=3579976: closest beacon is at x=103421, y=3007511 33 | Sensor at x=967209, y=3837958: closest beacon is at x=103421, y=3007511 34 | Sensor at x=3998480, y=1972726: closest beacon is at x=3943893, y=1918172 35 | -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/Day15Test.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | package com.ginsberg.advent2022 6 | 7 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 8 | import org.assertj.core.api.Assertions.assertThat 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 15") 14 | class Day15Test { 15 | 16 | // Arrange 17 | private val input = """ 18 | Sensor at x=2, y=18: closest beacon is at x=-2, y=15 19 | Sensor at x=9, y=16: closest beacon is at x=10, y=16 20 | Sensor at x=13, y=2: closest beacon is at x=15, y=3 21 | Sensor at x=12, y=14: closest beacon is at x=10, y=16 22 | Sensor at x=10, y=20: closest beacon is at x=10, y=16 23 | Sensor at x=14, y=17: closest beacon is at x=10, y=16 24 | Sensor at x=8, y=7: closest beacon is at x=2, y=10 25 | Sensor at x=2, y=0: closest beacon is at x=2, y=10 26 | Sensor at x=0, y=11: closest beacon is at x=2, y=10 27 | Sensor at x=20, y=14: closest beacon is at x=25, y=17 28 | Sensor at x=17, y=20: closest beacon is at x=21, y=22 29 | Sensor at x=16, y=7: closest beacon is at x=15, y=3 30 | Sensor at x=14, y=3: closest beacon is at x=15, y=3 31 | Sensor at x=20, y=1: closest beacon is at x=15, y=3 32 | """.trimIndent().lines() 33 | 34 | @Nested 35 | @DisplayName("Part 1") 36 | inner class Part1 { 37 | 38 | @Test 39 | fun `Matches example`() { 40 | // Act 41 | val answer = Day15(input).solvePart1(10) 42 | 43 | // Assert 44 | assertThat(answer).isEqualTo(26) 45 | } 46 | 47 | @Test 48 | fun `Actual answer`() { 49 | // Act 50 | val answer = Day15(resourceAsListOfString("day15.txt")).solvePart1(2_000_000) 51 | 52 | // Assert 53 | assertThat(answer).isEqualTo(4_748_135) 54 | } 55 | } 56 | 57 | @Nested 58 | @DisplayName("Part 2") 59 | inner class Part2 { 60 | 61 | @Test 62 | fun `Matches example`() { 63 | // Act 64 | val answer = Day15(input).solvePart2(20) 65 | 66 | // Assert 67 | assertThat(answer).isEqualTo(56000011L) 68 | } 69 | 70 | @Test 71 | fun `Actual answer`() { 72 | // Act 73 | val answer = Day15(resourceAsListOfString("day15.txt")).solvePart2(4000000) 74 | 75 | // Assert 76 | assertThat(answer).isEqualTo(13743542639657L) 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day15.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 15 - Beacon Exclusion Zone 7 | * Problem Description: http://adventofcode.com/2022/day/15 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day15/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import kotlin.math.absoluteValue 13 | 14 | class Day15(input: List) { 15 | 16 | private val sensors: Set = parseInput(input) 17 | 18 | fun solvePart1(findRow: Int): Int = 19 | sensors.mapNotNull { it.findRange(findRow) } 20 | .reduce() 21 | .sumOf { it.last - it.first } 22 | 23 | fun solvePart2(caveSize: Int): Long { 24 | val cave = (0..caveSize) 25 | return sensors.firstNotNullOf { sensor -> 26 | val up = Point2D(sensor.location.x, sensor.location.y - sensor.distance - 1) 27 | val down = Point2D(sensor.location.x, sensor.location.y + sensor.distance + 1) 28 | val left = Point2D(sensor.location.x - sensor.distance - 1, sensor.location.y) 29 | val right = Point2D(sensor.location.x + sensor.distance + 1, sensor.location.y) 30 | 31 | (up.lineTo(right) + right.lineTo(down) + down.lineTo(left) + left.lineTo(up)) 32 | .filter { it.x in cave && it.y in cave } 33 | .firstOrNull { candidate -> sensors.none { sensor -> sensor.isInRange(candidate) } } 34 | }.calculateAnswer() 35 | } 36 | 37 | private fun Point2D.calculateAnswer(): Long = (x * 4000000L) + y 38 | 39 | private class Sensor(val location: Point2D, closestBeacon: Point2D) { 40 | val distance: Int = location.distanceTo(closestBeacon) 41 | 42 | fun findRange(y: Int): IntRange? { 43 | val scanWidth = distance - (location.y - y).absoluteValue 44 | return (location.x - scanWidth..location.x + scanWidth).takeIf { it.first <= it.last } 45 | } 46 | 47 | fun isInRange(other: Point2D): Boolean = 48 | location.distanceTo(other) <= distance 49 | } 50 | 51 | private fun parseInput(input: List): Set = 52 | input 53 | .map { row -> 54 | Sensor( 55 | Point2D( 56 | row.substringAfter("x=").substringBefore(",").toInt(), 57 | row.substringAfter("y=").substringBefore(":").toInt() 58 | ), 59 | Point2D( 60 | row.substringAfterLast("x=").substringBefore(",").toInt(), 61 | row.substringAfterLast("=").toInt() 62 | ) 63 | ) 64 | }.toSet() 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day13.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 13 - Distress Signal 7 | * Problem Description: http://adventofcode.com/2022/day/13 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day13/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day13(input: List) { 13 | 14 | private val packets = input.filter { it.isNotBlank() }.map { Packet.of(it) } 15 | 16 | fun solvePart1(): Int = 17 | packets.chunked(2).mapIndexed { index, pair -> 18 | if (pair.first() < pair.last()) index + 1 else 0 19 | }.sum() 20 | 21 | fun solvePart2(): Int { 22 | val dividerPacket1 = Packet.of("[[2]]") 23 | val dividerPacket2 = Packet.of("[[6]]") 24 | val ordered = (packets + dividerPacket1 + dividerPacket2).sorted() 25 | return (ordered.indexOf(dividerPacket1) + 1) * (ordered.indexOf(dividerPacket2) + 1) 26 | } 27 | 28 | private sealed class Packet : Comparable { 29 | companion object { 30 | fun of(input: String): Packet = 31 | of( 32 | input.split("""((?<=[\[\],])|(?=[\[\],]))""".toRegex()) 33 | .filter { it.isNotBlank() } 34 | .filter { it != "," } 35 | .iterator() 36 | ) 37 | 38 | private fun of(input: Iterator): Packet { 39 | val packets = mutableListOf() 40 | while (input.hasNext()) { 41 | when (val symbol = input.next()) { 42 | "]" -> return ListPacket(packets) 43 | "[" -> packets.add(of(input)) 44 | else -> packets.add(IntPacket(symbol.toInt())) 45 | } 46 | } 47 | return ListPacket(packets) 48 | } 49 | } 50 | } 51 | 52 | private class IntPacket(val amount: Int) : Packet() { 53 | fun asList(): Packet = ListPacket(listOf(this)) 54 | 55 | override fun compareTo(other: Packet): Int = 56 | when (other) { 57 | is IntPacket -> amount.compareTo(other.amount) 58 | is ListPacket -> asList().compareTo(other) 59 | } 60 | } 61 | 62 | private class ListPacket(val subPackets: List) : Packet() { 63 | override fun compareTo(other: Packet): Int = 64 | when (other) { 65 | is IntPacket -> compareTo(other.asList()) 66 | is ListPacket -> subPackets.zip(other.subPackets) 67 | .map { it.first.compareTo(it.second) } 68 | .firstOrNull { it != 0 } ?: subPackets.size.compareTo(other.subPackets.size) 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day23.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 23 - Unstable Diffusion 7 | * Problem Description: http://adventofcode.com/2022/day/23 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day23/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day23(input: List) { 13 | 14 | private val startingPositions = parseInput(input) 15 | private val nextTurnOffsets: List> = createOffsets() 16 | 17 | fun solvePart1(): Int { 18 | val locations = (0 until 10).fold(startingPositions) { carry, round -> carry.playRound(round) } 19 | val gridSize = ((locations.maxOf { it.x } - locations.minOf { it.x }) + 1) * ((locations.maxOf { it.y } - locations.minOf { it.y }) + 1) 20 | return gridSize - locations.size 21 | } 22 | 23 | fun solvePart2(): Int { 24 | var thisTurn = startingPositions 25 | var roundId = 0 26 | do { 27 | val previousTurn = thisTurn 28 | thisTurn = previousTurn.playRound(roundId++) 29 | } while (previousTurn != thisTurn) 30 | return roundId 31 | } 32 | 33 | private fun Set.playRound(roundNumber: Int): Set { 34 | val nextPositions = this.toMutableSet() 35 | val movers: Map = this 36 | .filter { elf -> elf.neighbors().any { it in this } } 37 | .mapNotNull { elf -> 38 | nextTurnOffsets.indices.map { direction -> nextTurnOffsets[(roundNumber + direction) % 4] } 39 | .firstNotNullOfOrNull { offsets -> 40 | if (offsets.none { offset -> (elf + offset) in this }) elf to (elf + offsets.first()) 41 | else null 42 | } 43 | }.toMap() 44 | 45 | val safeDestinations = movers.values.groupingBy { it }.eachCount().filter { it.value == 1 }.keys 46 | movers 47 | .filter { (_, target) -> target in safeDestinations } 48 | .forEach { (source, target) -> 49 | nextPositions.remove(source) 50 | nextPositions.add(target) 51 | } 52 | return nextPositions 53 | } 54 | 55 | private fun createOffsets(): List> = 56 | listOf( 57 | listOf(Point2D(0, -1), Point2D(-1, -1), Point2D(1, -1)), // N 58 | listOf(Point2D(0, 1), Point2D(-1, 1), Point2D(1, 1)), // S 59 | listOf(Point2D(-1, 0), Point2D(-1, -1), Point2D(-1, 1)), // W 60 | listOf(Point2D(1, 0), Point2D(1, -1), Point2D(1, 1)), // E 61 | ) 62 | 63 | private fun parseInput(input: List): Set = 64 | input.flatMapIndexed { y, row -> 65 | row.mapIndexedNotNull { x, char -> 66 | if (char == '#') Point2D(x, y) else null 67 | } 68 | }.toSet() 69 | } 70 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day12.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 12 - Hill Climbing Algorithm 7 | * Problem Description: http://adventofcode.com/2022/day/12 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day12/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import java.util.PriorityQueue 13 | 14 | class Day12(input: List) { 15 | 16 | private val heightMap: HeightMap = parseInput(input) 17 | 18 | fun solvePart1(): Int = heightMap.shortestPath( 19 | begin = heightMap.start, 20 | isGoal = { it == heightMap.end }, 21 | canMove = { from, to -> to - from <= 1 } 22 | ) 23 | 24 | fun solvePart2(): Int = heightMap.shortestPath( 25 | begin = heightMap.end, 26 | isGoal = { heightMap.elevations[it] == 0 }, 27 | canMove = { from, to -> from - to <= 1 } 28 | ) 29 | 30 | private class HeightMap(val elevations: Map, val start: Point2D, val end: Point2D) { 31 | 32 | fun shortestPath( 33 | begin: Point2D, 34 | isGoal: (Point2D) -> Boolean, 35 | canMove: (Int, Int) -> Boolean 36 | ): Int { 37 | val seen = mutableSetOf() 38 | val queue = PriorityQueue().apply { add(PathCost(begin, 0)) } 39 | 40 | while (queue.isNotEmpty()) { 41 | val nextPoint = queue.poll() 42 | 43 | if (nextPoint.point !in seen) { 44 | seen += nextPoint.point 45 | val neighbors = nextPoint.point.cardinalNeighbors() 46 | .filter { it in elevations } 47 | .filter { canMove(elevations.getValue(nextPoint.point), elevations.getValue(it)) } 48 | if (neighbors.any { isGoal(it) }) return nextPoint.cost + 1 49 | queue.addAll(neighbors.map { PathCost(it, nextPoint.cost + 1) }) 50 | } 51 | } 52 | throw IllegalStateException("No valid path from $start to $end") 53 | } 54 | } 55 | 56 | private data class PathCost(val point: Point2D, val cost: Int) : Comparable { 57 | override fun compareTo(other: PathCost): Int = 58 | this.cost.compareTo(other.cost) 59 | } 60 | 61 | private fun parseInput(input: List): HeightMap { 62 | var start: Point2D? = null 63 | var end: Point2D? = null 64 | val elevations = input.flatMapIndexed { y, row -> 65 | row.mapIndexed { x, char -> 66 | val here = Point2D(x, y) 67 | here to when (char) { 68 | 'S' -> 0.also { start = here } 69 | 'E' -> 25.also { end = here } 70 | else -> char - 'a' 71 | } 72 | } 73 | }.toMap() 74 | return HeightMap(elevations, start!!, end!!) 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day11.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 11 - Monkey in the Middle 7 | * Problem Description: http://adventofcode.com/2022/day/11 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day11/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day11(input: List) { 13 | 14 | private val monkeys: List = input.chunked(7).map { Monkey.of(it) } 15 | 16 | fun solvePart1(): Long { 17 | rounds(20) { it / 3 } 18 | return monkeys.business() 19 | } 20 | 21 | fun solvePart2(): Long { 22 | val testProduct: Long = monkeys.map { it.test }.reduce(Long::times) 23 | rounds(10_000) { it % testProduct } 24 | return monkeys.business() 25 | } 26 | 27 | private fun List.business(): Long = 28 | sortedByDescending { it.interactions }.let { it[0].interactions * it[1].interactions } 29 | 30 | private fun rounds(numRounds: Int, changeToWorryLevel: (Long) -> Long) { 31 | repeat(numRounds) { 32 | monkeys.forEach { it.inspectItems(monkeys, changeToWorryLevel) } 33 | } 34 | } 35 | 36 | private class Monkey( 37 | val items: MutableList, 38 | val operation: (Long) -> Long, 39 | val test: Long, 40 | val trueMonkey: Int, 41 | val falseMonkey: Int 42 | ) { 43 | 44 | var interactions: Long = 0 45 | 46 | fun inspectItems(monkeys: List, changeToWorryLevel: (Long) -> Long) { 47 | items.forEach { item -> 48 | val worry = changeToWorryLevel(operation(item)) 49 | val target = if (worry % test == 0L) trueMonkey else falseMonkey 50 | monkeys[target].items.add(worry) 51 | } 52 | interactions += items.size 53 | items.clear() 54 | } 55 | 56 | companion object { 57 | fun of(input: List): Monkey { 58 | val items = input[1].substringAfter(": ").split(", ").map { it.toLong() }.toMutableList() 59 | val operationValue = input[2].substringAfterLast(" ") 60 | val operation: (Long) -> Long = when { 61 | operationValue == "old" -> ({ it * it }) 62 | '*' in input[2] -> ({ it * operationValue.toLong() }) 63 | else -> ({ it + operationValue.toLong() }) 64 | } 65 | val test = input[3].substringAfterLast(" ").toLong() 66 | val trueMonkey = input[4].substringAfterLast(" ").toInt() 67 | val falseMonkey = input[5].substringAfterLast(" ").toInt() 68 | return Monkey( 69 | items, 70 | operation, 71 | test, 72 | trueMonkey, 73 | falseMonkey 74 | ) 75 | } 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/test/kotlin/com/ginsberg/advent2022/ResourcesTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | @file:Suppress("RedundantInnerClassModifier", "RedundantInnerClassModifier") 6 | 7 | package com.ginsberg.advent2022 8 | 9 | import com.ginsberg.advent2022.Resources.resourceAsListOfInt 10 | import com.ginsberg.advent2022.Resources.resourceAsListOfLong 11 | import com.ginsberg.advent2022.Resources.resourceAsListOfString 12 | import com.ginsberg.advent2022.Resources.resourceAsString 13 | import com.ginsberg.advent2022.Resources.resourceAsText 14 | import org.assertj.core.api.Assertions.assertThat 15 | import org.assertj.core.api.Assertions.assertThatThrownBy 16 | import org.junit.jupiter.api.Nested 17 | import org.junit.jupiter.api.Test 18 | 19 | class ResourcesTest { 20 | 21 | @Nested 22 | inner class ResourceAsStringTests { 23 | @Test 24 | fun `concatenates lines without delimiter`() { 25 | assertThat(resourceAsString("read_file_test_1.txt")) 26 | .isEqualTo("123") 27 | } 28 | 29 | @Test 30 | fun `concatenates lines with delimiter`() { 31 | assertThat(resourceAsString(fileName = "read_file_test_1.txt", delimiter = ":::")) 32 | .isEqualTo("1:::2:::3") 33 | } 34 | 35 | @Test 36 | fun `throws exception when file does not exist`() { 37 | assertThatThrownBy { 38 | resourceAsString("this_does_not_exist.txt", delimiter = "???") 39 | }.isInstanceOf(IllegalArgumentException::class.java) 40 | } 41 | } 42 | 43 | @Nested 44 | inner class ResourceAsTextTests { 45 | @Test 46 | fun `reads file as-is into one String`() { 47 | assertThat(resourceAsText("read_file_test_1.txt")) 48 | .isEqualTo(""" 49 | 1 50 | 2 51 | 3 52 | """.trimIndent()) 53 | } 54 | } 55 | 56 | @Nested 57 | inner class ResourceAsListTests { 58 | @Test 59 | fun `reads lines as Strings`() { 60 | assertThat(resourceAsListOfString("read_file_test_1.txt")) 61 | .hasSize(3) 62 | .containsExactly("1", "2", "3") 63 | } 64 | 65 | @Test 66 | fun `reads lines as Ints`() { 67 | assertThat(resourceAsListOfInt("read_file_test_1.txt")) 68 | .hasSize(3) 69 | .containsExactly(1, 2, 3) 70 | } 71 | 72 | @Test 73 | fun `reads lines as Longs`() { 74 | assertThat(resourceAsListOfLong("read_file_test_1.txt")) 75 | .hasSize(3) 76 | .containsExactly(1L, 2L, 3L) 77 | } 78 | 79 | @Test 80 | fun `throws exception when file does not exist`() { 81 | assertThatThrownBy { 82 | resourceAsListOfString("this_does_not_exist.txt") 83 | }.isInstanceOf(IllegalArgumentException::class.java) 84 | } 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /src/main/resources/day16.txt: -------------------------------------------------------------------------------- 1 | Valve OS has flow rate=0; tunnels lead to valves EE, CL 2 | Valve EN has flow rate=0; tunnels lead to valves CL, GV 3 | Valve RR has flow rate=24; tunnels lead to valves FS, YP 4 | Valve VB has flow rate=20; tunnels lead to valves UU, EY, SG, ZB 5 | Valve UU has flow rate=0; tunnels lead to valves OT, VB 6 | Valve WH has flow rate=0; tunnels lead to valves CS, JS 7 | Valve OF has flow rate=25; tunnel leads to valve YM 8 | Valve TY has flow rate=0; tunnels lead to valves AA, GQ 9 | Valve RV has flow rate=0; tunnels lead to valves BT, YX 10 | Valve GK has flow rate=0; tunnels lead to valves GD, AA 11 | Valve EL has flow rate=0; tunnels lead to valves EK, EE 12 | Valve OT has flow rate=9; tunnels lead to valves YR, BJ, OX, UU, HJ 13 | Valve DG has flow rate=11; tunnels lead to valves BN, QE 14 | Valve YR has flow rate=0; tunnels lead to valves OT, YX 15 | Valve GV has flow rate=0; tunnels lead to valves AA, EN 16 | Valve BN has flow rate=0; tunnels lead to valves DG, LU 17 | Valve FS has flow rate=0; tunnels lead to valves TI, RR 18 | Valve DW has flow rate=0; tunnels lead to valves SS, MS 19 | Valve DJ has flow rate=0; tunnels lead to valves KY, GD 20 | Valve BJ has flow rate=0; tunnels lead to valves OT, BT 21 | Valve KY has flow rate=0; tunnels lead to valves EE, DJ 22 | Valve YP has flow rate=0; tunnels lead to valves YM, RR 23 | Valve LU has flow rate=0; tunnels lead to valves BN, CS 24 | Valve OX has flow rate=0; tunnels lead to valves OT, XD 25 | Valve ZB has flow rate=0; tunnels lead to valves VB, PP 26 | Valve CL has flow rate=10; tunnels lead to valves KQ, EN, OS, MQ 27 | Valve XD has flow rate=0; tunnels lead to valves KR, OX 28 | Valve YM has flow rate=0; tunnels lead to valves OF, YP 29 | Valve EY has flow rate=0; tunnels lead to valves MS, VB 30 | Valve KQ has flow rate=0; tunnels lead to valves CS, CL 31 | Valve SS has flow rate=0; tunnels lead to valves AA, DW 32 | Valve SG has flow rate=0; tunnels lead to valves VB, KR 33 | Valve EE has flow rate=22; tunnels lead to valves XR, OS, KY, EL 34 | Valve OI has flow rate=0; tunnels lead to valves RE, MS 35 | Valve QE has flow rate=0; tunnels lead to valves DG, GD 36 | Valve GD has flow rate=3; tunnels lead to valves GK, DJ, MQ, QE, JS 37 | Valve EK has flow rate=23; tunnel leads to valve EL 38 | Valve GQ has flow rate=0; tunnels lead to valves CS, TY 39 | Valve CS has flow rate=7; tunnels lead to valves GQ, WH, KQ, LU 40 | Valve MS has flow rate=4; tunnels lead to valves HJ, EY, DW, OI 41 | Valve XR has flow rate=0; tunnels lead to valves EE, AA 42 | Valve RE has flow rate=6; tunnels lead to valves TI, PP, OI 43 | Valve KR has flow rate=17; tunnels lead to valves XD, SG 44 | Valve BT has flow rate=15; tunnels lead to valves BJ, RV 45 | Valve PP has flow rate=0; tunnels lead to valves RE, ZB 46 | Valve TI has flow rate=0; tunnels lead to valves RE, FS 47 | Valve HJ has flow rate=0; tunnels lead to valves OT, MS 48 | Valve AA has flow rate=0; tunnels lead to valves GK, GV, SS, XR, TY 49 | Valve MQ has flow rate=0; tunnels lead to valves GD, CL 50 | Valve JS has flow rate=0; tunnels lead to valves GD, WH 51 | Valve YX has flow rate=5; tunnels lead to valves YR, RV 52 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /src/main/resources/day24.txt: -------------------------------------------------------------------------------- 1 | #.######################################################################################################################## 2 | #<..<^>vv^.>>>^.>v.^v<.^<>><^v>v^v><><^<<.<..^^..^>v>><>^>>>vv>v.<^v>v<^v^>.^<^^<<><<<>^vv^>.^># 3 | #<>><>^^<.^<>^^>^^><^><^>v>v>v>>>^><<<>>v<>v>^v>>^v>v<<<.>^<<<<<>>v<<>^v^>.>>v<<># 4 | #>.^>.>v<><^^>..^....v>^^>>^v><<<<<^<^v><.v<.>..<>.>^v^^^.>^^><^v^^v<<....>^>v><<>v>^>^>v^^v><# 5 | #<^>^>v>.<^<.v<<<>^>vv^<vvv<^vv^v^<>vv^<><<>v<>v.vvv.>>v^>><<<>^^v><^^v^^v^^v>>v><<.>^vv.^<# 6 | #>>^><>.>>><><.<>v><<><>vvvv>^><>vv^>^<>^<>^^>><^^>.vvv^<^><^.>vvvv>^.vv<^><^.^vvv<<# 7 | #<>^.v.<^.v<>^^^^^>><^<..v<^v<>>.>>^><^v<^^v^>v^<.<^<.><^^<>^v^><.<>..^>v^.v>.^<><>^.^v><>>>>^.<# 8 | #><^>^<^.^<^.vv>.>v^<.>.<>.v<>>v^><><<<<^vv<<.v^<>><.^<^..^^>.v^<<<>^.v^<>^<.^<<>><# 9 | #<>vvv.v.<^<>^v.v><^^.>^>^<^v.v>>v<^^^<^<^^v.^.><<<>.<<>>^>>^<>.^>v<^.v.vv^v^^^..>.v<.vv<>.>>>>.^><><# 10 | #<>v.^><<<<>>.<<^v>.>v^<>^v>^>>.v.>>^.v^^^><^<<<^^.^v^^>^vv<<>>>.><.^^<<^^<<.<<><^<^^.v><# 11 | #>>><v>^v<^^v^vv><^.v..v.v.>vv><<^...><^v>>^<><>^>>^>^^<>>>.<^^>.v^^^.><>v<>.<# 12 | #><^^^v<><<<^v>^^>^<<>>.<^^vvv<<>^v^<.<>^v^..v>v<.<^^v><^<<<^v.><>vv><^vvv>^v^.^<.>vvvvv<>><># 13 | #>^<>^v^^v<^vvvvv^v.<<>v>>>^<^^<..>^<^<^.>v<>^>^>><>v.vvv.^^v.^^>^<>>^^v<>v<<<^^.>>^>>^>.>>><><>^^^>>^>><<^^^>>v<>>>>^v<^^>.><<^>^^^<.<>v<^><><>>>v>.>.>vv>.v<.<^^>>vv^v>>vv># 15 | #>>.>.vv>^>><^>^.^v>^v<>..<>^^.>..vv<^v>>^.vvv>>^^^vv^^v>^<^.><<v^<<>><^v>>^>^^.v^<^^<>><># 16 | #<^>^>v<^.v^vv^^v>^^v>v^^vv^v^vv>^.><.v<.<><>v^<><<<<>.v^v^<<>^<<>>>>>><.^^^<><<>^v^^# 17 | #.<^^>>v<^^<^>>>>.vvv^>^^><^><.<>v^^vv^v<^>>^<.>^>><^<^><<..v># 18 | #<.>>^.v^.^.v^v<>v>v>v^vv^^<^<<>^^><<><.v<>>^>vv^^>>v<><^^<>^v<vv.vvv>v<.^v^.^><>v>>vvv># 19 | #<>^.v<^v>>>v>v<>^>v^vv<^<.^v.vv^>.v..>>.>vv>>>v^.^^>>^>>><><><>v>>..<^.>^v<^^v^<>>>.^^<^<.v>^>vvv># 20 | #<^.v^<><<..^^vv>>>^vv.>^<>v^v^v^.>^<^<.>>^v><^^v>>^<<<..v<^>v>^vv>^vv^>^v.>>^<<^^>.>>^>^>^^vv.<^v^>>>.>>><^>>v^^^.vv.<<^v^.>v>><^>v.v><^<<>v>v^vv.v<.><><>.^v>.>>>^<>.^>^>v.^v^>v^<><.<<<^<^><^^^<# 22 | #>^<>v>v>.>><>.><..vvvv<>vv<<^^v<>v><^<><<^v>^v<<.<<^^<.v>.<<<>vvv.v>>v^v.>^<>>.<<^v.^^v<^^v.^<.v<<>...<<<<^^^v^.<.>^^<>>^>v^^^^<^v^<><^<<^^.^^<^vv^v<<^^<^<.^># 24 | #<^.^^.<.<<^v^<..><.^v<<>v.<^vv><v>>v><<^.<.>^>v>>>.<><.>^v>>v^v<.^^>.v^v>^><^^v^v>>vv>^.v<>^># 25 | #.>^.v<.>>^<><^>v><.<>>^^vv^.<.>.v>>v.>^><<..v<>v>v>>v><>v^^<^>^<<>^.<<^>v.>v^>vv<>># 26 | #<><.^^^^<>>.<^v.>^<<>v>.>>vv^^<>v^v<^.<.v^v>>>>^><^vvv.>>>v<<<.^^.v.^v.><<.v<>>>^.^v>^vvv.<>v^<^v^<^v<^<><^^^v^<# 27 | ########################################################################################################################.# 28 | -------------------------------------------------------------------------------- /src/main/resources/day12.txt: -------------------------------------------------------------------------------- 1 | abaaaaaccccccccccccccccccaaaaaaaaaaaaaccccaaaaaaaccccccccccccccccccccccccccccaaaaaa 2 | abaaaaaaccaaaacccccccccccaaaaaaaaacaaaacaaaaaaaaaacccccccccccccccccccccccccccaaaaaa 3 | abaaaaaacaaaaaccccccccccaaaaaaaaaaaaaaacaaaaaaaaaacccccccccccccaacccccccccccccaaaaa 4 | abaaaaaacaaaaaacccccccccaaaaaaaaaaaaaaccaaacaaaccccccccccccccccaacccccccccccccccaaa 5 | abccaaaccaaaaaacccaaaaccaaaaaaaaaaaaaccccaacaaacccccccccaacaccccacccccccccccccccaaa 6 | abcccccccaaaaaccccaaaacccccaaaaacccaaaccaaaaaaccccccccccaaaaccccccccccccccccccccaac 7 | abcccccccccaaaccccaaaacccccaaaaacccccccccaaaaaccccccccccklllllccccccccccccccccccccc 8 | abcccccccccccccccccaaccccccccaaccccccccaaaaaaaccccccccckklllllllcccccddccccaacccccc 9 | abaccccccccccccccccccccccccccaaccccccccaaaaaaaaccccccckkkklslllllcccddddddaaacccccc 10 | abacccccccccccccccccccccccccccccccaaaccaaaaaaaaccccccckkkssssslllllcddddddddacccccc 11 | abaccccccccccccccccccccccccccccccccaaaaccaaacaccccccckkksssssssslllmmmmmdddddaacccc 12 | abcccccccccccccccaaacccccccccccccaaaaaaccaacccccccccckkkssssusssslmmmmmmmdddddacccc 13 | abcccccccaaccccaaaaacccccccccccccaaaaaccccccaaaaaccckkkrssuuuussssqmmmmmmmmdddccccc 14 | abcccccccaaccccaaaaaacccccccaaccccaaaaacccccaaaaacckkkkrruuuuuussqqqqqqmmmmdddccccc 15 | abccccaaaaaaaacaaaaaacccccccaaaaccaaccaccccaaaaaacjkkkrrruuuxuuusqqqqqqqmmmmeeccccc 16 | abcaaaaaaaaaaacaaaaaccccccaaaaaacccccaaccccaaaaajjjjrrrrruuuxxuvvvvvvvqqqmmmeeccccc 17 | abcaacccaaaaccccaaaaaaacccaaaaacccacaaaccccaaaajjjjrrrrruuuxxxxvvvvvvvqqqmmeeeccccc 18 | abaaaaccaaaaacccccccaaaccccaaaaacaaaaaaaacccaajjjjrrrrtuuuuxxxyvyyyvvvqqqnneeeccccc 19 | abaaaaaaaaaaacccaaaaaaaccccaacaacaaaaaaaacccccjjjrrrttttuxxxxxyyyyyvvvqqnnneeeccccc 20 | abaaaaaaaccaacccaaaaaaaaacccccccccaaaaaaccccccjjjrrrtttxxxxxxxyyyyyvvvqqnnneeeccccc 21 | SbaaaaaacccccccccaaaaaaaaaccccccccaaaaacccccccjjjrrrtttxxxEzzzzyyyvvrrrnnneeecccccc 22 | abaaaaacccccccccccaaaaaaacccccccccaaaaaaccccccjjjqqqtttxxxxxyyyyyvvvrrrnnneeecccccc 23 | abaaacccccccccccaaaaaaaccaaccccccccccaaccaaaaajjjqqqttttxxxxyyyyyyvvrrrnnneeecccccc 24 | abaaacccccccccccaaaaaaaccaaacaaacccccccccaaaaajjjjqqqtttttxxyywyyyywvrrnnnfeecccccc 25 | abcaaacccccccaaaaaaaaaaacaaaaaaaccccccccaaaaaaciiiiqqqqtttxwyywwyywwwrrrnnfffcccccc 26 | abcccccccccccaaaaaaaaaaccaaaaaacccccccccaaaaaacciiiiqqqqttwwywwwwwwwwrrrnnfffcccccc 27 | abccccccccccccaaaaaacccaaaaaaaacccccccccaaaaaaccciiiiqqqttwwwwwswwwwrrrrnnfffcccccc 28 | abccccccccccccaaaaaacccaaaaaaaaacccccccccaaacccccciiiqqqtswwwwssssrrrrrroofffcccccc 29 | abccccccaaaaacaaaaaacccaaaaaaaaaaccccccccccccccccciiiqqqssswsssssssrrrrooofffaccccc 30 | abccccccaaaaacaaccaaccccccaaacaaacccccccccccccccccciiiqqssssssspoorrrooooofffaacccc 31 | abcccccaaaaaacccccccccccccaaacccccccccccccccccccccciiiqppssssspppooooooooffffaacccc 32 | abcccccaaaaaacccccccccccccaacccccccccccccccccccccccciipppppppppppoooooooffffaaccccc 33 | abcccccaaaaaaccccccccccccccccccccccccccccccccccccccciihppppppppgggggggggfffaaaccccc 34 | abccccccaaacccccccccccccccccccccccaccccccccccccccccchhhhpppppphggggggggggfaaaaccccc 35 | abaaaccccccccccccccccccccccaccccaaacccccccccccccccccchhhhhhhhhhgggggggggcaacccccccc 36 | abaaccaaaccaccccccccccccccaaacccaaacaacccaaaaacccccccchhhhhhhhhgaaccccccccccccccccc 37 | abaaacaaacaacccccccccaaaccaaaacaaaaaaaaccaaaaaccccccccchhhhhhaaaaacccccccccccccccca 38 | abaaaccaaaaaccccccccccaaacaaaaaaaacaaaaccaaaaaaccccccccccaaacccaaaacccccccccccaccca 39 | abcccaaaaaaccccccccccaaaaaaaaaaaaacaaaaccaaaaaaccccccccccaaaccccaaaccccccccccaaaaaa 40 | abcccaaaaaaaacccccccaaaaaaaaaaaaaaaaaccccaaaaaacccccccccccccccccccccccccccccccaaaaa 41 | abcccaacaaaaaccccccaaaaaaaaaaaaaaaaaaacccccaacccccccccccccccccccccccccccccccccaaaaa 42 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day16.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 16 - Proboscidea Volcanium 7 | * Problem Description: http://adventofcode.com/2022/day/16 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day16/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import com.github.shiguruikai.combinatoricskt.combinations 13 | import com.github.shiguruikai.combinatoricskt.permutations 14 | 15 | class Day16(input: List) { 16 | 17 | private val rooms: Map = input.map { ValveRoom.of(it) }.associateBy { it.name } 18 | private val cheapestPathCosts: Map> = calculateShortestPaths() 19 | 20 | fun solvePart1(): Int = searchPaths("AA", 30) 21 | 22 | fun solvePart2(): Int = 23 | cheapestPathCosts.keys.filter { it != "AA" } 24 | .combinations(cheapestPathCosts.size / 2) 25 | .map { it.toSet() } 26 | .maxOf { halfOfTheRooms -> 27 | searchPaths("AA", 26, halfOfTheRooms) + searchPaths("AA", 26, cheapestPathCosts.keys - halfOfTheRooms) 28 | } 29 | 30 | private fun searchPaths( 31 | location: String, 32 | timeAllowed: Int, 33 | seen: Set = emptySet(), 34 | timeTaken: Int = 0, 35 | totalFlow: Int = 0 36 | ): Int = cheapestPathCosts 37 | .getValue(location) 38 | .asSequence() 39 | .filterNot { (nextRoom, _) -> nextRoom in seen } 40 | .filter { (_, traversalCost) -> timeTaken + traversalCost + 1 < timeAllowed } 41 | .maxOfOrNull { (nextRoom, traversalCost) -> 42 | searchPaths( 43 | nextRoom, 44 | timeAllowed, 45 | seen + nextRoom, 46 | timeTaken + traversalCost + 1, 47 | totalFlow + ((timeAllowed - timeTaken - traversalCost - 1) * rooms.getValue(nextRoom).flowRate) 48 | ) 49 | } ?: totalFlow 50 | 51 | 52 | private fun calculateShortestPaths(): Map> { 53 | val shortestPaths = rooms.values.associate { 54 | it.name to it.paths.associateWith { 1 }.toMutableMap() 55 | }.toMutableMap() 56 | shortestPaths.keys.permutations(3).forEach { (waypoint, from, to) -> 57 | shortestPaths[from, to] = minOf( 58 | shortestPaths[from, to], // Existing Path 59 | shortestPaths[from, waypoint] + shortestPaths[waypoint, to] // New Path 60 | ) 61 | } 62 | val zeroFlowRooms = rooms.values.filter { it.flowRate == 0 || it.name == "AA" }.map { it.name }.toSet() 63 | shortestPaths.values.forEach { it.keys.removeAll(zeroFlowRooms) } 64 | val canGetToFromAA: Set = shortestPaths.getValue("AA").keys 65 | return shortestPaths.filter { it.key in canGetToFromAA || it.key == "AA" } 66 | } 67 | 68 | private operator fun Map>.set(key1: String, key2: String, value: Int) { 69 | getValue(key1)[key2] = value 70 | } 71 | 72 | private operator fun Map>.get(key1: String, key2: String, defaultValue: Int = 31000): Int = 73 | get(key1)?.get(key2) ?: defaultValue 74 | 75 | private data class ValveRoom(val name: String, val paths: List, val flowRate: Int) { 76 | companion object { 77 | fun of(input: String): ValveRoom = 78 | ValveRoom( 79 | input.substringAfter(" ").substringBefore(" "), 80 | input.substringAfter("valve").substringAfter(" ").split(", "), 81 | input.substringAfter("=").substringBefore(";").toInt() 82 | ) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/resources/day06.txt: -------------------------------------------------------------------------------- 1 | pnnfhnhshrhmhwwmwzmznmnwmwfmfhfjfcjjtgtbggpdgdjjbjrjsjpjrrmddmgmpmddrhddnfnfzfpfvpfpprhhlffmtffqhhdtdcdsswsdwswmmfvvpdprrnnhhhtffnfbbznbznnvdnnbffjrfrbfrbrgbrrntnggrqqwtqwwgjgsswgwqwtwwsvwvbwvwrwlrlppzfzwfzzpmzzhqqzqlzlglzzmrmwrmwwvmwvvnppjfjttlffhjjjsccbggnffqgfgjjnccmdmzmllvnlnznttlvlttvnvgnvvqvmvqqzrqqcgglzzwtztwwmjmzjjnddsffqrqlrrvsvdvldvvlgvlvccdzczcqcpphggtnthhhtbhtttcjtjcjgcjcbbrhbbfrffgjgdgzddcttczzsccbpcpddcpcggmjgjddtcccthccfrccmdmhmddnwddfldffntnptnpttcptcptpfphhmfmwfwmmlblgbgvbvlltqltldttfcfcclgcllmplmlbbjnjzjnzzttnvvgddshddsqddggsqgqddsggdhghjgjhhgchhdmdjmjddgdhghrrphrrpnnqhhjwwqrrcmmslmmszzpgzpzzrmzmznzllnjnnlnbbdvdsdffbpffcmmnznqqcbbzvvjnjvvwqwgqqpnnzwnzwnzwwwlpwpzzfqzfqqwnqnbnfnqnbqqbggqnqdndrrzzlffbbgqgfgrfrqqsddnqnqjjgssqwqwcqcpcrrqppwpjjfnfpffhphwwmcwwznwznnplptlplnlsnlsldslslsffwtwftwtbtdbbjsjcczwwfllwtlwtlwlvwlwrwppsggvcvrrqcrqqvmqvmmbrrsbsfspspjpnnmpmqmcczgzffqmfmtmpppwzppzrpzrzsrrpqrpqpmpvmpvpttbqtqmtmjttqdqgggcppclcjcpcsppctpplpdpcppcmmdzmzddvhvhnhrrldllcwwbnwnssshlhrhthggtmggbjbjwwbvbttjllvrrfggngvngnmmvzzrrmddmcddztztctfccqpcpcqqvqppqcqdcdhhvhssgfgzgwwzmmnssvwwbqbhbnhnphpqqjcqcddfwfttqjtqtlttglljgjbgjgnnsqqvrvffqvqfqbffljjpffssqdsqstqqqldqqmhmsmsqqwtqwqdqgdgjjfbjffgbbrhhqghgppqgpgmpmmfzfhhfrhffgmfggpzgpzzhtzhhlbhhqbbzvvnvqnntptmmbhbdhdwwmjjcnnmsscqcbbtjtvjvwjvvmsmjmtmpmgghttcztzggpddbfbfgbbdsdrsrrqfqjjqfjjhzhtzzmdzzcgzgdzzmvmmfmjmgjmggmppbdppmzpppvfppzhhfsfwfhhpjpmmrjjpssdccjpjpwjppvdpphcpcjcfjfwjfwfjwfjjqcqcwqqqsmmmbbgdgwwpcwwdfdlflrltlgtthfhfjhhlthtddlgdggsjsrrdpdcppgttphpgpwppmpzmmrjmmvjvgvgfglfgllbqlqhllszzlwwhzzdfdcdtctptwtztfzzmjzjtjtrjrcrnrjjmwmnnbddgvgtgsstjsszmpqdmzgqflrbrspjmtzjcrmlzltmhgblghnwqvwwqwzbpnfrpdpblpjgshfccfbjfsnwvvhnjftsdnsgtzzjtzpmtfdvzrhtqpblhwgmqtgpbfvbdmsnrrrvvbstpsznvbbwgjfqjrhdvwvgptpglpfddhddmtglmjlpwlvfpbtbmgbplbzrlpdlvqzcwhbscpszgfstjpfdvfpmljlngrbgrdnnblzqrfpzsdvblpwbtnhdjclldvwvbwcwzfzbdspgwpfqjfbdbrqcshtlvcrdstnzggbwqnzbrfzbpnrtmvpbvdhcvdsdshgtvhfgdzljflppqbwclnvbhbczvrscjhlbgbfvwdjhnjsgmvwhpfgwbbmnndpnglfrmtfdzvqgfjdqfhgrhvpbqndmqnqccgwswwdsqjnbjtjbjdbqgjnmfbdvlnfwbnrdqgvgzzhmmbbdzfdvvpwhpbwbnzdcdpchrwlhfsjnhhjggvplmqggwjdsvjtpnpnqgldjjdcscrdltssjdrpcrfbgbcjfplhzgwbprfcslhpcngtszrghmwhzdqscbfrhzdwcffzvmjrmcjcstfvhplvrsglgsjnjtrpddsdfqjsndjnfmvdhfgdbzzflqhsrrwmrnlpqzmcddqbqvvzgtlztpgjnddtcnbmqsjlhmcszrmcjvwzpptlfqsmpvgnzvrjdwzpdwqgbmdgdtvjlmfczthjbcgfhbqpnmlbmrwwhfptzlbmfdhssznjcvjbmnjtnvzjhzczlrrdnttmmcbnzhqpplzqwgttwrnwfvmnptgqlfrnzvqpjfgrzwmlcwvtptvcvrlsrdwdgqfvffspmdbnnrqjttpqvhvdpbcrvzptwnhhfsqzchmncvttcdgdnlppcfzpmjpvbvqhlvplwvrmmbbggbwttwmvsqjlllsftprsmtmnzjcqfzblrllzgshfljchrjwjlpvhpbrtrsschzltrblgjnbgdnmwdggjhqggntblnhsvfgsbcblhmctbqzqwmhqnjhpzjfqpjdgwpzhczcftfcpdhvzhzccmwmrfrbqshzmtpqgpbbvfqqbjbmvnlnlwjtzrpmhdlffccrqcfgsjfszbrzrfztntchtmgmbhjgmlsqzcbtqqjzzlghtzzqmlnnvsgsvbbjfgqsqbqmqrdzwpwdgbggpdvhvnlzshhntprjdwhnwfvdjzpqgflwrvwgtmfdmfdztcbtfnjdrvgdwwczdgphnvdgrbdchprqldfjrvcsflcmlcmzqvqgsgnzcgmrhccgcmptcdzhbcdgdtppwztfstzqqzqrdzlnzthggjmpcflmbcmdrrjnnpbpqfmjbzqbtsjjgdlmgncbmgspqqvbrvzrdjscpzjsdtcdvsdwqlmwrngttswnrsbqctvhgfnnwblpcqzdmzpfchplslspmghvgcqntmlrfhgpcbpspvfhnvqvglsqzsnsdzddqpbsjhlclslngbwvvgjhwfcncqsmqwbptzvpzlzslsjjjldjpwpfrdlfbjphqcjtsgqdsdfdjhqgdhcppndwmhmmldvvmblcqcqfqhltbcbvrnghjfmtgqwtwljtczvqlnmgscjhqdhnzwhzvzzqnlsrhqvljqpgpwghfqlhjjrrhvnmnnrbnlhdcjctwtlhmhhmhjvcgzdrzmdjrvqzgnsttjdwglgwlcmbcdnjprgfsbbdzzngbqdrvwwwhbtlnnmzqdjttsrrpvlfdqnfhhtdtvmpcjgdwtbnqmwmtszdqfmbhjsjpqqddzfggwjhbtlnqfgcwbjzdtcpcpzgnrmnvwlpgmwfjlpgppdfrfvvjwsfcdqdnpcpjbqsvhttssgptqjghctrbgntlfjzdrfjccsprsjlrrwrzsmnjsqslmpdtrvhlqbnmgpjthpqdqmnvrtzlhhzzfzbrcclpmpcszhbttgrtcpgcpjwpdbfpfvgspsgtvglwthqcmcvmrfmclwlvjlsptfgmtlrnsvjrnfwzhdcsmgztpzfcvzwdztpppvqpvqfpdrsfnlhrbqwrsqjtwjmhnpwmqmpdgdhbtbpfwnmswffdqffdggrdrpmngvpzplmmwlddnhcvjjzqqfsbbtfmzdwnpvbjrshmllczhgvwwcbcbtfrfnplqjwmjlvpwwgfrtffwddwppsgtnlmpvfnhfzcsgjbqbjmbvpnqppsrvwnlzvcmjqgtbzrdsnrgwbfmrvnflgccrssfvcwgllqqbbcthzmbtnsmbzbcczhtzcvmthttpltrtdmgspctvtpvqbhmnnpnjwmhpqclmjsdrbjwvjbtzcjlqbjsvbgdwqzflnwzcfjwtrhjgfshfmwbjfwpnhjsmtpgbpwlfjjnmdlrhchmnfmgmgcrftmwbzshdwbhndgwtjbrrvbwprqppfmgfmfllpcjgrwdmtzddthsjlgjljv 2 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day21.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 21 - Monkey Math 7 | * Problem Description: http://adventofcode.com/2022/day/21 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day21/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day21(input: List) { 13 | 14 | private val monkeys: Set = parseInput(input) 15 | private val root: Monkey = monkeys.first { it.name == "root" } 16 | 17 | fun solvePart1(): Long = 18 | root.yell() 19 | 20 | fun solvePart2(): Long = 21 | root.calculateHumanValue() 22 | 23 | private fun parseInput(input: List): Set { 24 | val monkeyCache: Map = input.map { Monkey(it) }.associateBy { it.name } 25 | monkeyCache.values.filterIsInstance().forEach { monkey -> 26 | monkey.left = monkeyCache.getValue(monkey.leftName) 27 | monkey.right = monkeyCache.getValue(monkey.rightName) 28 | } 29 | return monkeyCache.values.toSet() 30 | } 31 | 32 | private interface Monkey { 33 | val name: String 34 | fun yell(): Long 35 | fun findHumanPath(): Set 36 | fun calculateHumanValue(humanPath: Set = findHumanPath(), incoming: Long = 0L): Long 37 | 38 | companion object { 39 | operator fun invoke(row: String): Monkey { 40 | val name = row.substringBefore(":") 41 | return if (row.length == 17) { 42 | FormulaMonkey(name, row.substring(6..9), row.substringAfterLast(" "), row[11]) 43 | } else { 44 | NumberMonkey(name, row.substringAfter(" ").toLong()) 45 | } 46 | } 47 | } 48 | } 49 | 50 | private class NumberMonkey( 51 | override val name: String, 52 | val number: Long 53 | ) : Monkey { 54 | override fun yell(): Long = number 55 | 56 | override fun findHumanPath(): Set = 57 | if (name == "humn") setOf(this) else emptySet() 58 | 59 | override fun calculateHumanValue(humanPath: Set, incoming: Long): Long = 60 | if (name == "humn") incoming else number 61 | } 62 | 63 | private class FormulaMonkey( 64 | override val name: String, 65 | val leftName: String, 66 | val rightName: String, 67 | val op: Char 68 | ) : Monkey { 69 | lateinit var left: Monkey 70 | lateinit var right: Monkey 71 | 72 | override fun calculateHumanValue(humanPath: Set, incoming: Long): Long = 73 | if (name == "root") { 74 | if (left in humanPath) left.calculateHumanValue(humanPath, right.yell()) 75 | else right.calculateHumanValue(humanPath, left.yell()) 76 | } else if (left in humanPath) { 77 | left.calculateHumanValue(humanPath, incoming leftAntiOp right.yell()) // Negate 78 | } else { 79 | right.calculateHumanValue(humanPath, incoming rightAntiOp left.yell()) // Negate 80 | } 81 | 82 | override fun findHumanPath(): Set { 83 | val leftPath = left.findHumanPath() 84 | val rightPath = right.findHumanPath() 85 | return if (leftPath.isNotEmpty()) leftPath + this 86 | else if (rightPath.isNotEmpty()) rightPath + this 87 | else emptySet() 88 | } 89 | 90 | override fun yell(): Long = 91 | left.yell() op right.yell() 92 | 93 | private infix fun Long.op(right: Long): Long = 94 | when (op) { 95 | '+' -> this + right 96 | '-' -> this - right 97 | '*' -> this * right 98 | else -> this / right 99 | } 100 | 101 | private infix fun Long.leftAntiOp(right: Long): Long = 102 | when (op) { 103 | '+' -> this - right 104 | '-' -> this + right 105 | '*' -> this / right 106 | else -> this * right 107 | } 108 | 109 | private infix fun Long.rightAntiOp(right: Long): Long = 110 | when (op) { 111 | '+' -> this - right 112 | '-' -> right - this 113 | '*' -> this / right 114 | else -> right / this 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day17.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 17 - Pyroclastic Flow 7 | * Problem Description: http://adventofcode.com/2022/day/17 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day17/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import kotlin.math.absoluteValue 13 | 14 | class Day17(input: String) { 15 | 16 | private val jets: List = parseJets(input) 17 | private val shapes: List> = generateShapes() 18 | private val cave: MutableSet = (0..6).map { Point2D(it, 0) }.toMutableSet() 19 | private val down: Point2D = Point2D(0, 1) 20 | private val up: Point2D = Point2D(0, -1) 21 | private var jetCounter: Int = 0 22 | private var blockCounter: Int = 0 23 | 24 | fun solvePart1(): Int { 25 | repeat(2022) { 26 | simulate() 27 | } 28 | return cave.height() 29 | } 30 | 31 | fun solvePart2(): Long = 32 | calculateHeight(1000000000000L - 1) 33 | 34 | private fun simulate() { 35 | var thisShape = shapes.nth(blockCounter++).moveToStart(cave.minY()) 36 | do { 37 | val jettedShape = thisShape * jets.nth(jetCounter++) 38 | if (jettedShape in (0..6) && jettedShape.intersect(cave).isEmpty()) { 39 | thisShape = jettedShape 40 | } 41 | thisShape = thisShape * down 42 | } while (thisShape.intersect(cave).isEmpty()) 43 | cave += (thisShape * up) 44 | } 45 | 46 | private fun calculateHeight(targetBlockCount: Long): Long { 47 | data class State(val ceiling: List, val blockMod: Int, val jetMod: Int) 48 | 49 | val seen: MutableMap> = mutableMapOf() 50 | while (true) { 51 | simulate() 52 | val state = State(cave.normalizedCaveCeiling(), blockCounter % shapes.size, jetCounter % jets.size) 53 | if (state in seen) { 54 | // Fast forward 55 | val (blockCountAtLoopStart, heightAtLoopStart) = seen.getValue(state) 56 | val blocksPerLoop: Long = blockCounter - 1L - blockCountAtLoopStart 57 | val totalLoops: Long = (targetBlockCount - blockCountAtLoopStart) / blocksPerLoop 58 | val remainingBlocksFromClosestLoopToGoal: Long = 59 | (targetBlockCount - blockCountAtLoopStart) - (totalLoops * blocksPerLoop) 60 | val heightGainedSinceLoop = cave.height() - heightAtLoopStart 61 | repeat(remainingBlocksFromClosestLoopToGoal.toInt()) { 62 | simulate() 63 | } 64 | return cave.height() + (heightGainedSinceLoop * (totalLoops - 1)) 65 | } 66 | seen[state] = blockCounter - 1 to cave.height() 67 | } 68 | } 69 | 70 | private operator fun IntRange.contains(set: Set): Boolean = set.all { it.x in this } 71 | private operator fun Set.times(point: Point2D): Set = map { it + point }.toSet() 72 | private fun Set.minY(): Int = minOf { it.y } 73 | private fun Set.height(): Int = minY().absoluteValue 74 | 75 | private fun Set.normalizedCaveCeiling(): List = 76 | groupBy { it.x } 77 | .entries 78 | .sortedBy { it.key } 79 | .map { pointList -> pointList.value.minBy { point -> point.y } } 80 | .let { 81 | val normalTo = this.minY() 82 | it.map { point -> normalTo - point.y } 83 | } 84 | 85 | private fun Set.moveToStart(ceilingHeight: Int): Set = 86 | map { it + Point2D(2, ceilingHeight - 4) }.toSet() 87 | 88 | private fun generateShapes(): List> = 89 | listOf( 90 | setOf(Point2D(0, 0), Point2D(1, 0), Point2D(2, 0), Point2D(3, 0)), 91 | setOf(Point2D(1, 0), Point2D(0, -1), Point2D(1, -1), Point2D(2, -1), Point2D(1, -2)), 92 | setOf(Point2D(0, 0), Point2D(1, 0), Point2D(2, 0), Point2D(2, -1), Point2D(2, -2)), 93 | setOf(Point2D(0, 0), Point2D(0, -1), Point2D(0, -2), Point2D(0, -3)), 94 | setOf(Point2D(0, 0), Point2D(1, 0), Point2D(0, -1), Point2D(1, -1)) 95 | ) 96 | 97 | private fun parseJets(input: String): List = 98 | input.map { 99 | when (it) { 100 | '>' -> Point2D(1, 0) 101 | '<' -> Point2D(-1, 0) 102 | else -> throw IllegalStateException("No such jet direction $it") 103 | } 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/main/resources/day19.txt: -------------------------------------------------------------------------------- 1 | Blueprint 1: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 20 obsidian. 2 | Blueprint 2: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 15 obsidian. 3 | Blueprint 3: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 3 ore and 8 obsidian. 4 | Blueprint 4: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 15 clay. Each geode robot costs 2 ore and 13 obsidian. 5 | Blueprint 5: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 12 clay. Each geode robot costs 3 ore and 15 obsidian. 6 | Blueprint 6: Each ore robot costs 2 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 11 clay. Each geode robot costs 2 ore and 16 obsidian. 7 | Blueprint 7: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 8 clay. Each geode robot costs 2 ore and 15 obsidian. 8 | Blueprint 8: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 11 clay. Each geode robot costs 2 ore and 10 obsidian. 9 | Blueprint 9: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 16 clay. Each geode robot costs 3 ore and 9 obsidian. 10 | Blueprint 10: Each ore robot costs 4 ore. Each clay robot costs 2 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 2 ore and 8 obsidian. 11 | Blueprint 11: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 5 clay. Each geode robot costs 3 ore and 12 obsidian. 12 | Blueprint 12: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 7 clay. Each geode robot costs 4 ore and 20 obsidian. 13 | Blueprint 13: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 18 clay. Each geode robot costs 2 ore and 11 obsidian. 14 | Blueprint 14: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 20 clay. Each geode robot costs 2 ore and 8 obsidian. 15 | Blueprint 15: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 10 clay. Each geode robot costs 2 ore and 7 obsidian. 16 | Blueprint 16: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 9 clay. Each geode robot costs 2 ore and 20 obsidian. 17 | Blueprint 17: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 17 clay. Each geode robot costs 2 ore and 13 obsidian. 18 | Blueprint 18: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 16 clay. Each geode robot costs 4 ore and 16 obsidian. 19 | Blueprint 19: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 7 clay. Each geode robot costs 4 ore and 13 obsidian. 20 | Blueprint 20: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 14 clay. Each geode robot costs 3 ore and 17 obsidian. 21 | Blueprint 21: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 19 clay. Each geode robot costs 3 ore and 19 obsidian. 22 | Blueprint 22: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 7 clay. Each geode robot costs 2 ore and 16 obsidian. 23 | Blueprint 23: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 19 clay. Each geode robot costs 3 ore and 17 obsidian. 24 | Blueprint 24: Each ore robot costs 3 ore. Each clay robot costs 3 ore. Each obsidian robot costs 2 ore and 20 clay. Each geode robot costs 2 ore and 20 obsidian. 25 | Blueprint 25: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 14 clay. Each geode robot costs 3 ore and 16 obsidian. 26 | Blueprint 26: Each ore robot costs 4 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 5 clay. Each geode robot costs 3 ore and 18 obsidian. 27 | Blueprint 27: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 2 ore and 19 clay. Each geode robot costs 2 ore and 12 obsidian. 28 | Blueprint 28: Each ore robot costs 2 ore. Each clay robot costs 4 ore. Each obsidian robot costs 4 ore and 15 clay. Each geode robot costs 2 ore and 20 obsidian. 29 | Blueprint 29: Each ore robot costs 3 ore. Each clay robot costs 4 ore. Each obsidian robot costs 3 ore and 6 clay. Each geode robot costs 2 ore and 10 obsidian. 30 | Blueprint 30: Each ore robot costs 4 ore. Each clay robot costs 3 ore. Each obsidian robot costs 3 ore and 7 clay. Each geode robot costs 3 ore and 9 obsidian. 31 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day24.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 24 - Blizzard Basin 7 | * Problem Description: http://adventofcode.com/2022/day/24 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day24/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | class Day24(input: List) { 13 | 14 | private val initialMapState: MapState = MapState.of(input) 15 | private val start: Point2D = Point2D(input.first().indexOfFirst { it == '.' }, 0) 16 | private val goal: Point2D = Point2D(input.last().indexOfFirst { it == '.' }, input.lastIndex) 17 | 18 | fun solvePart1(): Int = 19 | solve().first 20 | 21 | fun solvePart2(): Int { 22 | val toGoal = solve() 23 | val backToStart = solve(goal, start, toGoal.second, toGoal.first) 24 | val backToGoal = solve(start, goal, backToStart.second, backToStart.first) 25 | return backToGoal.first 26 | } 27 | 28 | private fun solve( 29 | startPlace: Point2D = start, 30 | stopPlace: Point2D = goal, 31 | startState: MapState = initialMapState, 32 | stepsSoFar: Int = 0 33 | ): Pair { 34 | val mapStates = mutableMapOf(stepsSoFar to startState) 35 | val queue = mutableListOf(PathAttempt(stepsSoFar, startPlace)) 36 | val seen = mutableSetOf() 37 | 38 | while (queue.isNotEmpty()) { 39 | val thisAttempt = queue.removeFirst() 40 | if (thisAttempt !in seen) { 41 | seen += thisAttempt 42 | val nextMapState = mapStates.computeIfAbsent(thisAttempt.steps + 1) { key -> 43 | mapStates.getValue(key - 1).nextState() 44 | } 45 | 46 | // Can we just stand still here? 47 | if (nextMapState.isOpen(thisAttempt.location)) queue.add(thisAttempt.next()) 48 | 49 | val neighbors = thisAttempt.location.cardinalNeighbors() 50 | 51 | // Is one of our neighbors the goal? 52 | if (stopPlace in neighbors) return Pair(thisAttempt.steps + 1, nextMapState) 53 | 54 | // Add neighbors that will be open to move to on the next turn. 55 | neighbors 56 | .filter { it == start || (nextMapState.inBounds(it) && nextMapState.isOpen(it)) } 57 | .forEach { neighbor -> 58 | queue.add(thisAttempt.next(neighbor)) 59 | } 60 | } 61 | } 62 | throw IllegalStateException("No path to goal") 63 | } 64 | 65 | private data class PathAttempt(val steps: Int, val location: Point2D) { 66 | fun next(place: Point2D = location): PathAttempt = 67 | PathAttempt(steps + 1, place) 68 | } 69 | 70 | private data class MapState(val boundary: Point2D, val blizzards: Set) { 71 | private val unsafeSpots = blizzards.map { it.location }.toSet() 72 | 73 | fun isOpen(place: Point2D): Boolean = 74 | place !in unsafeSpots 75 | 76 | fun inBounds(place: Point2D): Boolean = 77 | place.x > 0 && place.y > 0 && place.x <= boundary.x && place.y <= boundary.y 78 | 79 | fun nextState(): MapState = 80 | copy(blizzards = blizzards.map { it.next(boundary) }.toSet()) 81 | 82 | companion object { 83 | fun of(input: List): MapState = 84 | MapState( 85 | Point2D(input.first().lastIndex - 1, input.lastIndex - 1), 86 | input.flatMapIndexed { y, row -> 87 | row.mapIndexedNotNull { x, char -> 88 | when (char) { 89 | '>' -> Blizzard(Point2D(x, y), Point2D(1, 0)) 90 | '<' -> Blizzard(Point2D(x, y), Point2D(-1, 0)) 91 | 'v' -> Blizzard(Point2D(x, y), Point2D(0, 1)) 92 | '^' -> Blizzard(Point2D(x, y), Point2D(0, -1)) 93 | else -> null 94 | } 95 | } 96 | }.toSet() 97 | ) 98 | } 99 | } 100 | 101 | private data class Blizzard(val location: Point2D, val offset: Point2D) { 102 | fun next(boundary: Point2D): Blizzard { 103 | var nextLocation = location + offset 104 | when { 105 | nextLocation.x == 0 -> nextLocation = Point2D(boundary.x, location.y) 106 | nextLocation.x > boundary.x -> nextLocation = Point2D(1, location.y) 107 | nextLocation.y == 0 -> nextLocation = Point2D(location.x, boundary.y) 108 | nextLocation.y > boundary.y -> nextLocation = Point2D(location.x, 1) 109 | } 110 | return copy(location = nextLocation) 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/resources/day23.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 | #.#....#..######...##.##......#.#...#####.#.##.#..#####..#..##....#...#.### 52 | .#.#..##.#..##.#...##.#..####.##..#...##..#.#.#..##.####...#.......##..#.## 53 | #.#.#..####.##.#.#......###..##.##..#.#.##.##..##.###.#..####.#..##..###.## 54 | ##.##.#......#.#..#.##.#..###.#.#....##..##.#..###..#........###..#.#..#.#. 55 | ##..##..###..##.#.####.#..###.....#...####.##...#...##.######.#.#.##.#...#. 56 | .#..##..#...##......####...##.#.##...##.###.#.##..#..###.##.....#...#.##..# 57 | #..#....#...#...#...#..#.#.#..#.####....#.#.#...##.#...#..###..#####.#...#. 58 | .#....#..#.####.#####.#....######....#.#####....#.##.##.#...#.#....#.....#. 59 | #.#####..###.##.#.#..#..#...######...#.###.##.##...##.#.#.#.#.##.##...#..#. 60 | #.#..#.....####.##......##...##..###.#.##.#..#.#.##..#...##.##.##...#...##. 61 | ####..##..##.##....##.##.####.....###.#####.###.#####....#####.#.#..##.#.## 62 | ##.#..###.#.#.#######..#..##.#..#........#.##.#..#....##...#.####..#.#..... 63 | .#..#.######.#.###.########..#..####.##...#.#.####..##..##.#...##.#...#.... 64 | #######...#...###.##.#.#.#....##.#..####.#.##..##.######..#.####..#..#..##. 65 | ####.#..#####.......#...###.....##.#.########..#..#####.##.##.##.#.##.#...# 66 | ####.#.....#.##.#.#...#####.###.####.####.####....#..#........#######.####. 67 | .#.#..#.#.#.#.##.###...##....##.#.#...#.#..####.#####..##...###.#.##.#..##. 68 | #.##.#.##.#...#..#..#..##....#.##.###...#.#..##....#....###.#..#.#####.#... 69 | .#.##..###.##..#######.#..#.##......###..####..##.##....#...#.#.#...#.###.# 70 | #..#..#.###.##......#...###.#.#..##...##.#..#.#.#.####.#....#.###..####..## 71 | ...##.#..#...#.#.#.#...#.#...##.#..##..#...##..#..####.....##..###.#..##... 72 | #.####.##....####.#.#.##.##...###..#......#####.....###....#.###..##...#.## 73 | ####..##..#..##..#...###.##..###.##..#.#..###...#...##.#.#..#...#..##.....# 74 | #.##.#.##.#....#.#...##.##...#.##......###...##.#.#...####....#.#...#...#.# 75 | #.#.##...####...##.###.#######.#.##..#.#..###..##.##.##....#.....#..#.#.... 76 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | ############################################################################## 3 | ## 4 | ## Gradle start up script for UN*X 5 | ## 6 | ############################################################################## 7 | 8 | # Attempt to set APP_HOME 9 | # Resolve links: $0 may be a link 10 | PRG="$0" 11 | # Need this for relative symlinks. 12 | while [ -h "$PRG" ] ; do 13 | ls=`ls -ld "$PRG"` 14 | link=`expr "$ls" : '.*-> \(.*\)$'` 15 | if expr "$link" : '/.*' > /dev/null; then 16 | PRG="$link" 17 | else 18 | PRG=`dirname "$PRG"`"/$link" 19 | fi 20 | done 21 | SAVED="`pwd`" 22 | cd "`dirname \"$PRG\"`/" >/dev/null 23 | APP_HOME="`pwd -P`" 24 | cd "$SAVED" >/dev/null 25 | 26 | APP_NAME="Gradle" 27 | APP_BASE_NAME=`basename "$0"` 28 | 29 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 30 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 31 | 32 | # Use the maximum available, or set MAX_FD != -1 to use that value. 33 | MAX_FD="maximum" 34 | 35 | warn () { 36 | echo "$*" 37 | } 38 | 39 | die () { 40 | echo 41 | echo "$*" 42 | echo 43 | exit 1 44 | } 45 | 46 | # OS specific support (must be 'true' or 'false'). 47 | cygwin=false 48 | msys=false 49 | darwin=false 50 | nonstop=false 51 | case "`uname`" in 52 | CYGWIN* ) 53 | cygwin=true 54 | ;; 55 | Darwin* ) 56 | darwin=true 57 | ;; 58 | MINGW* ) 59 | msys=true 60 | ;; 61 | NONSTOP* ) 62 | nonstop=true 63 | ;; 64 | esac 65 | 66 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 67 | 68 | # Determine the Java command to use to start the JVM. 69 | if [ -n "$JAVA_HOME" ] ; then 70 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 71 | # IBM's JDK on AIX uses strange locations for the executables 72 | JAVACMD="$JAVA_HOME/jre/sh/java" 73 | else 74 | JAVACMD="$JAVA_HOME/bin/java" 75 | fi 76 | if [ ! -x "$JAVACMD" ] ; then 77 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 78 | 79 | Please set the JAVA_HOME variable in your environment to match the 80 | location of your Java installation." 81 | fi 82 | else 83 | JAVACMD="java" 84 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 85 | 86 | Please set the JAVA_HOME variable in your environment to match the 87 | location of your Java installation." 88 | fi 89 | 90 | # Increase the maximum file descriptors if we can. 91 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 92 | MAX_FD_LIMIT=`ulimit -H -n` 93 | if [ $? -eq 0 ] ; then 94 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 95 | MAX_FD="$MAX_FD_LIMIT" 96 | fi 97 | ulimit -n $MAX_FD 98 | if [ $? -ne 0 ] ; then 99 | warn "Could not set maximum file descriptor limit: $MAX_FD" 100 | fi 101 | else 102 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 103 | fi 104 | fi 105 | 106 | # For Darwin, add options to specify how the application appears in the dock 107 | if $darwin; then 108 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 109 | fi 110 | 111 | # For Cygwin or MSYS, switch paths to Windows format before running java 112 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 113 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 114 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 115 | JAVACMD=`cygpath --unix "$JAVACMD"` 116 | 117 | # We build the pattern for arguments to be converted via cygpath 118 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 119 | SEP="" 120 | for dir in $ROOTDIRSRAW ; do 121 | ROOTDIRS="$ROOTDIRS$SEP$dir" 122 | SEP="|" 123 | done 124 | OURCYGPATTERN="(^($ROOTDIRS))" 125 | # Add a user-defined pattern to the cygpath arguments 126 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 127 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 128 | fi 129 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 130 | i=0 131 | for arg in "$@" ; do 132 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 133 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 134 | 135 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 136 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 137 | else 138 | eval `echo args$i`="\"$arg\"" 139 | fi 140 | i=`expr $i + 1` 141 | done 142 | case $i in 143 | 0) set -- ;; 144 | 1) set -- "$args0" ;; 145 | 2) set -- "$args0" "$args1" ;; 146 | 3) set -- "$args0" "$args1" "$args2" ;; 147 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 148 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 149 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 150 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 151 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 152 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 153 | esac 154 | fi 155 | 156 | # Escape application args 157 | save () { 158 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 159 | echo " " 160 | } 161 | APP_ARGS=`save "$@"` 162 | 163 | # Collect all arguments for the java command, following the shell quoting and substitution rules 164 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 165 | 166 | exec "$JAVACMD" "$@" 167 | -------------------------------------------------------------------------------- /src/main/kotlin/com/ginsberg/advent2022/Day19.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022 by Todd Ginsberg 3 | */ 4 | 5 | /** 6 | * Advent of Code 2022, Day 19 - Not Enough Minerals 7 | * Problem Description: http://adventofcode.com/2022/day/19 8 | * Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2022/day19/ 9 | */ 10 | package com.ginsberg.advent2022 11 | 12 | import java.util.PriorityQueue 13 | import kotlin.math.ceil 14 | 15 | class Day19(input: List) { 16 | 17 | private val blueprints: List = input.map { Blueprint.of(it) } 18 | 19 | fun solvePart1(): Int = 20 | blueprints.sumOf { it.id * calculateGeodesFound(it, 24) } 21 | 22 | fun solvePart2(): Int = 23 | blueprints.take(3).map { calculateGeodesFound(it, 32) }.reduce(Int::times) 24 | 25 | private fun calculateGeodesFound(blueprint: Blueprint, timeBudget: Int): Int { 26 | var maxGeodes = 0 27 | val queue = PriorityQueue().apply { add(ProductionState()) } 28 | 29 | while(queue.isNotEmpty()){ 30 | val state = queue.poll() 31 | if (state.canOutproduceBest(maxGeodes, timeBudget)) { 32 | queue.addAll(state.calculateNextStates(blueprint, timeBudget)) 33 | } 34 | maxGeodes = maxOf(maxGeodes, state.geodes) 35 | } 36 | 37 | return maxGeodes 38 | } 39 | 40 | private data class ProductionState( 41 | val time: Int = 1, 42 | val ore: Int = 1, 43 | val oreRobots: Int = 1, 44 | val clay: Int = 0, 45 | val clayRobots: Int = 0, 46 | val obsidian: Int = 0, 47 | val obsidianRobots: Int = 0, 48 | val geodes: Int = 0, 49 | val geodeRobots: Int = 0 50 | ): Comparable { 51 | 52 | override fun compareTo(other: ProductionState): Int = other.geodes.compareTo(geodes) 53 | 54 | fun canOutproduceBest(bestSoFar: Int, timeBudget: Int): Boolean { 55 | val timeLeft = timeBudget - time 56 | val potentialProduction = (0 until timeLeft).sumOf { it + geodeRobots } 57 | return geodes + potentialProduction > bestSoFar 58 | } 59 | 60 | fun calculateNextStates(blueprint: Blueprint, timeBudget: Int): List { 61 | val nextStates = mutableListOf() 62 | if (time < timeBudget) { 63 | if (blueprint.maxOre > oreRobots && ore > 0) { 64 | nextStates += blueprint.oreRobot.scheduleBuild(this) 65 | } 66 | if (blueprint.maxClay > clayRobots && ore > 0) { 67 | nextStates += blueprint.clayRobot.scheduleBuild(this) 68 | } 69 | if (blueprint.maxObsidian > obsidianRobots && ore > 0 && clay > 0) { 70 | nextStates += blueprint.obsidianRobot.scheduleBuild(this) 71 | } 72 | if (ore > 0 && obsidian > 0) { 73 | nextStates += blueprint.geodeRobot.scheduleBuild(this) 74 | } 75 | } 76 | return nextStates.filter { it.time <= timeBudget } 77 | } 78 | } 79 | 80 | private data class RobotBlueprint( 81 | val oreRobotsBuilt: Int, 82 | val clayRobotsBuilt: Int, 83 | val obsidianRobotsBuilt: Int, 84 | val geodeRobotsBuilt: Int, 85 | val oreCost: Int, 86 | val clayCost: Int = 0, 87 | val obsidianCost: Int = 0 88 | ) { 89 | private fun timeUntilBuild(productionState: ProductionState): Int = 90 | maxOf( 91 | if (oreCost <= productionState.ore) 0 else ceil((oreCost - productionState.ore) / productionState.oreRobots.toFloat()).toInt(), 92 | if (clayCost <= productionState.clay) 0 else ceil((clayCost - productionState.clay) / productionState.clayRobots.toFloat()).toInt(), 93 | if (obsidianCost <= productionState.obsidian) 0 else ceil((obsidianCost - productionState.obsidian) / productionState.obsidianRobots.toFloat()).toInt() 94 | ) + 1 95 | 96 | fun scheduleBuild(state: ProductionState): ProductionState { 97 | val timeRequired = timeUntilBuild(state) 98 | return state.copy( 99 | time = state.time + timeRequired, 100 | ore = (state.ore - oreCost) + (timeRequired * state.oreRobots), 101 | oreRobots = state.oreRobots + oreRobotsBuilt, 102 | clay = (state.clay - clayCost) + (timeRequired * state.clayRobots), 103 | clayRobots = state.clayRobots + clayRobotsBuilt, 104 | obsidian = (state.obsidian - obsidianCost) + (timeRequired * state.obsidianRobots), 105 | obsidianRobots = state.obsidianRobots + obsidianRobotsBuilt, 106 | geodes = state.geodes + (timeRequired * state.geodeRobots), 107 | geodeRobots = state.geodeRobots + geodeRobotsBuilt 108 | ) 109 | } 110 | } 111 | 112 | private data class Blueprint( 113 | val id: Int, 114 | val oreRobot: RobotBlueprint, 115 | val clayRobot: RobotBlueprint, 116 | val obsidianRobot: RobotBlueprint, 117 | val geodeRobot: RobotBlueprint 118 | ) { 119 | val maxOre: Int = 120 | maxOf(oreRobot.oreCost, clayRobot.oreCost, obsidianRobot.oreCost, geodeRobot.oreCost) 121 | 122 | val maxClay: Int = 123 | maxOf(oreRobot.clayCost, clayRobot.clayCost, obsidianRobot.clayCost, geodeRobot.clayCost) 124 | 125 | val maxObsidian: Int = 126 | maxOf(oreRobot.obsidianCost, clayRobot.obsidianCost, obsidianRobot.obsidianCost, geodeRobot.obsidianCost) 127 | 128 | companion object { 129 | fun of(input: String): Blueprint { 130 | val parts = input.split(" ", ": ") 131 | return Blueprint( 132 | id = parts[1].toInt(), 133 | oreRobot = RobotBlueprint(1, 0, 0, 0, parts[6].toInt()), 134 | clayRobot = RobotBlueprint(0, 1, 0, 0, parts[12].toInt()), 135 | obsidianRobot = RobotBlueprint(0, 0, 1, 0, parts[18].toInt(), parts[21].toInt()), 136 | geodeRobot = RobotBlueprint(0, 0, 0, 1, parts[27].toInt(), 0, parts[30].toInt()), 137 | ) 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/resources/day17.txt: -------------------------------------------------------------------------------- 1 | >>><<<>>>><<<<>><<<<>><>>><>>>><><<<<>>>><<>>><<<>><>>><<>><>>><<>>><<>><>>><>>><<<<><<<>><<<>>><<>>>><>>>><<<<>>>><<<>>>><<<>>>><<<>>>><<<<><<<<><<<>>>><<<>>><<<><<<>>>><<>><<<>><<<><<<><<>><<>>>><<>>><<><<>><<><<>>><<>>>><<<><>>><<<<>>><<<<><><<<><<>>><<>><>>>><<<<><<>>><<<>>><<<<>>>><<<<>><<<>>><<<<>>><<<>>>><<<>>>><<<>>>><<<<>>><<<>>>><<<><><<<><<<><>>>><>><>>><<><<<>>><><<<>><<<<>><<>><>><>>>><<<<>>><<>>>><<><<>><<<<>><><<>>>><<<>>>><<<>><<<<>>><<<<>>>><>>>><<>><<<><<<>><<<<>>><<<<>><<>><><<<<>>><<><<<>>>><<>>>><<<<>>>><<<>>>><<<>>><<>>>><>>>><<>>><<<>>>><>>>><<<<>>>><>>>><<<><<<>>>><>><>>><>>>><<<><>><<<<><<><>>>><<><<<<><<<>>><><>>>><<><>>>><<<>>><<<<>>><>>>><<<>>><<<<>>>><<>><<<>>><<>>>><<><<<<><><<<<>>><<<<>>><<<<>>><<>>><<<>><<>>><<<<>>>><<<<>>>><<<>>><>>>><<<<>>><>><<>>><<><<<<>><<>>><<<><><<<<>>>><<<>><><<>>><<>><<><>>><<<>>>><<<<>>><<<><<>><<>>><>><<>>>><<>>>><<>>>><<>>>><<>><>>>><<><>>>><<<>>>><<<>>><<><<<<><>><<<>><<<<>><<<<>><<>>>><<<>><<>><>>>><<<>>>><<<>>>><<<<>>><<<<>><<><<<>>>><<<>>>><<>>><<><><<<<>><<<<><<<><<>><<><<<<>><<<<>><<<<><<<<>>>><<<>><<<><<<<>>><>><>>><>>><<><<<<>>><<<<>>>><<<><<<>><<<>><<<>>><<>>><<<>>><>>><<><>>>><<<<>>><<<<>>>><<<>>>><>>><>><<>><<<>><><<<>>>><<<>>><><<><<><<<<><<<<>>><<<<><>>>><<<>>>><<>>><<<<>>>><<<<>>><<>>><>>>><>><<<>>><<<<>>>><>><<>>><<<><<<>>><<<<><<<<><>>>><<><>><<<<>><<<<>>>><>>>><<>>><<<<><<<><<>>>><<><<<>>><<<><<<<>><<>>><<<<>><>>>><><<<<>>><<<>>>><><<>>>><<<<>>>><<<<>><<<>>><<<<>>><<<>>><>>>><<>><>><<<<><<<>><<>>>><>><>>>><<<>>><<><<<>><<>><<<>><<>>><<<<>><><<<>>><<<<>>><<<>>><<<<>>><<<<>>><<>>><>>><<>>><<<>><>><<<>>><<<<>><>>>><<<>>><>><>><<<>>><>>><<>>><<>><<<<>>>><<>>>><<<<>><>>><<<<>>><<<<>>>><<<>>>><>><<<>>>><<<><<>>><<><>><<<>>><<<>>><<><>>><<>>>><<<><<<<><><>>><<<<>>>><<<<><<<>><<<>><<<>>><<<>>>><>>><<<>>><<<<>><<>><<<>>>><<<><<>>><<<>><<<<>>>><<<<>><<<><<<>>><<<<><>><<<><<<<>>>><<><>><<<>>><<>>>><>>>><<<><<<<>>>><<>>>><<>><<<>>>><><<<>><<>>><<><<<<>>><<>><<<>><<<<>>>><<>>><<>>><<<<>>>><<>>><<<>><<>>>><<>><<<>>><<<>>><<>>>><<<<><>><>>><<<<>>><<<><<>><<<><<<>>><>><<<><<><<<>>><<><<>>><>><<<>>>><<><>><<<>>><<<>>>><<>><><>>><<<<>>><<>><<<><<<<>>>><>>><<<<>>><><><<<<><><<>><<>><>>>><<<<>>><<<>>>><><<<<>><<<<>><<><<<<>>><>>><<<><<<>>><<<>>><<<<>>><<>><<<<><<<<>>>><<>><<<<>>><<<>><<>>><<<><<<>>>><<>><<<<>>><<<<>>>><<<>>>><<>>><>>><<<<><<<<><><<>>>><<<>><>>>><<<>>><>><>><><<>>><<<>>>><<<>><<><<><<>><<<<><<<><>>>><>>><>><>>><<<<>>><<<><>><<<<>>><<<<><><>>>><<>>>><<>>>><<>>>><<<<>>><>><<<<>>>><<<>><<><<<<>>>><>><<>><>><>>>><<>>><>>>><<<<>><<<>>><<<>>>><<<<>><<><<<<>><>>><<>>>><<<<>><<<<>><>>>><><<<<>>>><<><<<><<>><<<<>>>><<><<<<><<<<>>>><>><<>><<><<<<>><<<><<<<>>><><<>>><>>>><<<<>><>>><<<><<>>><>>>><>><<<>>>><>>><>><<<<>>><<<><<<<>>>><<<>>><<<>><<<>>>><<<>>><<<<>>><<<<><>>><<<<>>>><>><>>><>>><<>><<<>>>><<<>><<<>>><<<>>><<>>>><<<<><<<<><<<<>>>><<<>>><<<>>>><<<><<<<>>><<<<><<<<>><<<<>><>><<<<><<<<>>><<>><><<<<><><<<<>><<>>>><<>><>><<<<><<<<>>>><<>>>><<<>>><<<<>>>><<<<>>>><<<<>><<><>>>><>>>><<><<<<><<>><<>>>><<>><<<>>><>><><<<<><<><<>><<<>>><<>>><<>>>><<<><>>>><<<<>>>><<<>><<<><<<<><<><<<><<<>>>><<<<>>>><<<<><<<<><>>><><<<<>>>><<<<><<>><<<>>>><<<<>>><>><<<<>>><<<<>>>><<<<>>><>>><<>>><<<><>>><><<<<>>><>>><>><><<<>><>>>><><<<>><<><<<>>><<><<<<>>>><<<<>>>><<<<>><<<><<<><><>>><<<><>><<>>><>>>><<<<>>><<>>><<<<>>>><<<<>>><<<>><<<<><>><<<<>>><>><<<>>><<<<>><<<<>><<>>><<<<>>>><<<>>><<>>>><<>>>><<><<<<><<>>><<<<>><<>><<<><<<<>><<<>>><<<>>>><<<<>><>>>><>><<>>>><><<>><<<<><><<<>>><<<>><<<>>>><<<<>>>><<<<>>>><<<>>>><>>>><<<>>>><>><<<>><>>><<<><>>><<><>>><<<<>><<<<>><<><<<>>>><<<<>>><<<<>>>><<<<><<<<>>><<<>>><<<>><<<>>><<<<>><<<><<<>><<<><<<<>>>><<<>>><<<><<<<>>><<<>>>><><<<<>>><><<<>>>><<<<>><>>>><<><>>>><><<<><<<<>>>><<<>><<>>><<<<><<>>><><<><<>>><<<>>><<<<><<>><<><<<>>><<>>>><<<>>><<><>>><<<>><<<>>><>>>><<<<>>>><<>>>><<>><<>><<<<><<<>>>><<<<>>>><><<<><<>><<<<>>><>><>><<>>>><<<><<<>>>><>>><<><<><<<<>>>><<<>>>><<>><><<<<>>><<>>><<<<>><>><<<<><<>>><<<>>><<<<>>><>><<<>><<>>>><<<>>><><<<>><<<<>><>>><<>><<<<>>><<><<>>><>>><><<<<>>>><<<<>><<>><<<>>><<<<>>><<>>>><<><<<<>>>><>>><<>>>><>>><<<<>>>><<<<>>><<>>><<<>>><<<><<<<><>>>><<>><><<<<>>>><>>>><<<<>><>>>><>><>>>><<<<>>>><<>>>><<><<<<>>>><<<><>>><<<<><<>>><<<><<<<><>><<<>>><<>><<<<><<<>>>><<>><<>>><<<><<<<>><><<<><>>><<<<>>>><<>>><>>>><>>><<<<>>><<<><><<>>>><<<>><<<<>>>><<><<<>>><<<<>><<<<>>><>>>><<<<>><<>>><<<<>>><>>><<<<><<<>>>><<>>><<<<><<><<<>>>><<<<>><><<<<>>>><<<>>>><<<<><<>><<>>><<<>>><>><><<>>><<>><<<<><>><<<><>>><<<<>>><<>>><>><<<>>>><<<<>><><<<>><<<>><<>><<<>><<<<>>>><<<<><<<<>>>><<<<>>><<<><<<>>><>>>><<<>>><<<<>>>><>>>><>>><<<<>>>><<>>><<>>>><<>><>>><<>>>><>>>><<<<>>>><>>><<<><<<<><>>><<<<><>>>><<<>>>><>>><<>><<><<<>><<<<><<<><<<>><<<><<>>>><<<><<>>>><<><>><<>>><<>>><>><<<>><>>>><<>>>><<>>><>>><<<<>>>><<><<>>>><<<>>>><><<>>>><<<<>><>><<><>><<><>>><>>>><<<>>>><><<<>>><<<>>>><<<>>><<<>>><>><>>><>>>><<<><<<>><>>><<><<>><<<<><<>><<>><<<>>><<>>><<<<>>><<><>>><<>>>><<<><<<>>><><<<<><<><<<>><<<<>>><><<<<><<<<><>>>><<>>>><<<<>>><<<<>><<<<>><<<><<>><<>><>><<<<>>><<<<><>><<<<><<<<><<><<>><<<><<>>><<<<>>><<<>>>><<<>><>><<<>>><<<>><>>><<>>>><<>>><<<<>><<>>>><<<<><>>><<<><<<>>><<<>>><<><>>><>>>><<<>><<<<>><><<<>>>><<<<>>><<>><<<<>>><<<>><><<>>>><<>>>><<<>>>><<<><<<>>>><<<<>><<<<>>>><<>>><<<<><>>>><>>>><>><>>>><<<>>>><>>><<<<><<<><<<<>>><><<<<>><>><<>>>><<<>><<<>>>><>><<<><>>><<<><>><<<<>><<>>>><<>><>>><<<<>>><<<>><>>><<<>>><<>>><>>><<<<>>>><<>>>><>>>><<<<>><<<>><><>><<><<<>>>><<<>>><<<>>>><<<<>><<<<><<<>>>><<>><>><<<<>>><<>>>><>>>><<<<>>><><<<>>>><<<>>><<<>>>><<<><<>><<>>>><<<<>><<<>>>><<<>><<<<>>>><<>><<>>><<>>><<>>>><<>><>>><><<>>>><>><>><>><>><<<>><<<<>><>>><<<><><<<<>>>><<<>>>><<<<>><<<<><>>><<><<<<>><<<<>><<<>>>><<<<>>><>>>><<<<>>><>><>>>><<<>>><<<<>><>>>><<><<<<>>>><<<>>>><<<><<<>>>><<<>>><<<>><>>><<<>>><<<<>>>><<<>><>>>><<>>><<>>><><<<<>>><<>><<>>><<>>><<<<>>><<<>><>>><<>>>><<<>><<<>>>><<<>><<<<>><<>>>><<<<><>>><<<><<<>>>><<>><<<<><<<>>><>>><<<<>>><<<<>><<<<>><<<<>><<<>><<<>>><<<<>>>><<<>>>><><>><>><<<>>><<<<><<<<>>><<<<><<<<><><>>><<<>>>><<<<>>>><>><<<<><<<>><>>>><<<>><>>>><<<>><>>><<>>><<<<>><><<>>><<<<><<<<><<<><<<<>>><<><<><>>>><<><<<<>><>>><<<<>>><>>><<<<><<<<>>><>>>><<>>>><<<>>>><<<>>>><>>><>><<<<><<<<>><<<<>>>><<<<>><>>><<>>><<<>>><>>><<<><><><>>><<<<><<>>>><>><<>><<<<>><<<<>>><><<<<>><<>>><<<>>>><>><><><<<><>><<<<>>><>>>><>>><<>><<<<><<>>><<<>>><<><<<>>><>>>><<<<>>>><<<><>>><>>><<<>><>>><<><<>><<><<<>><><>>><<<<>>>><<<>><<<><<<>>><<>><>>>><>>>><<<>>><<<>>><<>>>><<<<><<>>>><<>>>><<<<>>>><<<<>>>><<<>>><<>>><<>><<>>><<<<>><<<><>>>><<<>>><<<>>><<>>>><>><<>>>><<<<>>><<>>><<<<>><<>>>><<<<>>><>>>><<>>><<<>>><<<>><<<<><>>>><<><<>>><>>><<<>><<><<<<>>>><<<<>><>>>><<>>><<<>><<>>>><>><<>><<<<>><<>>><>>><<<>><<>><><<<<>>><>><<><>>>><<>>>><<<<>><><>>>><>>>><>>>><<>><<<<><>>>><<<>><<<>>><<>><<<><<<<>>><>>>><<>>><<<<>><>><<<<>><>>>><<<>><<<<>>>><<<<>>><>>>><<><<<><<>>><<><<>><<<><<><>>>><<>>><>><<<<>>>><<<<><>><<<>><>><<<><><<<<>>><<>>><<<>><<<><<<>>>><<<<>>><<<><>>>><<<><<><>><<<<>>>><<<<><<>>><<<<>>><<>>><>>>><<<>>>><<><>>><<<<>><>>><<<><<<>>>><<<<>><<<<>>><>>>><<>>><>>>><>>>><<>>>><<<>><<<><<<><<>>>><<<<><<>>><<>><>><<>><<<>>><<<<>>>><<>>><<<>><<>>><><>>>><<<>>><<<<>>>><<<<>>><<<<>><<><<<>><>><<<<><<<<>>><<<<><<<<><<<>>><<<<>>><<<<>>>><<<>>>><<<<>>><<<<><<<>>>><<><<<>>>><<<<>>>><>>>><<<<>>><<><<>><<>><<>>>><<<<><>>><<><<>><<><<<>><<>>>><<<<><>><<<><<<><<<>>>><<<<><<><<<<><<>>><>>>><<>>><<<>>>><<><<<<><<<<>><<<<><<><<>><<>>>><>><<<>>><<><<<>>>><<<>>>><<>><<><>><>><<<<>><<<>><>>>><<<<><<<>>>><<><<<<>><<<<><<<<>><<<<>>>><<<>>><<<<>>><<><<<>>>><>>>><<<>>>><<<<>><<><<<<>>><<<>>><<>><<<><><<>>>><<><<<>>>><<<>>>><<<<>>>><>>>><<<>>>><<<>>><>><<<><<<>>><<><<>>>><<<><<<>>><<>><<<>><><<<<>><><<<><<>>><<<>><<<<>>>><<>><<<<>>><<<<><>><>>>><<>><<<<>>>><<>><<<<>>>><>>>><<<>><<<>>>><><>>>><<>>><<>>><<<>><>><<><>><<<<>><<<<><<><<<<>><<<>>><<<><<<>>>><<<>>>><<<>>>><<<<>>>><<>>><<<<>><<<<>><<>>><>>><<><>><<<><><>>>><<><>>><<>>><<<>><>>><<><<<<>>><<>><<<<>>><<><>><<><<<<>>><<<>>>><>><<<<><<>>><<>><<<>>>><<<>><<<<>><<<<><<<>><>>><<<<>><<<<>>>><<<<><<>>><>>><<<<>>>><<<<>>><><><<<><<<<>>><><>><>>>><>>><>>>><<<>>>><<>><<<<><<<>>>><>>><<<<>>>><<>>>><<<<><<><<>>>><<>>><>><><>>><<<<>><>><<>>><<<>><>>><<>><<<><<>>>><<<<>>><<>>>><<<<>>><<><<<>>>><<<>>><<<>>><><<<>><<<<>>><>><<<<>><<>>><<<<><<<<>><<<<>>><>>><<>>><<>><<<>><>>><<<<>>><<<<><<<>>><<<>>>><<><><<<><<>><<>>>><<<>>>><<<<><<<<>>><>>>><<><<<<>><<<<>>>><<<<>>>><>>><<<<>><<<>>>><<<<>>><<<<>>>><<<<><>>>><<><>><<><<><<>>><<<<><<>>><<>>>><<<>><<<<><<<>>>><<<><>><<<<>>><<<>>><<<><<>><<<<>><<<><<>>>><><>>><<>>>><<>><>>>><<<><<>>>><<>>><<<<>><<<>>>><<>>>><<<<>>>><<<<>>><>><<<>>><<<<><<<>>>><<<>>>><>><<<<>>><<>><<<>>>><<>>><>>><<<<>><>>><<<>>><<<<><><<<>><<<<>>>><<<<>>>><<<<>>><>><><<>>>><<<>>>><<<>><<<>>><<>><<<<>><><<><<>>>><<>>><<<><<>>>><<<<>>>><<<>><>>><><<<><<<>>><<><<<<>>>><<<<>>><<>><<>>><<<<><<>>>><<>>>><<<>>>><<><>><<<>><<<<>>><<<<>>><<>><<<<>>>><<<<>>>><<<<><<<<>>>><<>>>><<<>>><<>><>>><<>>><<>>><<<>>>><<<>>><><>>>><<>><>>>><<<>><>>><<<><<>>><<><<<>><>>><<>><>>><<>>>><<<<>><<>>>><>><<<><<<<>>><<<><>>><<<<>>>><<<>><<<<><>>><<<<>><>>><<<>>>><<>>>><<<<>>><<><<<<>>><<<>>><><<<>>>><<><<<>>>><<>><>>>><<>>>><><<<><<>>>><<>><<>>><>><><<<>>>><<>>><<<<>><>>>><<<>><<><>>><<><<<>>>><<><<>>><>>>><<>>>><<<><<>>><>>><>><>><<<>>>><<<><<<>><<<<>><<<>><<>>>><>>>><<<<>>>><<>>><<><<<>>><<<<>><<<<>>>><<>><<<<><<><>>>><<<>>>><<>>><><<<<>><>>><<<<><<<<>>>><<<<>><>><>>>><<<<>>><<>>><>>>><<>>><<<<>>><><<<>>>><<>>><<<<>><<<><>>><><<><<><<><<<><<<>>>><<<>>>><<<<><>>>><>>><>><<>>><<<><>><<<<>>>><><<<>>><<<>><<><<<>>><<><<<>><<<><<<<>>><<>>>><<>>><<<><<<>><<><><<>>>><<>><<<>>>><<>>><<<<>>><<<<>>><<<>>>><<<<>><<<>>><<>>><<>>><>>><<>>><<>>><<<<>><<<<><<>><<<<>>>><>>><<>>>><<<<>><>><>>>><><>>>><>>>><<<>><<<<>>>><<<>>><<>>><<<<><<>><<<<>>><<<>>>><>>>><<<>><<<><<<>><<<<>><<><<>>><><<<<>><>><<>>><><<<<>>><<>>><<<><<>><<>><>><<>><<>>>><<<><<<<>>>><<<>>><<>><<<<>>><<<<>><><<<<>>>><<<<><>><>>>><<<><<>>>><<>>><<>><<<<>>>><><>><<<><>>>><<<>>><<<>>><>><<>>>><<<><<<><<<<><<>><<<>>><<<<>><<<<><<<<><<<>>>><<<><><<<<>><<><<>>> 2 | -------------------------------------------------------------------------------- /src/main/resources/day08.txt: -------------------------------------------------------------------------------- 1 | 131210223122034201100050105424523044130411422315401641602244345313413050154142511210232230010113310 2 | 311013023144242433041451004544121455454620031355066511426335055503430442412031400134421222323200231 3 | 000000231023234100542524312250523355415365261251616530425625664621215121033040340113311421124403120 4 | 112300444001303041405153523535126435661025243650554326352462442340031244522333142343310234422042101 5 | 011212224431121423533535502254210263641435632425025530513616353113250430340323201235001322302202112 6 | 202112313203021131220031503364123020251021060003210224226552235425544614111231232422312141400320413 7 | 200444200302403233024104523503202601044223254222154626546510545561110210263213430521241312421430303 8 | 004102313211311304304014024303123532011445320262467355722501012602644242025103522053013251103111002 9 | 304431411242103200225521661431265142636476475774766762762162363612154012423154144521032044323220414 10 | 431010040140112455335030032360262556456443775453334565671317716550430136651202313511214502241202330 11 | 043110240102454224516544224630616266622151633641416574141573472553733643035156556442540112231022330 12 | 344001014540504225063305264264244355672617755344543332512133532145451255143634431525512440433123411 13 | 113143353104203351103602240424523453451134364517415112721516225167142625124311653430211020140140033 14 | 342424105441510440330522410035715716774467613477463165551222537127247464353412121551250032130221402 15 | 410022504110015140563646535637544514224772163251875687177773617131666312426516653364620212210230313 16 | 211041303415212543246450027775344644111513854625668347224721545553312454276112266113006550101452023 17 | 122004120501250326115204667575557541115833886847258462846234567626374111773571244513654010011342043 18 | 301350253554662030333624245656331336684563833452867366254385562353677252735134322645443400000505332 19 | 245553522153032254411763514675764155633476526675325578425443428557445775637465473664541400534333232 20 | 322442130433125464663414766715267753434324555463784727253433653632683735371446657522664436422521413 21 | 331053445014305402543221122137356667287622582365352535357653444332458554753476126241266505611211314 22 | 132305431204423645643332442378265875383382785757384646688636277356473225215656144464631013404513545 23 | 053434505352362212362322254526384368455578549563664455533528348238256867477226167554313140041401143 24 | 203253201234236243775741122764852566323853963388779975599397567878847548722235622474163122662031025 25 | 104312526333250166615172668583238338723855457693768963653558894638325372838152126473716643303600351 26 | 300033325433641325623235156626436335535335388847464645964634799646746246766834574361166125456122351 27 | 120451143220054517417432222372537276354686677646995668437869779369928258788534513761754512104013333 28 | 533230405632016226763328844653255879987575353774339563955877645966846826356373371671142605624114450 29 | 344214406630075321522734573335883369387497369848437466643758736756744863635423414516662160242011015 30 | 153451326406137727666257774235355975796748378956899755978495944398847342278543532717554136340636511 31 | 024120564062654627732368525228793638475545556576899665765756673653534943354538526752326643260141204 32 | 412203404021155532277533544576338345978848669679757658576464434458866475384364264335343563643142455 33 | 524002156645642574176682747734737558688944465667846776898785795455858947565382387667331113015066451 34 | 113326321336515741227873667767747863748957949856994566445966947557698763647356484312144362112035661 35 | 434431122332456363585644236338986386449886459969898794477784876859584934744448487422233247433555125 36 | 554200316641747712525646475695585944855767864476587785657648489858488643964822385635771521136623046 37 | 052645555643364326224256887465763984499555456786655996459854588687984483443425342327437117204051333 38 | 324343644132162478234438235893544695988896887697765955598567945698759463346462838746232654576440215 39 | 462521542732624633374484345633767949856985955975898956868594588984946798839592836667471162150441636 40 | 304026636645461478734587878689834446685557768558895888866986985488496437548446368538251171154630512 41 | 101552533162346275323229586354898455686576855758557778659698597964984437888644223388226555216163411 42 | 226105531714231626224846935734356584745868996975697659897867984899744976774696753265736467266365363 43 | 545055625455625875447559864667957979647968997958989658678889877465465468549376486535366137522210053 44 | 232635236714655674743537653457749846596956975956766868889657789549747795675485857275755452342405631 45 | 336205405746366588226663467669498957868656755776686987887868569798659876543375846338247764415355462 46 | 155141051431316677636748574867789558675986588998679878868759877859999565576663475662435765647005340 47 | 232654031116753272825747668968554669668677998669769697669576866955596675964889624528726432263222616 48 | 046125447675236746223768668449879754576588858988996889696887777774597744733788336362244612637553514 49 | 332536552224754343576649855595666484566675788668896786768988988769569579999834385254427632624650030 50 | 460234671543372887673258495575749597595556689798666968989999596584956587675793948224673776637134104 51 | 542551244113357255333348985978787695699886688996687688989678979668986898375478542858365611723122044 52 | 436025232763148825472748645398546496988875698898869977888888759686766658866855938347566311743605100 53 | 041352435563335243486289834394558775588869568696989689688668679659674985985749374752633143335411605 54 | 645651613323411838844847964446478646777866888967786698987886597984667558653798334378662326523323316 55 | 453251236357514443523673467349998744667597789678969978697885696567487655374593857785247555435556045 56 | 125626067513221885878857759866589459898567986669876767888879686774468986669574866876872256777244651 57 | 061632634136353483585356796789964457467578899876878869685969688887694989435735523286834312755525066 58 | 340540044551242754354545465975657758685657898679669667967695977988789866474643553377742333237366424 59 | 263036352242131347425624853533685546887657969789867597887875857754448643936644634734681251565046213 60 | 521221014252416228623283758687657746455765599789696566599868586857544488568349257532612223352106620 61 | 551056515565333357773577346794385876469668655769579779597857875875996655775847823478875155335563305 62 | 033061351361131165452262574439975544867848695885675877665879558695985696596744556573716376424303526 63 | 051413453164367157546735796993358565449465886965769896875794786968869649574645557564453516434340036 64 | 522012306661675468522365554866664944774645598595765956997799788597559834845664822564673263773400310 65 | 303552112356652526736235234953975468449454679549576957655985777498534633999648453476132767604136505 66 | 430122433512263557743477259647593668744879856557445598497869544969574539864264546361414462664221411 67 | 454611134331624353887744383937939357467695869797758446748645646757337474547364356834125123550540011 68 | 205311422445771735787735535567487687866565989949866754567798798789335594675342524621173252621030620 69 | 104546314105111141478387738596677754347769889645474649778444486556868546667547447347454232412330210 70 | 211510511334467714212764237753489789395879446757548685444899995947477635333458277512623242566130511 71 | 424514361505346363172223743443943549786984455999479779995888784953977545326775458231326323010233504 72 | 533506406351652124743874362238244995393575576558499944857439678937793742537382237144513564254651535 73 | 353553630060426172733685862388329358887865467969479496565936757634945866336662814247313410506123210 74 | 513043225146416126342738452268474836363669357555484378683836437894548678424787336776674656521041540 75 | 244212015566607562363563332245262634763988943955763374435446957788627758456361246547173556634433112 76 | 120250204244540161453135477576577584679685399997348333875938895345463364665351151547550433420451010 77 | 255032316662364526536463566477643566873988833997886594683996985547474224255612136321352552052105402 78 | 104213510451031021331446321843388442357338856338535749438457984676336446257657625355006562000544113 79 | 541445315342554104332147175678875788872263746578533386785725742286747757363143223363002242403240300 80 | 250054145114114250444475636452277673763367766534832262225326442862356536367112741723425324561325551 81 | 333553132316232331166236712324478868545457256543258752567822364684454281563652476110466630243545012 82 | 105553252451444255251516625337126655486536656548634366772767853646345616517533725655446161145113520 83 | 025500320531252635012635251245524534532874583455824435258654245466851271721413732103556450032134212 84 | 122200331203513436340117775373456645476436746876327282863778274541722364747346544343564664345130314 85 | 441320433033461423032344434231635142515424736857357883276527554723561743647654233055512312302104530 86 | 204042200400054122313353457757245116453332283484837768668273767612521361442530615235236222154004311 87 | 221131430533350565006640022453717233151527675542578563343653736225637243741111121060442013041415121 88 | 143234105412111133566044252147564714332714531116676347152755116543123447451004602504145444453253433 89 | 320324355203321243353463365121412173726252341762654343152225445674136341343221112445214335524423100 90 | 202300215012154413506542142320154422415625511216416742722732625443456234050601116134422203301324102 91 | 101234204150414100204253404415020535764151322156246545763562327134761563456554466111402435010443123 92 | 431241014215100150231323511544033066474456542763733572523364653251210236631153343300102203501444131 93 | 042113314231102110430451540516134616441273312433773513644616643153262013464225504105041102141121134 94 | 011110441120300210525243055356613232510501653115647342112643545365615664665363430033144102220342002 95 | 022302231313301100120453535411263110120014430464665351336004360420564432406415043521343230142324012 96 | 113120323401112034331301531555663250242545635553155553026665545501304141205024555331305404432131422 97 | 012114144232442305005303300503446534353541113202335113010041055013513101112435052423113214420112332 98 | 230302124240141434221315223103536661161244640554266246312142632216301114101010004305311113412410032 99 | 023121121202444024012413530551503240563056005135401560566653254102253143503152511431441042423320132 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Advent of Code 2022 Solutions in Kotlin 3 | 4 | [![license](https://img.shields.io/github/license/tginsberg/advent-2022-kotlin)]() 5 | 6 | This repo is my personal attempt at solving the [Advent of Code 2022](http://adventofcode.com/2022) set of problems with 7 | the Kotlin programming language. 8 | 9 | I am trying to solve these on the day they are posted with clear, idiomatic solutions. That means in some cases I will 10 | sacrifice performance for a more clear solution. While I will endeavour to have these done day-of I can't promise it 11 | because work and life can get in the way. Plus, some of these problems can get quite involved so solving it clearly and 12 | writing up an explanation might take me longer than a day. We'll see how it goes! :) 13 | 14 | Past years, also in Kotlin: 15 | 16 | * 2017 - [GitHub](https://github.com/tginsberg/advent-2017-kotlin/) 17 | and [Blog Posts](https://todd.ginsberg.com/post/advent-of-code/2017/) 18 | * 2018 - [GitHub](https://github.com/tginsberg/advent-2018-kotlin/) 19 | and [Blog Posts](https://todd.ginsberg.com/post/advent-of-code/2018/) 20 | * 2019 - [GitHub](https://github.com/tginsberg/advent-2019-kotlin/) 21 | and [Blog Posts](https://todd.ginsberg.com/post/advent-of-code/2019/) 22 | * 2020 - [GitHub](https://github.com/tginsberg/advent-2020-kotlin/) 23 | and [Blog Posts](https://todd.ginsberg.com/post/advent-of-code/2020/) 24 | * 2021 - [GitHub](https://github.com/tginsberg/advent-2021-kotlin/) 25 | and [Blog Posts](https://todd.ginsberg.com/post/advent-of-code/2021/) 26 | 27 | #### Daily Solution Index for 2022 28 | 29 | | Day | Title | Links | 30 | |-----|:-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 31 | | 1 | Calorie Counting | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day1/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day01.kt) [\[AoC\]](http://adventofcode.com/2022/day/1) | 32 | | 2 | Rock Paper Scissors | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day2/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day02.kt) [\[AoC\]](http://adventofcode.com/2022/day/2) | 33 | | 3 | Rucksack Reorganization | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day3/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day03.kt) [\[AoC\]](http://adventofcode.com/2022/day/3) | 34 | | 4 | Camp Cleanup | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day4/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day04.kt) [\[AoC\]](http://adventofcode.com/2022/day/4) [\[Live Stream Recording\]](https://www.youtube.com/watch?v=dBIbr55YS0A) | 35 | | 5 | Supply Stacks | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day5/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day05.kt) [\[AoC\]](http://adventofcode.com/2022/day/5) | 36 | | 6 | Tuning Trouble | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day6/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day06.kt) [\[AoC\]](http://adventofcode.com/2022/day/6) | 37 | | 7 | No Space Left On Device | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day7/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day07.kt) [\[AoC\]](http://adventofcode.com/2022/day/7) | 38 | | 8 | Treetop Tree House | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day8/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day08.kt) [\[AoC\]](http://adventofcode.com/2022/day/8) | 39 | | 9 | Rope Bridge | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day9/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day09.kt) [\[AoC\]](http://adventofcode.com/2022/day/9) | 40 | | 10 | Cathode-Ray Tube | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day10/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day10.kt) [\[AoC\]](http://adventofcode.com/2022/day/10) | 41 | | 11 | Monkey in the Middle | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day11/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day11.kt) [\[AoC\]](http://adventofcode.com/2022/day/11) | 42 | | 12 | Hill Climbing Algorithm | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day12/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day12.kt) [\[AoC\]](http://adventofcode.com/2022/day/12) | 43 | | 13 | Distress Signal | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day13/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day13.kt) [\[AoC\]](http://adventofcode.com/2022/day/13) | 44 | | 14 | Regolith Reservoir | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day14/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day14.kt) [\[AoC\]](http://adventofcode.com/2022/day/14) | 45 | | 15 | Beacon Exclusion Zone | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day15/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day15.kt) [\[AoC\]](http://adventofcode.com/2022/day/15) | 46 | | 16 | Proboscidea Volcanium | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day16/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day16.kt) [\[AoC\]](http://adventofcode.com/2022/day/16) | 47 | | 17 | Pyroclastic Flow | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day17/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day17.kt) [\[AoC\]](http://adventofcode.com/2022/day/17) | 48 | | 18 | Boiling Boulders | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day18/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day18.kt) [\[AoC\]](http://adventofcode.com/2022/day/18) | 49 | | 19 | Not Enough Minerals | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day19/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day19.kt) [\[AoC\]](http://adventofcode.com/2022/day/19) | 50 | | 20 | Grove Positioning System | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day20/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day20.kt) [\[AoC\]](http://adventofcode.com/2022/day/20) | 51 | | 21 | Monkey Math | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day21/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day21.kt) [\[AoC\]](http://adventofcode.com/2022/day/21) | 52 | | 22 | Monkey Map | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day22/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day22.kt) [\[AoC\]](http://adventofcode.com/2022/day/22) | 53 | | 23 | Unstable Diffusion | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day23/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day23.kt) [\[AoC\]](http://adventofcode.com/2022/day/23) | 54 | | 24 | Blizzard Basin | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day24/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day24.kt) [\[AoC\]](http://adventofcode.com/2022/day/24) | 55 | | 25 | Full of Hot Air | [\[Blog Post\]](https://todd.ginsberg.com/post/advent-of-code/2022/day25/) [\[Code\]](https://github.com/tginsberg/advent-2022-kotlin/blob/main/src/main/kotlin/com/ginsberg/advent2022/Day25.kt) [\[AoC\]](http://adventofcode.com/2022/day/25) | 56 | 57 | Copyright © 2022 by Todd Ginsberg. 58 | -------------------------------------------------------------------------------- /src/main/resources/day03.txt: -------------------------------------------------------------------------------- 1 | zBBtHnnHtwwHplmlRlzPLCpp 2 | vvhJccJFGFcNsdNNJbhJsJQplQMRLQMlfdfTPCLfQQCT 3 | GPhjcjhZDjWtnSVH 4 | BNhHVhrGNVTbDHdDJdJRPJdSQQSJwPjR 5 | lvtsfbsqzwSnJcvjSm 6 | MftttFLftZMLgtgMbltMqZzbDNrTpVGhNWrDTrpTGNpZGZhD 7 | VSSHcTgTtTdtllZlzmmbljTn 8 | RqMqsFfQLLFLQFMMfRLPZLvPpCfWrbpmCbjCnfjlWmnrmmnm 9 | hqRDqPDRsqNHwtHSNBZtJd 10 | tNFDpDFrtdjfmjjjFmFFdScpZhZScTJgpHccHhMJgS 11 | lLzSlSCQqbsVhBghggBZgCcJ 12 | zRLVVLQnvQqVVzRldfWrwffjjdwSdfjv 13 | bpWqqqWvHBpwGBCCRl 14 | hJdjdJFQqdBBDMMC 15 | tFFzJZFtJSqtZJQsWLbNSTnffHfvTH 16 | lFhRZhFjPlqMlJqZJlJcRLwrLrwStRwtsVVtVSrgRV 17 | WcpDvDfBmpDHzWBDbpbmWmNVSSTzLTtrVswgttVVzwwr 18 | pbWfmGBpHfDmWnvvGbmWnjjMqPJMlMFPdGcjqPqPhP 19 | NjFNRlpVLFCSSlbBWWfw 20 | pssPZQQsMnzmtnQPttzDBbBJBcrrJWbrZSBJSbfC 21 | QTHPHspMNGHdhvRR 22 | QfPdSJfFJmthSthtwbsNLbPLlLTLpbvP 23 | nHnMBnZqqgBMnWrZMqnZVcbCqRwNsvblRwppbllTsRNp 24 | nZHBHznMnWgcrnVBtjFdfmzQNtNddjNF 25 | hFhfPghppPhpRNhzsjsvHVzjpsGnWz 26 | tTjlCCwMqtdMjMctGJWHwWnVwWnwvWGs 27 | rZdrjBBtqdCtlcdgFZQLfhRLFSgRNP 28 | RDHSWrJWffJFlJCgCMCDjCvzjPMP 29 | QtGTndBwBtNzBVjBCMgB 30 | LdwwMpTdwsRHsqSHqHJl 31 | RfsfzvLLFvFzCSvSbDsTpTGMPMZPPTMt 32 | jqWBjwBBNwWqwPGZbTwVwVtD 33 | BnhgglhhNNngqjBjHNWrZLlFLSCJSFFCCQzQvQFCFF 34 | HLvLDQbvnDQDvbHTLhntSnGBSlfGldddcmfMMf 35 | NgFjZjrZZJrlfJfSVcBJGc 36 | scWCNFZpsjzrDLwLhbQzhQwD 37 | SlqJlThDPqpwSTwhcbDdbWDbZGcZNcDb 38 | MsnWWjHjvLvfscjjgdzNdbgbcc 39 | vQQvWVQFLLHfHVBWfsfmFFpJRhhSplqlRJqpBwlqTCPC 40 | DZbDzzZDjQbPGZFFSSgSlFCzTgzm 41 | qLnvwvhddrqMrwrCTLLFJjmtSlFlSH 42 | VdhvsWqdVWvvRhsvqbpbPcZfPpjZGBQNRj 43 | mJNtNFmzDZtzdzrLtwwRqJSchgfGcRfwRB 44 | pWpjQjCTQnHMWCCpjQpHvTqcwTwScfRcBcSGBRThwS 45 | MQHjvjVCCqsvljWnVQzLtNPZzmzLVNLddtPN 46 | QVRPRVDgsRjLssnL 47 | TTGDJDJfbfLHSnsMWWbs 48 | qGqqTFFDqgQgQQQq 49 | nlMnRRjbMjCdJVQJCZ 50 | nGqfLwfNLFNLnPPGFVVCdVGZJtCtCCVzJz 51 | LHHfPNHnPqqLwqPqDPWfNFvMglbhhbMgmclgcllDmgmrcl 52 | cLLWWSThtdLpRcddcgPRZFDMCVPPMCCPCPCZ 53 | NfGbGNzrBNffGNJjbPPZsZmZZPmDHpMH 54 | zlJBfzlQzNjNjfJcpwSdvWhcvLwQWt 55 | cVVQfVCJVrVcTJnfNvlDFmDrmlvrFWlL 56 | snZHpMhZtMbtPNvzHWWvNFNvNW 57 | gppnbbbRgMnZbswRqRwbqTcCCSTCJJdGjgfVGTdcCG 58 | jplgNdrHrrNZgdHmlHNJHddlDSPPSTlzTSlTSDSzCQLfzf 59 | vscvWWWvGWGGscbFMpRWFwQTPzfLQwQwPfLbzSzzDL 60 | GvGBWpqcMVRNNZHgdHdtBJ 61 | LchbZhjjZFjwSmPRqRffqbdtggdR 62 | vWHMWlHJdGqtRqHV 63 | MvzCJlnMnlTNnNNLLdhjjCdjjhDjjL 64 | FNCllHFvCGvwQcPQJfgfmwgh 65 | zjtRpbDLjtsrzbLLQmfBTgTBQQfhbfQB 66 | WLgqRzqsrWvFGFZFZC 67 | qjLlNcLjcNWpQLlQMmvmhCvCgsMZZghj 68 | tGSDJtRGJzHMMGDVZCfvmfhzmZZgZsmv 69 | BSSRDRHBGHtSSSbGJSwHbNcLQddqMNlrqcMQMldBWc 70 | JSfctrtctDpszHvzVQHr 71 | glCWjhWmFjlmlhmdWPhVVznvcHjszbvvpHvznv 72 | FgBmFhCBCGFqglgmhCFmSTSRLJLLZfSRJcDSGMtM 73 | vZGlFFtLMLdShSSShRVtVf 74 | rQNvmznWPNCPNsrCsbWbsPCvjShhhfHBBHJjSJRhjSRnHhSj 75 | mCNsQCmqszNcQzrzrrzWvGgGMgpdFpMLlFZGwcLDdg 76 | QJRJQDlcqLlWbNGL 77 | HCnwwsCrnstLWqtWNgZNgg 78 | rsnTrTCHTnnVwnsVPqqDQcRjcczMPvPRzM 79 | qCzjqnzVdzrdhnhddDbDBMPttcGBDBDPnc 80 | sZgRQWHgWHHLsgsRRZsJbpJlDcDGNcTDFtGNFFcJNFPBPBTc 81 | WggbRQSRRgRSsWWmbHqvVffVwhzvCdmfhmdV 82 | lhqWcNpQGcNmmHmNPWCsQzQsgrQrBMCMbMVM 83 | wDLFFDJvSFFZRDZSzCrzTzsRgVWbCrMW 84 | dFwDtZfdjFZWFFfmHGPnPPmqfmPNcN 85 | lcMRNJRGGLJnNVFbVrwrwZrD 86 | tjCzQjQhQwgWFShVFS 87 | ffHQsQssQTzBsPnLpMPRwsJP 88 | MQSMSBSRFMQLJChLChjTBh 89 | WmVlPrwnpwDlflNpDrNnDlDwThJCCdLJhhdhCfJTccGjvscd 90 | gnDVnNnwgglwDwptSZFzgQHqbjZgZZ 91 | nwBcFgwTDcNrpZMD 92 | WQWCLZmvhMRvNjsNSD 93 | CGGWmZGHHhtVzHbTqgTdbgzz 94 | RmcTCwvssRbsThTcVRJJfSPqfJwJFqfjfMFq 95 | zQNZDWtQlDZGBQPfFQqjJLjL 96 | rrglggZGWnrnrrHlDhsbsPTVCsCVsTRpHv 97 | wFGfzSvCPGttSzqwmtqmvvPRDDRCWgWWDTBTMcBcBWbCRM 98 | hVJJHQHnpWnDTNnnDb 99 | LJsVVdhQqvmdbbSf 100 | srlJztzsVVsSsVtRlNllTWzzmqGhqWLPCDCgmChPLDdqCmCP 101 | bZQMZpbvMBMgmDGmZLSPZd 102 | MpScMSMpvfjMBcBcfMfSBnzlTjssNszrNrtlTVzlzFVN 103 | rCtgrgClprGGClnJCZmwtMjZRjbjjcjZQv 104 | PWVfBHWPdbNfbbRmRj 105 | sPsVqFPsHWLhBVVqHFqPVddWSDLJgpTCnnrRRLGpJSSTRrgT 106 | zjqpGjrQjGqSHCVvCrRZDN 107 | cTdshMhdmcMNmddRHBhvCCBCCvHZDC 108 | JTmTmJnLTdwzNQpPWJWgpP 109 | BmpZmrzZnznHbpprSbQSQbqdSVqbPQcV 110 | fRGTGJZRTTDwJTJRGDfgJgNFlSSFcldfdccFVlPlFFQPSQ 111 | GvTTTZZLmsntzmCL 112 | VhMcrmbhvzMSnhvftbRbllLtglBBtf 113 | HqqqJqDqPjJPNjjDVFDZCdqBtRtGBGlGRfQQgttQfHlTQl 114 | pCZJPqqZpmhvhpVh 115 | dWLBJHJhGJGMBJRcDLDSQsSQpvcR 116 | ZlnnPqglblfRRpSvSsnz 117 | sPTgZVjjmwVTljrwTTlbwVGdJhBNNdFdMGNHHJMjBNFN 118 | FhFrfbfgbLRdfqfrmvDgLdjrcQtSNStHHHQlSjJJPllt 119 | CnspzZWTpCnMVzzZZGZRCzttHNjNlQlSNtNlNjVcjlQS 120 | GCZsZBRwnvwfbqwFwb 121 | bZnJFJgLFRnqQZqJQJFQGpCLNcGlLllClNtccjGc 122 | rVfvwPDhPHGtlcbClr 123 | mBhshsfMvBvqsQJdTbgnqQ 124 | jgWHqMSWMGqWjWjqbWGJQDfVqLfrfDfJhVLfTr 125 | pPplwsRZPFZFtLhfwgfwrhJL 126 | zlRsdgFcRgmjdBCMHdjHWB 127 | qJSGJSPQWzcprtQZtt 128 | mBMVfsNBnZzcNtcc 129 | LMLBsmMlvBgFsghVVvfgLBvbJJSqgGHqPGPtCWwbJHqCPG 130 | ZvZLcdMGVMlHDvDpvqhH 131 | NNSrQNbJbrTnnWZDDZqqhqpW 132 | wbgNJrsrCwwJQZbsrJBFzjCCdzGdjcGzMdzj 133 | JbVmdVLJJJdQMnzmmMgHjPqqjNgvqwngHNNP 134 | ZfffDZZsRpcpRDcCRrlpplcWSSgwgSwjvvsjPSwhNSWggh 135 | cCtfppZrpjtMMmdQQTLz 136 | TtbnmbdmTmgTlPNhqvqj 137 | wrwrLsVZRsJJJsfHjvPPWfhjHqRN 138 | sDZwDvsCCQLJZQJQsMCMzZBtSMpndcSFnnSBFtSBmdBc 139 | mWFTZdmQdZFrFQbCRsrspjSjnvCLRS 140 | GwlDqcNHDzwGfHSRqCgJsSpnvpSL 141 | NGlcNwHLLGfDDHDhDwDcwVczbPddZtMFWttWWtdPPdQdhPWd 142 | mnfcZgcdZqnqdfFqPmHfhqsbgVMCJNMtvCJtMvtblTJtvb 143 | rRLDDjPSjjPDGBQSBNbtLVtbMNNJlTMtbl 144 | SzjDDzRRpGQDDDPHzdsmnnhsqcqdFq 145 | ZDGNRDGjSdwnnmnsVNsHJJ 146 | tMBWWrddLPLhvWTTPLccvmmbVpgsJHmccppJ 147 | ClPrtBWWrhrFLBPlCRzjzGqdRzjRdRGZjF 148 | csTRNQNJcNBDLfhfMf 149 | qGmWpGHqrqPLChPRhVFPDD 150 | tgHrtnrrJnZRTZcv 151 | FLqrfmLDrqCmqjTqcbGqRTGVvb 152 | FMtWMSWzzFStJzPzhWzhQvTvHVjjTjHTTHvbHc 153 | PgtWWstWtSpZWPzWwnrBsdBDdFLfllLlfC 154 | mThbMDMQDCDbwLqWpqPpdhwR 155 | zgrcffgHNZltZSgHLsRsLLWRWgLqppsW 156 | SVlSrfSHlSSVlrJfVctlNDMCmMFbnbRDbDBFJFbBRM 157 | PrBrWqtRPdBLLrBwqpswgpwhgpnZhhzsgw 158 | FTFRSVJQVJflFfQQgggGMZngGQZszZ 159 | TbmfFJFSDFblSTDSFFbmVSDrPLLWtcmBqqRmBtmcLtcrjP 160 | DjPsMwDjLVVTsvNNRTNTRT 161 | ztdQQHqHlFNtfRNNNMgg 162 | FzhMhHQlDcCrhCCc 163 | zSHGzzmHgnnMDLTNTG 164 | lPVBtvhQjpNSMWTLBD 165 | VCftbjvbVCfPbZwsJsrSgSSZwC 166 | CbwgmvMnmnCwMmwRQqJBGBgHZHpJHdtdZpJt 167 | zVSlNSDlrzNhqlNTScDzVWfBBZZZZGBstGsdsWFpdHdJsW 168 | NDlLzhrVcqRPCMRwLLLw 169 | TjTHHLwnLjVlTwLjgVfvsFvDsdWfvDvFMd 170 | qbRRRpmpcmDcczppztSqSvWFssFGfWdMvfQWdfsG 171 | RZpqDBmtrzhzphjTgjHlnwjgJhgJ 172 | dLmMgdgzwDLzDWFhBWvzFzzBZJ 173 | tTVcppbSTfstTMMHfTbhBchhJFCWcjWBZhjGGB 174 | SSSSNbsNRpRRsRrfVHfRpNtlPgQDLPdMmlDLlrPnqPdPLl 175 | qqbTCSqdqqFZdRLZhwhZ 176 | HWWlHtlrBfGtVssnsLnHfJVPPMMFzhPRwMPwFhzPZzPMGM 177 | nfmtsrlsnrfVnHJrVBWlsVfgbbNTNSvmvvpcTjLjLbqvvS 178 | GGhFvGPFcThqffPdnfNLqZZCSwtQSwZpwQQBsL 179 | RglMRrJJgHBCBZSQQpdr 180 | WmbRHHbzDgJMDzRDMdWmWHzHNFFvvGGhnvVvvfcvnFfcbvnT 181 | QsfQmsLfZZZcshnJ 182 | dSgdWgSVVFvzSpqFdqTgWRHbJNcbZNCTJCNNZRRCCh 183 | FcpVjgDvVVFdVWFvzjwwQtBMLtBBGDwftPrB 184 | rqsRrHsvsPqswNcJcNJrnnBrNn 185 | bFjgGFdbVRNNnpRQpV 186 | GSthhggGDSvMRqtHvMfM 187 | ZwVPgMsgVsGzVsRZpgpzzgpFMrNbbLFrDLFFrrSDLfrNBN 188 | qvnjBhQhntbfDLrF 189 | CJlHHcHcTWqvpBdsWRpdPdgs 190 | BjmTDjJBCBWrgQRPFlWWlW 191 | dHphshtdtVHVhpJqspdvRrqFPgrLPPFPrrRPvQ 192 | sdMsMtStVszpwMzHjJGjCcZjmScNfCDf 193 | DmGdDffgDSDDdJstqdJldlRt 194 | MhnvMCZCbbZHMvsCHtrcVrPjJcRqVtlt 195 | LsQbsFZvZhQzZwhQWTNgBWpNwSGpTmfS 196 | RRJQnCzbZZLTZJCBtWvFtsfqBqtfWb 197 | prjlChGNldGNdlSVMhWfqWtfsvwvqsFtdtsq 198 | GGjNDNhpMGMGVhrnZZTzcTHCCJcDHc 199 | RmbMmjgpPjMBsBMfchhVsc 200 | HwFWFTztSrtFpcQvBsSqVscBBC 201 | zWwnJFHtWWHDgbGgdpGpnl 202 | mnbWbRRLRFnmmWcCDTBVwCDBlwNW 203 | ggJPtpdHGfdZtMHgtZgVPPBCVsPNBcsBTTDDCC 204 | hpvJJTpGhdhtJdMHqvmmnLvSbmnFnRFm 205 | WWtrWrNgVbRjMrQCNzqJFwQJFNTJ 206 | LdHPhcdchQQssLzJrz 207 | pBccnHpnrrcGHnnSlWjnRMSlbt 208 | NMMfNFnZgMVThhTMcgTDJDJjsVvvJJqJmHsqHG 209 | LQpwwprCQzBNBdGjGjHswswdvm 210 | CBCzzCrbWbSlNQnTRgPPfFRWnfgc 211 | RFwHVQRwFgTQSFVhdsdHsBdDBnnqnq 212 | LGftLtPGGMzlNrhlPqPsrJ 213 | fvGpWpMtccpTwwpRRQhh 214 | TTJCGdTGtZRQQCnzcnCv 215 | FWWHPSFNFbDbDDqSWnVmLRRjRRQLhcmLjS 216 | qPwPWwFppbwggGZGfdJZgdnGdd 217 | zSTWzrzWTLWpCtCGpqqGgplc 218 | nZWwsJVZZBnJHJCclHllgtChgCgc 219 | DFnVBJsFssVVFBFnBdfvjDSmTMWzrmMfRmTv 220 | MJmgMssrsggqqMVstbwTcTbPbTTwThmw 221 | NRBBGRjHVRRcRbCp 222 | QnSfzLWzNHzNVQQVjrglJMsMFvgJdFWrgZ 223 | ggLLGnhgnPvJHZnN 224 | VBtmVSldbSBVlcNPHvjmNcwNZZ 225 | tdWqSVSSBztVWGrThLhfrfvG 226 | TDqrjdSwLqDppdTCdzPBFmmjQmhHFPFQhPFR 227 | zlGbMcVcVtsPHFRhWRRsPF 228 | btgvlVVcDZZZqgrz 229 | DgwlgbbFDDjjPTHDrmddPhPV 230 | WqtMBBtQsttMNWQBqsbJpGGzdPdTHLVmTzJhmTPhHHPTmH 231 | qQsqGZNQtZGMNsNtZpFnjnCRbZffwwSRljFf 232 | gMdFLCdnMZCTFFCqnTgWLCHfSgPgPHStcQQmfSBBSfHg 233 | vrwwrwzbGjjswjvhGGsjPQmqRmHPbBtcBQtqfmcH 234 | qzJllVsGVGljjsrzwDzhwzDGTddNLFnZWNdpCVWTNTZTLZCF 235 | LtwMhDtctwbwwppdWBJQJBWPvPfDfqvG 236 | FTzrNrgSRFrgzFRHNVFQJvlqHjBvQWlQWqPBfq 237 | sFgNzmVmNzgTvVTMwhMhstMwZtsbsc 238 | MrBDQVzzlrvhQzQrDMVQrzrzgRJnRRwwRbwSwwVRRNSgwwwJ 239 | qFTPTvfTHcqqncpcwR 240 | LmtdGGPmTPGCTLHLWsZMhvZMMMzrzzdlMQ 241 | ZVNpjfpZNpfNgNjzNVfWtnbbWmBHtsZWBSZBGS 242 | MrDrQvvDrPLDMvFvdmBGGsBBCtsHrnrGCm 243 | ltRMwLLDDRlvQwvlQcwhqfcJNpgzjJpjhJ 244 | sRRRlRbcFbBBdnFBwCGppNvGrTCDDGVNlr 245 | PPSLQzHjzZZPLZPjgTNTgpCbVJvGrNCTGr 246 | ZLHHPQjhQmWWSRRnssdtbnmfwF 247 | GRwrMrHJGwJPGWsgfqQgsc 248 | VbTvLQCZLSWWsgWf 249 | TVDvVCvppvTDmzZVTbZpTzBBNQQQJlJBBJBNNJmRBwRH 250 | shJRWJsjZGNjSTrjFS 251 | dMLCddggldQzMCCVgzVVLmLvTwNFFSqpNSqSbFGSqTTpMTFN 252 | VGQvVglCLcVzgdddCDVvlsPZRRBDJPHZWZZnBsWJRR 253 | CrwlwhRCMrswnsHBFccHHWFc 254 | QJTmtfQgLtzQfLQfdPcWSFHHDDSpcFpFBg 255 | jTQTqbfQfmLbLQJbJrRCWjljZGjNrZlZlC 256 | JmthDmLShtJmHphphJQCwjdjdFDzFgzFdgdNlC 257 | sbMTVBrWMbNvVMnsWMnVzjsjwCfjFgfZzfdgdzlj 258 | NvqbbBcMMPPSqLSpGGthmp 259 | RfGWFHlPFFNWGFZRZBjvwCvzBwhhrvvjzmrr 260 | sLJSLMSTSJTbStJtMSqSqbpMrvmrzWdvhmjDCzzwrrpjdDDv 261 | SbQqsqsWcZPcQGFG 262 | BjqbMqMVBsfqGqFqGLmF 263 | ZZQbQPddPcwbPnRQltdtQZdnmFNrvfhGrhrWWFNWWtmNFNNW 264 | dJJQccnRPpcbQcMHsSgSMsDMTJSg 265 | WWGBBvPflnWbBWhvhbPvNfnnVCFZmVRVZmVGMVwRLCCCGwVC 266 | gjszgTMrgzgqCRRdmJRjJLVw 267 | grzQHzqczMSzqSHcgQsqPvPlbNblpPhhPPbHvnhp 268 | sJDDNWdnRLTTvqwSFPCmLCCrCq 269 | thzplgfjglflFcbMclpppMfcwPqCZQCmqCwrzCqmQmHSqPqq 270 | MhcpFBMBlhjbBTdnNJWvNvsvBd 271 | czwwghnWWfcfgwfWthfrvVvrjdrdvDDVrbzrLF 272 | RHPPMRpQPRMPPJRjJQsZsrrvvJBDDVDVdFqrBrFdBv 273 | smjMsGZHRsHSmRQNGHPpSTwwttCflwngnChcCtWW 274 | bprrrwrtLDtrWwrQjRDQDbPPVHVmmmmHNWlPlVNPZZlv 275 | hqqhfnBCTfnnhzJwzsqzfPZZMCCVZVHHFvZMFvZmlC 276 | TzhhdJTqJzcBdJJnzjtQrLdjwgLtpbgrLQ 277 | qzQvzzgWSCqtqqGpddGc 278 | jLrZNZhZrNRLHNffhrjNjNdtdZtGcPFwFwpbGwbVpdwC 279 | nHnhrLNCCMHmhHBMhrzvgJvsWSWMWzzWzSlv 280 | RzcbzdRFzbbzbzbFdZFTHMZPhVhVQMLrlrQPhLZlMM 281 | BNGfBvsNttVmMhlMLm 282 | BwGjpllswfjwpcFDWcWcbpdb 283 | SjzpswrLSDjVSpwlmZJBTBdNJLvBNvHQZT 284 | rCcCtbqgCfthggtbGGMqqghqZQvvQTBNJQHQZQTcZTJFZFFd 285 | CggGMtqMfWbbGghPhhbCMtmsSppSspjpmWzjVSWlVrrm 286 | PmWTPThTQWnLWQFl 287 | VNcSVfMbtsddBQNnNpdl 288 | sSjctwjVSzzccjgnTnDTHRDhqjRR 289 | WfMWfCNCjWWHNTccMjRjfRcMbqSwfVwqwsfGGbssrJSrswVw 290 | llLFQLlvlPFnhQBPBZQBqvBwzSzGGhShJVwShmsJbbmzSG 291 | lnPqvQZBFFBnnpgplFvtvHDjTdcTjTMMjCRNCMWgRC 292 | rprFNFFNjNLmMdgcqL 293 | BvzCQQbBQgffsDbvVHMdbcVqmLVqlmqq 294 | JvJCzBDJwnsRnQDszCBnnnQBrjZPjFpgZFTFZRpTrpZFGFtT 295 | wBHQQZHVCcpwDgdZdMsZjvMZFn 296 | GPSzlNlJLfzzzvsWdWLMmFWLMM 297 | NfqGSfrTNzRTqJfRbptQHFQFrwrFHBHw 298 | sNjVMVNVMzPzQgghcMsNzJtjSJtTFDTJtJnnDLjDnL 299 | CHwrdCpvCrwrWdpZqcpFttJSFJTLLHLJfbnbfD 300 | qrlZCwlqZrqqpWdlRqCRqdqcVNsVMzQzmNgNPBsRhVQVVzMs -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 Todd Ginsberg 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------