Day4
This commit is contained in:
117
src/main/kotlin/com/basdado/adventofcode/Day4.kt
Normal file
117
src/main/kotlin/com/basdado/adventofcode/Day4.kt
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package com.basdado.adventofcode
|
||||||
|
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
import java.util.stream.IntStream
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
|
||||||
|
val day = Day4()
|
||||||
|
day.puzzle1()
|
||||||
|
day.puzzle2()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Day4 {
|
||||||
|
|
||||||
|
fun puzzle1() {
|
||||||
|
|
||||||
|
val guardDays = parseDayInput()
|
||||||
|
val maxSleepGuard = guardDays.stream()
|
||||||
|
.collect(Collectors.groupingBy({ g: GuardDay -> g.guardId },
|
||||||
|
Collectors.mapping({ g -> g.totalSleep() },
|
||||||
|
Collectors.summingInt { s: Int -> s }
|
||||||
|
)))
|
||||||
|
.maxBy { it.value }!!
|
||||||
|
|
||||||
|
val guardSleeps = guardDays.stream()
|
||||||
|
.filter{ it.guardId == maxSleepGuard.key}
|
||||||
|
.flatMap { it.sleeps.stream() }
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
|
||||||
|
val sleepMinutes = IntArray(60)
|
||||||
|
guardSleeps.forEach { IntStream.range(it.start, it.end).forEach{ m -> sleepMinutes[m]++ } }
|
||||||
|
|
||||||
|
val maxSleepMinute = sleepMinutes.indexOf(sleepMinutes.max()!!)
|
||||||
|
println(maxSleepMinute * maxSleepGuard.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun puzzle2() {
|
||||||
|
|
||||||
|
val guardDays = parseDayInput()
|
||||||
|
|
||||||
|
val guardsSleepMinutes = guardDays.stream().map { it.guardId }
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toMap( { id: Int -> id }, {IntArray(60)}))
|
||||||
|
|
||||||
|
guardDays.stream()
|
||||||
|
.forEach {
|
||||||
|
val guardSleepMinutes = guardsSleepMinutes[it.guardId]!!
|
||||||
|
it.sleeps.forEach { s ->
|
||||||
|
IntStream.range(s.start, s.end).forEach{ m -> guardSleepMinutes[m]++ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val maxSleepMinuteGuard = guardsSleepMinutes.maxBy { it.value.max()!! }!!
|
||||||
|
|
||||||
|
val maxSleepMinute = maxSleepMinuteGuard.value.indexOf(maxSleepMinuteGuard.value.max()!!)
|
||||||
|
println(maxSleepMinute * maxSleepMinuteGuard.key)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseDayInput(): List<GuardDay> {
|
||||||
|
val sortedLines = lines("/day/4/input.txt")
|
||||||
|
.map { parseLine(it) }
|
||||||
|
.filter{ it != null }
|
||||||
|
.map { it!! }
|
||||||
|
.sorted( Comparator.comparing { l: Line -> l.date}.thenComparing { l -> l.hour }.thenComparing { l -> l.minute})
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
|
||||||
|
return parseGuardDays(sortedLines)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseGuardDays(sortedLines: MutableList<Line>): List<GuardDay> {
|
||||||
|
val guardDays = mutableListOf<GuardDay>()
|
||||||
|
var currentDay = GuardDay(0, LocalDate.EPOCH, mutableListOf())
|
||||||
|
var sleepStartMinute = 0
|
||||||
|
for (line in sortedLines) {
|
||||||
|
if (line.event == GuardEventType.BEGIN_SHIFT) {
|
||||||
|
if (currentDay.guardId != 0) guardDays.add(currentDay)
|
||||||
|
currentDay = GuardDay(line.guardId!!, line.date, mutableListOf())
|
||||||
|
} else if (line.event == GuardEventType.FALL_ASLEEP) {
|
||||||
|
sleepStartMinute = line.minute
|
||||||
|
} else if (line.event == GuardEventType.WAKE_UP) {
|
||||||
|
currentDay.sleeps.add(GuardSleep(sleepStartMinute, line.minute))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return guardDays
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseLine(line: String): Line? {
|
||||||
|
val regex = Regex("""\[(\d+)-(\d+)-(\d+) (\d+):(\d+)] (Guard #(\d+) begins shift|falls asleep|wakes up)""")
|
||||||
|
val match = regex.matchEntire(line) ?: return null
|
||||||
|
return Line(
|
||||||
|
LocalDate.of(match.groups[1]!!.value.toInt(), match.groups[2]!!.value.toInt(), match.groups[3]!!.value.toInt()),
|
||||||
|
match.groups[4]!!.value.toInt(),
|
||||||
|
match.groups[5]!!.value.toInt(),
|
||||||
|
parseEventType(match.groups[6]!!.value),
|
||||||
|
match.groups[7]?.value?.toInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseEventType(eventString: String): GuardEventType {
|
||||||
|
return when(eventString) {
|
||||||
|
"falls asleep" -> GuardEventType.FALL_ASLEEP
|
||||||
|
"wakes up" -> GuardEventType.WAKE_UP
|
||||||
|
else -> GuardEventType.BEGIN_SHIFT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Line(val date: LocalDate, val hour: Int, val minute: Int, val event: GuardEventType, val guardId: Int?)
|
||||||
|
enum class GuardEventType { BEGIN_SHIFT, FALL_ASLEEP, WAKE_UP }
|
||||||
|
data class GuardDay (val guardId: Int, val date: LocalDate, val sleeps: MutableList<GuardSleep>) {
|
||||||
|
fun totalSleep(): Int = sleeps.stream().mapToInt{ it.sleep() }.sum()
|
||||||
|
}
|
||||||
|
data class GuardSleep (val start: Int, val end: Int) {
|
||||||
|
fun sleep(): Int = end - start
|
||||||
|
}
|
||||||
@@ -8,4 +8,4 @@ fun lines(resourceFile: String): Stream<String> {
|
|||||||
return Files.lines(Paths.get(Utils::class.java.getResource(resourceFile).toURI()))
|
return Files.lines(Paths.get(Utils::class.java.getResource(resourceFile).toURI()))
|
||||||
}
|
}
|
||||||
|
|
||||||
class Utils;
|
class Utils
|
||||||
1110
src/main/resources/day/4/input.txt
Normal file
1110
src/main/resources/day/4/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user