Skip to content

Commit

Permalink
day 6 done, nice and easy!
Browse files Browse the repository at this point in the history
  • Loading branch information
devPalacio committed Dec 7, 2023
1 parent 802f5d9 commit ddec081
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 11 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ plugins {
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.8.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}

tasks.test {
Expand Down
16 changes: 5 additions & 11 deletions src/main/kotlin/day04/Day04.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,11 @@ package day04
import fetchInput
import println
import kotlin.math.pow
import kotlin.system.measureTimeMillis

fun main() {
val input = fetchInput(4)
part1(input).println()
val executionTime = measureTimeMillis {
val result = part2(input)
result.println()
}
println("Execution time: $executionTime ms")
// part2(input).println()
part2(input).println()
}

fun part1(input: List<String>): Int {
Expand All @@ -36,7 +30,6 @@ fun part2(input: List<String>): Int {
}
}
}
println(cardTracker.asList().toString())
return cardTracker.sum()
}

Expand All @@ -45,23 +38,24 @@ fun Triple<Int, Set<Int>, Set<Int>>.numOfMatches(): Int = (second intersect thir
fun Int.numOfPoints(): Int = 2f.pow(this - 1).toInt()

fun String.parseInput(): Triple<Int, Set<Int>, Set<Int>> {
val parts = this.split(":", "|")
val parts = split(":", " | ")
require(parts.size == 3) { "String failed to parse: $this" }

val cardNum =
parts[0]
.substringAfter("Card ")
.trim()
.toInt()

val winningNums =
parts[1]
.trim()
.split(" ")
.filter { it.isNotBlank() }
.map(String::toInt)
.toSet()

val myNums =
parts[2]
.trim()
.split(" ")
.filter { it.isNotBlank() }
.map(String::toInt)
Expand Down
117 changes: 117 additions & 0 deletions src/main/kotlin/day05/Day05.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package day05

import fetchInput
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import println

fun main() {
val input = fetchInput(5)
part1(input).println()
part2(input).println()
}

fun part1(input: List<String>): Long {
val parsed = parseDay5(input)
return parsed.seeds.minOf {
seedToLocation(it, parsed, input)
}
}

fun part2(input: List<String>): Long =
runBlocking {
val parsed = parseDay5(input)
val newSeeds =
parsed.seeds
.chunked(2)
.map { (seed, range) ->
seed until seed + range
}

val locations = mutableSetOf<Long>()

newSeeds.map { longRange ->
async {
var min: Long = Long.MAX_VALUE
for (seed in longRange) {
min = minOf(seedToLocation(seed, parsed, input), min)
}
min
}
}.awaitAll().forEach {
locations.add(it)
}
locations.min()
}

data class Day05Game(
val seeds: List<Long>,
val sToSMap: String,
val sToFMap: String,
val fToWMap: String,
val wToLMap: String,
val lToTMap: String,
val tToHMap: String,
val hToLMap: String,
)

fun parseDay5(input: List<String>): Day05Game {
// a regex is probably way simpler.
val seeds =
input
.first()
.split(": ")
.drop(1)
.first()
.split(" ")
.map(String::toLong)

return Day05Game(
seeds = seeds,
sToSMap = "seed-to-soil map:",
sToFMap = "soil-to-fertilizer map:",
fToWMap = "fertilizer-to-water map:",
wToLMap = "water-to-light map:",
lToTMap = "light-to-temperature map:",
tToHMap = "temperature-to-humidity map:",
hToLMap = "humidity-to-location map:",
)
}

private fun convertToDestination(
seed: Long,
mapName: String,
input: List<String>,
): Long {
val startIndex = input.indexOf(mapName) + 1

for (i in startIndex until input.size) {
val line = input[i]
if (line.isBlank()) break

val parsed = line.split(" ").map(String::toLong)

val (destination, source, range) = parsed
if (seed in source until source + range) {
val offset = destination - source
return seed + offset
}
}
return seed
}

fun seedToLocation(
seed: Long,
game: Day05Game,
input: List<String>,
): Long {
var key = seed
val transformations =
listOf(game.sToSMap, game.sToFMap, game.fToWMap, game.wToLMap, game.lToTMap, game.tToHMap, game.hToLMap)
for (transform in transformations) {
val value = convertToDestination(key, transform, input)
key = value
}
return key
}
73 changes: 73 additions & 0 deletions src/test/kotlin/day05/Day05Test.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package day05

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class Day05Test {
@Test
fun seedReturnsCorrectSoil() {
val expected = listOf(82L, 43L, 86L, 35L)
val parsed = parseDay5(sampleInput)
val seeds = parsed.seeds
val actual = seeds.map { seedToLocation(it, parsed, sampleInput) }
assertEquals(expected, actual)
}

@Test
fun part2ReturnsLowestLocation() {
val expected = 46L
val parsed = parseDay5(sampleInput)
val newseeds =
parsed.seeds.chunked(2).map {
it[0] until it[0] + it[1]
}
val locations = mutableSetOf<Long>()

newseeds.forEach { longRange ->
var min: Long = Long.MAX_VALUE
for (seed in longRange) {
min = minOf(seedToLocation(seed, parsed, sampleInput), min)
locations.add(min)
}
}
val actual = locations.min()
assertEquals(expected, actual)
}

private val sampleInput =
"""
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
""".trimIndent().split("\n")
}
40 changes: 40 additions & 0 deletions src/test/kotlin/day06/Day06KtTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package day06

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test

class Day06KtTest {
@Test
fun parseRacesReturnsCorrectResult() {
val expected = listOf(Pair(7, 9), Pair(15, 40), Pair(30, 200))
val actual = parseDay6(sampleInput)
assertEquals(expected, actual)
}

@Test
fun parseRacesReturnsCorrectResultP2() {
val expected = Pair(71530L, 940200L)
val actual = parseDay6P2(sampleInput)
assertEquals(expected, actual)
}

@Test
fun findBestSpeedReturnsCorrectResult() {
val expected = listOf<Long>(2, 3, 4, 5)
val actual = findBestSpeeds(parseDay6(sampleInput).first())
assertEquals(expected, actual)
}

@Test
fun part2ReturnsCorrectResult() {
val expected = 71503
val actual = part2(sampleInput)
assertEquals(expected, actual)
}

private val sampleInput =
"""
Time: 7 15 30
Distance: 9 40 200
""".trimIndent().split("\n")
}

0 comments on commit ddec081

Please sign in to comment.