Advent of Code 2023 day 2
12/02/2024, 5:00 AMJakub Gwóźdź
12/02/2024, 5:25 AMline.windowed(2).all { (a, b) -> (b - a) * sign in (1..3) }
does the trickAnirudh
12/02/2024, 5:26 AMMarcin Wisniowski
12/02/2024, 5:28 AMMarcin Wisniowski
12/02/2024, 5:28 AMMarcin Wisniowski
12/02/2024, 5:28 AMKroppeb
12/02/2024, 5:29 AMis(Strict)Ascending
and descencing btwKroppeb
12/02/2024, 5:29 AMJonathan Kolberg
12/02/2024, 5:29 AMfun List<Long>.omit(index: Int): List<Long> = subList(0, index) + subList(index + 1, size)
Kroppeb
12/02/2024, 5:29 AMMarcin Wisniowski
12/02/2024, 5:29 AMis(Strict)Ascending
and descencing btw
In the stdlib? No there isn'tMarcin Wisniowski
12/02/2024, 5:30 AMJonathan Kolberg
12/02/2024, 5:30 AMKroppeb
12/02/2024, 5:32 AMisStrictAscending
a few days before AOC 2020. Thank you past me!Kroppeb
12/02/2024, 5:33 AMKroppeb
12/02/2024, 5:33 AMJakub Gwóźdź
12/02/2024, 5:35 AMfun part1(input: List<List<Long>>) = input.count(List<Long>::isSafe)
fun part2(input: List<List<Long>>) = input.count { line ->
line.indices.asSequence()
.map { bad -> line.filterIndexed { index, _ -> index != bad } }
.any(List<Long>::isSafe)
}
fun List<Long>.isSafe(): Boolean = windowed(2).all { (a, b) -> (b - a) in (1..3) } ||
windowed(2).all { (a, b) -> (a - b) in (1..3) }
Jacob
12/02/2024, 5:40 AMbj0
12/02/2024, 5:42 AMJacob
12/02/2024, 5:43 AMNeil Banman
12/02/2024, 5:47 AMbj0
12/02/2024, 5:49 AMvanshg
12/02/2024, 5:59 AMEndre Deak
12/02/2024, 6:01 AMfun <T> List<T>.allSubListsWithAdjacentRemoved(size: Int = 1): List<List<T>> =
this.indices
.reversed()
.windowed(size)
.map { ix ->
this.toMutableList()
.apply {
ix.forEach { i ->
this@apply.removeAt(i)
}
}
}
there must be a more idiomatic Kotlin way of doing thisvanshg
12/02/2024, 6:05 AMfun <T> List<T>.omit(index: Int): List<T> = take(index) + drop(index + 1)
fun generateCandidates(report: List<Int>): List<List<Int>> = listOf(report) + report.indices.map(report::omit)
Edit: Actually, using subList
is more efficient because it just returns a view of the existing list
fun <T> List<T>.omit(index: Int): List<T> = subList(0, index) + subList(index + 1, size)
Jakub Gwóźdź
12/02/2024, 6:05 AMfun part2(input: List<List<Long>>) = input.count { line ->
line.indices.asSequence()
.map(line::skippingOne)
.any(Iterable<Long>::isSafe)
}
fun List<Long>.skippingOne(indexToSkip: Int): Iterable<Long> = Iterable<Long> {
object : Iterator<Long> {
var i = if (indexToSkip == 0) 1 else 0
override fun next(): Long = this@skippingOne[i++].also { if (i == indexToSkip) i++ }
override fun hasNext(): Boolean = i < this@skippingOne.size
}
}
fun Iterable<Long>.isSafe(): Boolean = zipWithNext().all { (a, b) -> (b - a) in (1..3) } ||
zipWithNext().all { (a, b) -> (a - b) in (1..3) }
Petr Sýkora
12/02/2024, 6:06 AMDan Fingal-Surma
12/02/2024, 6:14 AMDan Fingal-Surma
12/02/2024, 6:38 AMfun <T> List<T>.omit(index: Int): List<T> = filterIndexed { i, _ -> i != index }
Dan Fingal-Surma
12/02/2024, 6:44 AMritesh
12/02/2024, 6:55 AMPaul Woitaschek
12/02/2024, 7:17 AMPoisonedYouth
12/02/2024, 7:17 AMfun List<Int>.withoutElementAt(listIndex: Int): List<Int> {
return this.let { it.toMutableList().also { it.removeAt(listIndex) }.toList() }
}
fun List<Int>.isMatching() = this.windowed(2).all {
it[1] - it[0] in (1..3)
}
fun part1(input: List<String>): Int {
return input.count { line ->
val report = line.split(" ").map { it.toInt() }
val strictlyIncreasing = report.isMatching()
val strictlyDecreasing = report.reversed().isMatching()
strictlyIncreasing || strictlyDecreasing
}
}
fun part2(input: List<String>): Int {
return input.count { line ->
val report = line.split(" ").map { it.toInt() }
val strictlyIncreasingFaultTolerant = List(report.size) { listIndex ->
report.withoutElementAt(listIndex).isMatching()
}.any { it }
val strictlyDecreasingFaultTolerant = List(report.size) { listIndex ->
report.withoutElementAt(listIndex).reversed().isMatching()
}.any { it }
strictlyIncreasingFaultTolerant || strictlyDecreasingFaultTolerant
}
}
Neil Banman
12/02/2024, 7:39 AMphldavies
12/02/2024, 7:39 AMphldavies
12/02/2024, 7:40 AMzipWithNext
with a transform to avoid creating a list of Pair when all I needed was the deltas.Paul Woitaschek
12/02/2024, 7:40 AMManaged to squeeze in Day 2 before the school runSame! At 6:40 my school lunch-prep service finished so I had until 7:00 when the teeth-brush service was supposed to start 😛
Anirudh
12/02/2024, 8:02 AMJakub Gwóźdź
12/02/2024, 8:09 AMMichael de Kaste
12/02/2024, 8:14 AMCharles Flynn
12/02/2024, 9:07 AMfilterIndexed
trick for building my sublists:
val subLists = mutableListOf<List<Int>>()
for (i in this.indices) {
subLists.add(this.filterIndexed { j, _ -> j != i })
}
Also fell for the trap of part 2 where I coded it to allow 1 "mistake" but that's not what was being asked.Tim Schraepen
12/02/2024, 10:25 AM()
after the ?:
to group that &&
conditional.Tim Schraepen
12/02/2024, 10:33 AMPaul Woitaschek
12/02/2024, 10:33 AMvadzim
12/02/2024, 10:35 AMimport kotlin.math.abs
import kotlin.math.sign
fun main() {
val reports = generateSequence {
readlnOrNull()?.split(' ')?.map(String::toInt)
}.toList()
fun Sequence<Int>.isSafe(): Boolean =
windowed(2) { (a, b) -> a - b }.run {
val firstSign = first().sign
all { diff ->
diff.sign == firstSign && abs(diff) in 1..3
}
}
// Day 1
reports.count { it.asSequence().isSafe() }.also(::println)
// Day 2
fun <T> List<T>.subsequences() = sequence {
repeat(size) { iToSkip ->
yield(asSequence().filterIndexed { i, _ -> i != iToSkip })
}
}
reports.count { levels ->
levels.run { asSequence().isSafe() || subsequences().any { it.isSafe() } }
}.also(::println)
}
phldavies
12/02/2024, 10:36 AM/snippet
to start a text snippetKarloti
12/02/2024, 10:58 AMfun main() {
val report = mutableListOf<List<Int>>()
fun load(fileName: String) {
report.clear()
readInput(fileName).map { line -> report.add(line.split(Regex("\\s+")).map(String::toInt)) }
}
fun List<Int>.checkSafe(): Int = zipWithNext { a, b ->
when (b - a) {
in 1..3 -> 1
in -3..-1 -> -1
else -> 0
}
}.run { if (sum().absoluteValue == size) 1 else 0 }
fun part1(): Int = report.sumOf { levels: List<Int> -> levels.checkSafe() }
fun part2(): Int = report.sumOf { levels: List<Int> ->
levels.indices.asSequence().map { i ->
levels.toMutableList().run {
removeAt(i)
checkSafe()
}
}.firstOrNull { it == 1 } ?: 0
}
load("Day02_test")
check(part1() == 2) { "incorrect result part1" }
check(part2() == 4) { "incorrect result part2" }
load("Day02")
part1().println()
part2().println()
}
Advent_of_Code_2024Karloti
12/02/2024, 11:20 AMy9san9
12/02/2024, 11:30 AMJakub Gwóźdź
12/02/2024, 11:31 AMJakub Gwóźdź
12/02/2024, 11:32 AMJakub Gwóźdź
12/02/2024, 11:32 AMy9san9
12/02/2024, 11:34 AMJaap Beetstra
12/02/2024, 11:34 AMinput.intLists().count { line ->
line.asSequence().windowed(3).runningFold(State.First) { acc, window ->
acc.nextState(window[0], window[1], window[2])
}.none { it == State.Invalid }
}
Jaap Beetstra
12/02/2024, 11:35 AMJaap Beetstra
12/02/2024, 1:32 PMJakub Gwóźdź
12/02/2024, 2:00 PM.fold(...) {..}
version that can short-circuit on some condition? I mean, I can always do return....
but it seems somewhat unelegant.phldavies
12/02/2024, 3:36 PMasSequence().runningFold {}.takeWhile {}.last()
Karloti
12/02/2024, 6:06 PMimport kotlin.math.absoluteValue
import kotlin.time.measureTime
fun main() {
val report = mutableListOf<List<Int>>()
fun load(fileName: String) {
report.clear()
readInput(fileName).map { line -> report.add(line.split(Regex("\\s+")).map(String::toInt)) }
}
fun direction(b: Int, a: Int) = when (b - a) {
in 1..3 -> 1
in -3..-1 -> -1
else -> 0
}
fun Iterable<Int>.checkSafe(): Int = zipWithNext { a, b -> direction(b, a) }
.run { if (sum().absoluteValue == size) 1 else 0 }
fun Iterable<Int>.checkSafe2(): Int {
var lastElement: Int? = null
var lastDirection: Int? = null
var countCorrection = 0
return zipWithNext { a, b ->
val result = when {
direction(b, a) == lastDirection -> 1
lastElement == null -> 0
direction(b, lastElement!!) == lastDirection -> run {
countCorrection++
if (countCorrection == 1) 1 else 0
}
else -> 0
}
lastElement = a
lastDirection = lastDirection ?: direction(b, a).takeIf { it != 0 }
result
}.run { if (sum().absoluteValue == size - 1) 1 else 0 }
}
fun part1(): Int = report.sumOf { levels: List<Int> -> levels.checkSafe() }
fun part2(): Int = report.sumOf { levels: List<Int> ->
levels.indices.asSequence().map { i ->
levels.toMutableList().run {
removeAt(i)
checkSafe()
}
}.firstOrNull { it == 1 } ?: 0
}
fun part2New(): Int = report.sumOf { levels: List<Int> -> levels.checkSafe2() }
load("Day02_test")
check(part1() == 2) { "incorrect result part1" }
check(part2() == part2New()) { "incorrect result part2New" }
load("Day02")
part1().println()
part2().println()
part2New().println()
measureTime {
repeat(100_000) { part2New() }
}.let(::println)
measureTime {
repeat(100_000) { part2() }
}.let(::println)
}
Karloti
12/02/2024, 6:06 PMKarloti
12/02/2024, 6:07 PMKarloti
12/02/2024, 6:09 PMDan Fingal-Surma
12/02/2024, 8:43 PMKarloti
12/02/2024, 9:36 PMKarloti
12/02/2024, 9:48 PMNeil Banman
12/02/2024, 10:37 PMDan Fingal-Surma
12/02/2024, 10:43 PMNeil Banman
12/03/2024, 1:07 AMJakub Gwóźdź
12/03/2024, 4:29 AMfun List<Long>.maxOneError() = asSequence().maxOneErrorOneWay() || reversed().asSequence().maxOneErrorOneWay()
data class Acc(val prev: Long = 0, val sign: Int = 0, val errors: Int = 0)
fun Sequence<Long>.maxOneErrorOneWay() = drop(1).runningFold(Acc(first())) { acc, curr ->
val delta = curr - acc.prev
if (delta == 0L || abs(delta) > 3 || delta.sign == -acc.sign) acc.copy(errors = acc.errors + 1)
else acc.copy(prev = curr, sign = delta.sign)
}.none { it.errors >= 2 }
(very helpful method this runningFold(), to bad it's only usable during AoC xd)y9san9
12/03/2024, 4:51 AMJakub Gwóźdź
12/03/2024, 4:57 AMJaap Beetstra
12/03/2024, 10:14 AMMichael de Kaste
12/03/2024, 11:54 AMJakub Gwóźdź
12/03/2024, 11:56 AMMichael de Kaste
12/03/2024, 11:57 AMJakub Gwóźdź
12/03/2024, 11:57 AMJakub Gwóźdź
12/03/2024, 11:59 AMMichael de Kaste
12/03/2024, 12:09 PMephemient
12/03/2024, 2:47 PMephemient
12/03/2024, 3:02 PMIntArray
before the discussion about how arrays are an ugly compatibility wart on the language in the stream blob stuck out tongue
doing a slightly sneaky trick for part 2: reusing the same array, just mutating one element at a time (moving the missing element hole down the line)starke
12/04/2024, 7:14 PM