From 8a9f518b5ba02e8a7fa0d347af5200d5276c5128 Mon Sep 17 00:00:00 2001 From: Ivan Reshetnikov Date: Thu, 19 Dec 2024 16:46:37 +0500 Subject: [PATCH] Refactor day 2 of AoC 2023 --- advent-of-code/2023/day_02/.gitignore | 42 ++++++++++ advent-of-code/2023/day_02/README.md | 81 +++++++++++++++++++ advent-of-code/2023/day_02/build.gradle.kts | 18 +++++ advent-of-code/2023/day_02/gradle.properties | 1 + .../2023/day_02/settings.gradle.kts | 2 + .../2023/day_02/src/main/kotlin/GameHost.kt | 61 ++++++++++++++ .../2023/day_02/src/main/kotlin/Main.kt | 12 +++ .../src/main/resources}/input.txt | 2 +- .../day_02/src/test/kotlin/GameHostTest.kt | 30 +++++++ .../2023/kotlin/src/main/kotlin/Solution02.kt | 81 ------------------- .../kotlin/src/main/resources/day-02/test.txt | 5 -- .../kotlin/src/test/kotlin/Solution02Test.kt | 32 -------- 12 files changed, 248 insertions(+), 119 deletions(-) create mode 100644 advent-of-code/2023/day_02/.gitignore create mode 100644 advent-of-code/2023/day_02/README.md create mode 100644 advent-of-code/2023/day_02/build.gradle.kts create mode 100644 advent-of-code/2023/day_02/gradle.properties create mode 100644 advent-of-code/2023/day_02/settings.gradle.kts create mode 100644 advent-of-code/2023/day_02/src/main/kotlin/GameHost.kt create mode 100644 advent-of-code/2023/day_02/src/main/kotlin/Main.kt rename advent-of-code/2023/{kotlin/src/main/resources/day-02 => day_02/src/main/resources}/input.txt (99%) create mode 100644 advent-of-code/2023/day_02/src/test/kotlin/GameHostTest.kt delete mode 100644 advent-of-code/2023/kotlin/src/main/kotlin/Solution02.kt delete mode 100644 advent-of-code/2023/kotlin/src/main/resources/day-02/test.txt delete mode 100644 advent-of-code/2023/kotlin/src/test/kotlin/Solution02Test.kt diff --git a/advent-of-code/2023/day_02/.gitignore b/advent-of-code/2023/day_02/.gitignore new file mode 100644 index 0000000..5d520d1 --- /dev/null +++ b/advent-of-code/2023/day_02/.gitignore @@ -0,0 +1,42 @@ +.gradle +gradle +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Kotlin ### +.kotlin + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store diff --git a/advent-of-code/2023/day_02/README.md b/advent-of-code/2023/day_02/README.md new file mode 100644 index 0000000..d0fda95 --- /dev/null +++ b/advent-of-code/2023/day_02/README.md @@ -0,0 +1,81 @@ +# Advent of Code 2023 day 2 solution in Kotlin + +## Cube Conundrum + +[Task page](https://adventofcode.com/2023/day/2) + +You're launched high into the atmosphere! The apex of your trajectory just barely reaches the surface of a +large island floating in the sky. You gently land in a fluffy pile of leaves. +It's quite cold, but you don't see much snow. An Elf runs over to greet you. + +The Elf explains that you've arrived at Snow Island and apologizes for the lack of snow. +He'll be happy to explain the situation, but it's a bit of a walk, so you have some time. +They don't get many visitors up here; would you like to play a game in the meantime? + +As you walk, the Elf shows you a small bag and some cubes which are either red, green, or blue. +Each time you play this game, he will hide a secret number of cubes of each color in the bag, +and your goal is to figure out information about the number of cubes. + +To get information, once a bag has been loaded with cubes, the Elf will reach into the bag, +grab a handful of random cubes, show them to you, and then put them back in the bag. He'll do this a few times per game. + +You play several games and record the information from each game (your puzzle input). +Each game is listed with its ID number (like the 11 in Game 11: ...) followed by a semicolon-separated +list of subsets of cubes that were revealed from the bag (like 3 red, 5 green, 4 blue). + +For example, the record of a few games might look like this: + +``` +Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green +Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue +Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red +Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red +Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green +``` + +In game 1, three sets of cubes are revealed from the bag (and then put back again). +The first set is 3 blue cubes and 4 red cubes; the second set is 1 red cube, 2 green cubes, and 6 blue cubes; +the third set is only 2 green cubes. + +The Elf would first like to know which games would have been possible if the bag contained only 12 red cubes, +13 green cubes, and 14 blue cubes? + +In the example above, games 1, 2, and 5 would have been possible if the bag had been loaded with that configuration. +However, game 3 would have been impossible because at one point the Elf showed you 20 red cubes at once; similarly, +game 4 would also have been impossible because the Elf showed you 15 blue cubes at once. +If you add up the IDs of the games that would have been possible, you get 8. + +Determine which games would have been possible if the bag had been loaded with only 12 red cubes, 13 green cubes, +and 14 blue cubes. What is the sum of the IDs of those games? + + +## Part Two + +The Elf says they've stopped producing snow because they aren't getting any water! +He isn't sure why the water stopped; however, he can show you how to get to the water source +to check it out for yourself. It's just up ahead! + +As you continue your walk, the Elf poses a second question: in each game you played, +what is the fewest number of cubes of each color that could have been in the bag to make the game possible? + +Again consider the example games from earlier: + +``` +Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green +Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue +Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red +Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red +Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green +``` + +- In game 1, the game could have been played with as few as 4 red, 2 green, and 6 blue cubes. If any color had even one fewer cube, the game would have been impossible. +- Game 2 could have been played with a minimum of 1 red, 3 green, and 4 blue cubes. +- Game 3 must have been played with at least 20 red, 13 green, and 6 blue cubes. +- Game 4 required at least 14 red, 3 green, and 15 blue cubes. +- Game 5 needed no fewer than 6 red, 3 green, and 2 blue cubes in the bag. + +The power of a set of cubes is equal to the numbers of red, green, and blue cubes multiplied together. +The power of the minimum set of cubes in game 1 is 48. In games 2-5 it was 12, 1560, 630, and 36, respectively. +Adding up these five powers produces the sum 2286. + +For each game, find the minimum set of cubes that must have been present. What is the sum of the power of these sets? diff --git a/advent-of-code/2023/day_02/build.gradle.kts b/advent-of-code/2023/day_02/build.gradle.kts new file mode 100644 index 0000000..6397ac9 --- /dev/null +++ b/advent-of-code/2023/day_02/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + kotlin("jvm") version "2.0.21" +} + +group = "space.comfycamp" +version = "1.0" + +repositories { + mavenCentral() +} + +dependencies { + testImplementation(kotlin("test")) +} + +tasks.test { + useJUnitPlatform() +} diff --git a/advent-of-code/2023/day_02/gradle.properties b/advent-of-code/2023/day_02/gradle.properties new file mode 100644 index 0000000..7fc6f1f --- /dev/null +++ b/advent-of-code/2023/day_02/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official diff --git a/advent-of-code/2023/day_02/settings.gradle.kts b/advent-of-code/2023/day_02/settings.gradle.kts new file mode 100644 index 0000000..179d9e0 --- /dev/null +++ b/advent-of-code/2023/day_02/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "day_02" + diff --git a/advent-of-code/2023/day_02/src/main/kotlin/GameHost.kt b/advent-of-code/2023/day_02/src/main/kotlin/GameHost.kt new file mode 100644 index 0000000..bac0701 --- /dev/null +++ b/advent-of-code/2023/day_02/src/main/kotlin/GameHost.kt @@ -0,0 +1,61 @@ +package space.comfycamp + +import kotlin.math.max + +data class CubeSet(var red: Int, var green: Int, var blue: Int) + +// Part 1 +fun getSumOfCorrectGameIDs(text: List): Int { + val games = readGames(text) + + return games + .withIndex() + .filter{ el -> isGameValid(el.value) } + .sumOf { el -> el.index + 1 } +} + +private fun isGameValid(cubeSets: List): Boolean { + for (cubeSet in cubeSets) { + if (cubeSet.red > 12 || cubeSet.green > 13 || cubeSet.blue > 14) { + return false + } + } + + return true +} + +// Part 2 +fun getSumOfPowers(text: List): Int { + val games = readGames(text) + + return games + .map { game -> + game.reduce { acc, cubeSet -> + CubeSet( + max(acc.red, cubeSet.red), + max(acc.green, cubeSet.green), + max(acc.blue, cubeSet.blue) + ) + } + } + .sumOf { cubeSet -> cubeSet.red * cubeSet.green * cubeSet.blue } +} + +private fun readGames(text: List): List> { + return text + .map{ line -> line.split(": ")[1] } + .map{ sets -> sets.split("; ").map{ cubeSet -> parseCubeSet(cubeSet) } } +} + +private fun parseCubeSet(description: String): CubeSet { + val cubeSet = CubeSet(0,0,0) + for (cubeStr in description.split(", ")) { + val (cubeCountStr, color) = cubeStr.split(" ") + when (color) { + "blue" -> cubeSet.blue = cubeCountStr.toInt() + "red" -> cubeSet.red = cubeCountStr.toInt() + "green" -> cubeSet.green = cubeCountStr.toInt() + } + } + return cubeSet +} diff --git a/advent-of-code/2023/day_02/src/main/kotlin/Main.kt b/advent-of-code/2023/day_02/src/main/kotlin/Main.kt new file mode 100644 index 0000000..8db37f2 --- /dev/null +++ b/advent-of-code/2023/day_02/src/main/kotlin/Main.kt @@ -0,0 +1,12 @@ +package space.comfycamp + +fun main() { + val resource = object{}.javaClass.getResource("/input.txt")!! + val lines = resource.readText().trim().lines() + + val res1 = getSumOfCorrectGameIDs(lines) + println("Part 1: $res1") + + val res2 = getSumOfPowers(lines) + println("Part 2: $res2") +} diff --git a/advent-of-code/2023/kotlin/src/main/resources/day-02/input.txt b/advent-of-code/2023/day_02/src/main/resources/input.txt similarity index 99% rename from advent-of-code/2023/kotlin/src/main/resources/day-02/input.txt rename to advent-of-code/2023/day_02/src/main/resources/input.txt index b768962..4a67744 100644 --- a/advent-of-code/2023/kotlin/src/main/resources/day-02/input.txt +++ b/advent-of-code/2023/day_02/src/main/resources/input.txt @@ -97,4 +97,4 @@ Game 96: 3 red, 10 green; 9 green, 11 red; 2 red, 6 green, 2 blue; 1 blue, 9 red Game 97: 3 green, 11 red, 1 blue; 3 green, 13 red, 4 blue; 1 green, 3 blue, 12 red; 4 green, 10 red; 4 blue, 10 green, 12 red Game 98: 6 blue, 12 red; 17 red, 1 green, 11 blue; 13 blue, 9 red; 9 red, 6 blue, 2 green Game 99: 15 green, 1 blue, 11 red; 12 green, 12 blue, 14 red; 12 green, 10 blue, 1 red -Game 100: 1 green, 11 red, 4 blue; 4 green, 1 red; 9 red, 2 blue; 5 blue, 11 red, 9 green \ No newline at end of file +Game 100: 1 green, 11 red, 4 blue; 4 green, 1 red; 9 red, 2 blue; 5 blue, 11 red, 9 green diff --git a/advent-of-code/2023/day_02/src/test/kotlin/GameHostTest.kt b/advent-of-code/2023/day_02/src/test/kotlin/GameHostTest.kt new file mode 100644 index 0000000..cd55e4a --- /dev/null +++ b/advent-of-code/2023/day_02/src/test/kotlin/GameHostTest.kt @@ -0,0 +1,30 @@ +import space.comfycamp.getSumOfCorrectGameIDs +import space.comfycamp.getSumOfPowers +import kotlin.test.assertEquals +import kotlin.test.Test + +class GameHostTest { + @Test + fun testGetSumOfCorrectGameIDs() { + val lines = listOf( + "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green", + "Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue", + "Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red", + "Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red", + "Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green" + ) + assertEquals(8, getSumOfCorrectGameIDs(lines)) + } + + @Test + fun testGetSumOfPowers() { + val lines = listOf( + "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green", + "Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue", + "Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red", + "Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red", + "Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green" + ) + assertEquals(2286, getSumOfPowers(lines)) + } +} diff --git a/advent-of-code/2023/kotlin/src/main/kotlin/Solution02.kt b/advent-of-code/2023/kotlin/src/main/kotlin/Solution02.kt deleted file mode 100644 index 6fc5bac..0000000 --- a/advent-of-code/2023/kotlin/src/main/kotlin/Solution02.kt +++ /dev/null @@ -1,81 +0,0 @@ -import kotlin.math.max - -class CubeCount(var red: Int, var green: Int, var blue: Int) { - fun lessOrEqualThan(other: CubeCount): Boolean { - return red <= other.red && green <= other.green && blue <= other.blue - } -} - -class Solution02 { - // Part 1 - fun getSumOfCorrectGameIDs(text: List, cubes: CubeCount): Int { - val games = readGames(text) - var sum = 0 - - for (game in games.entries) { - var valid = true - - for (count in game.value) { - if (!count.lessOrEqualThan(cubes)) { - valid = false - } - } - - if (valid) { - sum += game.key - } - } - - return sum - } - - // Part 2 - fun getSumOfPowers(text: List): Int { - val games = readGames(text) - var sum = 0 - - for (game in games.values) { - var maxRed = 0 - var maxGreen = 0 - var maxBlue = 0 - - for (gameSet in game) { - maxRed = max(maxRed, gameSet.red) - maxGreen = max(maxGreen, gameSet.green) - maxBlue = max(maxBlue, gameSet.blue) - } - - sum += maxRed * maxGreen * maxBlue - } - - return sum - } - - private fun readGames(text: List): HashMap> { - val games = hashMapOf>() - - text.forEach { - // `it` example: "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green" - val (game, sets) = it.split(": ") - val gameID = game.split(" ")[1].toInt() - games[gameID] = arrayListOf() - - // setStr example: "3 blue, 4 red" - for (setStr in sets.split("; ")) { - val gameSet = CubeCount(0,0,0) - // cubeStr example: "3 blue" - for (cubeStr in setStr.split(", ")) { - val (cubeCountStr, color) = cubeStr.split(" ") - when (color) { - "blue" -> gameSet.blue = cubeCountStr.toInt() - "red" -> gameSet.red = cubeCountStr.toInt() - "green" -> gameSet.green = cubeCountStr.toInt() - } - } - games[gameID]?.add(gameSet) - } - } - - return games - } -} diff --git a/advent-of-code/2023/kotlin/src/main/resources/day-02/test.txt b/advent-of-code/2023/kotlin/src/main/resources/day-02/test.txt deleted file mode 100644 index 1cd7d33..0000000 --- a/advent-of-code/2023/kotlin/src/main/resources/day-02/test.txt +++ /dev/null @@ -1,5 +0,0 @@ -Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green -Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue -Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red -Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red -Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green \ No newline at end of file diff --git a/advent-of-code/2023/kotlin/src/test/kotlin/Solution02Test.kt b/advent-of-code/2023/kotlin/src/test/kotlin/Solution02Test.kt deleted file mode 100644 index ef6c098..0000000 --- a/advent-of-code/2023/kotlin/src/test/kotlin/Solution02Test.kt +++ /dev/null @@ -1,32 +0,0 @@ -import kotlin.test.Test -import kotlin.test.assertEquals - -class Solution02Test { - @Test - fun testGetSumOfCorrectGameIDs() { - val text = ResourceReader().readFile("day-02/test.txt") - val res = Solution02().getSumOfCorrectGameIDs(text, CubeCount(12, 13, 14)) - assertEquals(8, res) - } - - @Test - fun testGetPowerSum() { - val text = ResourceReader().readFile("day-02/test.txt") - val res = Solution02().getSumOfPowers(text) - assertEquals(2286, res) - } - - @Test - fun solvePart1() { - val text = ResourceReader().readFile("day-02/input.txt") - val res = Solution02().getSumOfCorrectGameIDs(text, CubeCount(12, 13, 14)) - println(res) - } - - @Test - fun solvePart2() { - val text = ResourceReader().readFile("day-02/input.txt") - val res = Solution02().getSumOfPowers(text) - println(res) - } -}