Advent of Code 2021 day 6
12/06/2022, 5:00 AMDan Fingal-Surma
12/06/2022, 5:05 AMJonathan Kolberg
12/06/2022, 5:06 AMDan Fingal-Surma
12/06/2022, 5:06 AMJonathan Kolberg
12/06/2022, 5:07 AMDan Fingal-Surma
12/06/2022, 5:07 AMindexOfFirst
, niceMarcin Wisniowski
12/06/2022, 5:07 AMMarcin Wisniowski
12/06/2022, 5:08 AMMichael de Kaste
12/06/2022, 5:09 AMMichael de Kaste
12/06/2022, 5:09 AMobject Day6 : Challenge() {
override fun part1() = solve(4)
override fun part2() = solve(14)
private fun solve(size: Int) = input.windowed(size).indexOfFirst { it.toSet().size == size } + size
}
Dan Fingal-Surma
12/06/2022, 5:10 AMJonathan Kolberg
12/06/2022, 5:10 AMxxfast
12/06/2022, 5:10 AMwindowed
fun part(inputs: List<String>, size: Int): List<Int> = inputs
.map { input -> input.windowed(size).indexOfFirst { it.toSet().size == size } + size }
check(part(testInput, 4) == listOf(7, 5, 6, 10, 11))
println(part(input, 4))
check(part(testInput, 14) == listOf(19, 23, 23, 29, 26))
println(part(input, 14))
Michael de Kaste
12/06/2022, 5:12 AMMichael Böiers
12/06/2022, 5:12 AMpackage aoc2022
fun main() = day06(String(System.`in`.readAllBytes())).forEach(::println)
private fun day06(input: String) = listOf(4, 14).map { n -> input.windowed(n).indexOfFirst { it.toSet().size == n } + n }
Cognitive Gear
12/06/2022, 5:12 AMclass Day06 : AdventDay(2022, 6) {
override fun part1(): String {
return input.withIndex().windowed(4, 1).first {
val (a, b, c, d) = it
a.value != b.value &&
b.value != c.value &&
c.value != d.value &&
a.value != c.value &&
a.value != d.value &&
b.value != d.value
}.last().let { it.index + 1}.toString()
}
override fun part2(): String {
return input.asSequence().withIndex().windowed(14, 1).first {
val set = it.map { it.value}.toSet()
set.size == it.size
}.last().let { it.index + 1}.toString()
}
}
fun main() {
Day06().main()
}
jonas.app
12/06/2022, 5:13 AMJacob Moulton
12/06/2022, 5:13 AMSergei Petunin
12/06/2022, 5:14 AMfun solution(input: String, length: Int) = input.windowed(length)
.indexOfFirst { it.toSet().size == length } + length
fun part1(input: String) = solution(input, 4)
fun part2(input: String) = solution(input, 14)
Dan Fingal-Surma
12/06/2022, 5:14 AMJacob Moulton
12/06/2022, 5:14 AMNeil Banman
12/06/2022, 5:16 AMDavid Whittaker
12/06/2022, 5:17 AMMichael Böiers
12/06/2022, 5:17 AMMichael Böiers
12/06/2022, 5:21 AMAnirudh
12/06/2022, 5:23 AMBrian Hartvigsen
12/06/2022, 5:24 AMwindowed
before! That's hella nice. I went with:
fun startOfInput(message: String, size: Int = 4): Int {
var last4 = mutableListOf<Char>()
return message.takeWhile {
if (last4.size == size && last4.groupBy { c -> c }.map { g -> g.value.size }.all { n -> n == 1 }) {
false
} else {
last4.add(it)
if (last4.size == size+1) {
last4.removeAt(0)
}
true
}
}.length
}
ritesh
12/06/2022, 5:24 AMSlidingWindow + Set
Alex J.
12/06/2022, 5:24 AMJonathan Kolberg
12/06/2022, 5:28 AMxxfast
12/06/2022, 5:28 AMJonathan Kolberg
12/06/2022, 5:29 AMAnirudh
12/06/2022, 5:30 AMJakub Gwóźdź
12/06/2022, 5:42 AM.windowedIndexed()
? Oh screw it, i’ll write it myself:
fun part1(input: String) = (0..input.length).first {
input.substring(it, it + 4).toSet().size == 4
} + 4
Which was actually better, since .windowed
returns List<…>
of all possible substrings to the end of strings, it’s not a lazy sequence.Anirudh
12/06/2022, 5:43 AMJakub Gwóźdź
12/06/2022, 5:44 AM@SinceKotlin("1.2")
public fun CharSequence.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false): List<String> {
return windowed(size, step, partialWindows) { it.toString() }
}
Anirudh
12/06/2022, 5:46 AMSergei Petunin
12/06/2022, 5:47 AMfun solution(input: String, length: Int): Int {
var distinctCount = 0
val charCounts = IntArray(256)
return 1 + input.indices.first {
if (it >= length) {
when (--charCounts[input[it - length].code]) {
0 -> distinctCount--
1 -> distinctCount++
}
}
when (++charCounts[input[it].code]) {
1 -> distinctCount++
2 -> distinctCount--
}
distinctCount == length
}
}
Jakub Gwóźdź
12/06/2022, 5:48 AM.windowed()
on Sequence
is a Sequence
indeed, but CharSequence
is not a `Sequence`…. because I don’t know why :)nkiesel
12/06/2022, 5:48 AMwindowedSequence
instead of windowed
?Jakub Gwóźdź
12/06/2022, 5:49 AMJakub Gwóźdź
12/06/2022, 5:53 AMfun <T> Iterable<T>.windowed(
size: Int,
step: Int = 1,
partialWindows: Boolean = false
): List<List<T>>
but then it gives example on
val sequence = generateSequence(1) { it + 1 }
val windows = sequence.windowed(size = 5, step = 1)
...
where the return type is a Sequence<…>
, not a `List<…>`… 😆Anirudh
12/06/2022, 6:02 AMtransform
parameter would make our already short solutions even shorter 🤣
fun <T, R> Iterable<T>.windowed(
size: Int,
step: Int = 1,
partialWindows: Boolean = false,
transform: (List<T>) -> R
): List<R>
the IDE should tell us that 'windowed followed map' could be used in the transformOzioma Ogbe
12/06/2022, 6:09 AMfun findMarker(input: String, numberOfDistinctMarker: Int): Int {
return input.indexOf(
input.windowed(numberOfDistinctMarker).find {
it.toSet().size == it.length
}!!
) + numberOfDistinctMarker
}
Part 1
fun main() = solve { lines ->
findMarker(lines.joinToString(""), 4)
}
Part2
fun main() = solve { lines ->
findMarker(lines.joinToString(""), 14)
}
Jakub Gwóźdź
12/06/2022, 6:13 AMprivate fun solve(input: String, size: Int) =
input.windowedSequence(size) { it.toList().distinct().size }
.indexOfFirst { it == size } + size
Marc Javier
12/06/2022, 6:14 AMAnirudh
12/06/2022, 6:14 AMit.distinct()
would do, don't need it.toList().distinct()
Jakub Gwóźdź
12/06/2022, 6:15 AMAnirudh
12/06/2022, 6:15 AMJakub Gwóźdź
12/06/2022, 6:16 AMJakub Gwóźdź
12/06/2022, 6:19 AMAnirudh
12/06/2022, 6:19 AMSequence<Char>
is not the same as CharSequence
Jakub Gwóźdź
12/06/2022, 6:20 AMdistinct
is basically toSet, but more kotlinish 🙂ephemient
12/06/2022, 6:23 AMephemient
12/06/2022, 6:24 AMPoisonedYouth
12/06/2022, 6:30 AMreturn input.map { line ->
line.windowed(size).indexOfFirst { group -> group.groupBy { it }.size == size } + size
}
https://github.com/PoisonedYouth/advent-of-code-kotlin-2022/blob/main/src/day06/Day06.ktRiccardo Lippolis
12/06/2022, 6:36 AMprivate fun String.findStartOfMessageMarker(size: Int) = asSequence()
.windowed(size)
.takeWhile { chars -> chars.toSet().size != size }
.count() + size
thanks to your examples, could reduce it to this: 👌
private fun String.findStartOfMessageMarker(size: Int) =
windowedSequence(size) { it.toSet().size }.indexOfFirst { it == size } + size
indeed a pretty easy one today 😅Neil Banman
12/06/2022, 6:55 AMMonster Brain
12/06/2022, 6:57 AMinput.substring(index-4, index)
😭Anirudh
12/06/2022, 6:59 AMGrzegorz Aniol
12/06/2022, 7:02 AMwindowed
and toSet
ephemient
12/06/2022, 7:15 AMByteArray
as your counter instead of a MutableMap<Char, Int>
frascu
12/06/2022, 7:33 AMkqr
12/06/2022, 7:45 AMAbdul Khaliq
12/06/2022, 7:46 AMephemient
12/06/2022, 7:51 AMwindowedSequence
gives you windows lazily instead of all at onceephemient
12/06/2022, 7:51 AMAbdul Khaliq
12/06/2022, 7:52 AMphldavies
12/06/2022, 7:56 AMphldavies
12/06/2022, 8:04 AMGrzegorz Aniol
12/06/2022, 8:14 AMritesh
12/06/2022, 8:15 AMBen Ooms
12/06/2022, 8:20 AMBen Ooms
12/06/2022, 8:20 AMfun part1(input: String): Int {
val window = 4
return (input.chars().toList().windowed(window,1).indexOfFirst {
it.toSet().size == window
})+window
}
Paul Woitaschek
12/06/2022, 8:29 AMAbdul Khaliq
12/06/2022, 8:31 AMchars.toList()
and just do input.windowed()
.Davio
12/06/2022, 8:32 AMobject Day6 {
private fun getStartMarker(messageLength: Int) = getInputAsLine()
.windowed(messageLength)
.indexOfFirst { it.length == it.toSet().size } + messageLength
fun getResultPart1() = getStartMarker(4)
fun getResultPart2() = getStartMarker(14)
}
Davio
12/06/2022, 8:32 AMDavio
12/06/2022, 8:32 AMBen Ooms
12/06/2022, 8:33 AMfun getUniqueBlockIndexEndOf(input: String, window: Int) =
(input.windowed(window)
.indexOfFirst {
it.toSet().size == window
}) + window
Davio
12/06/2022, 8:59 AMprivate val set = hashSetOf<Char>()
private fun getStartMarker(messageLength: Int) = getInputAsLine()
.windowed(messageLength)
.indexOfFirst { !it.hasDuplicates } + messageLength
private val String.hasDuplicates: Boolean get() {
set.clear()
return this.any { !set.add(it) }
}
You can reuse the same set and just return immediately if you added a duplicate character to it instead of creating an entire set each timeMichael Böiers
12/06/2022, 8:59 AMfun main() = with(String(System.`in`.readAllBytes())) {
fun String.afterMarker(i: Int, n: Int) =
i > n && with(mutableSetOf<Char>()) { (i - n until i).all { add(get(it)) } }
var part1 = false
indices.forEach { i ->
if (!part1 && afterMarker(i, 4)) {
println(i)
part1 = true
}
if (afterMarker(i, 14)) {
println(i)
return
}
}
}
Davio
12/06/2022, 9:01 AMWilerson Oliveira
12/06/2022, 9:46 AMwindowed
and iterated by hand.
var buffer = ""
var index = 0
for (c in line) {
if (buffer.length >= 14) {
break
} else {
val repeatedIndex = buffer.indexOf(c)
if (repeatedIndex >= 0) {
buffer = buffer.drop(repeatedIndex + 1)
}
buffer += c
index++
}
}
println(index)
Charles Flynn
12/06/2022, 10:00 AMwindowed
and indexOfFirst
here too. That was easy.Davio
12/06/2022, 10:01 AMDavio
12/06/2022, 10:01 AMCharles Flynn
12/06/2022, 10:03 AMDavio
12/06/2022, 10:11 AMlineSequence
to get the lines as a sequence, or you can use useSequence
with a block which closes the reader at the endJoey Haas
12/06/2022, 10:27 AMmapIndexed
, too! The standard library has great functional programming support.
For me, I made it into a oneliner (if you don't count the hardcoded input string):
fun main(): Unit = println(listOf(4, 14).map { n -> input.windowed(n).indexOfFirst { it.toSet().size == n } + n })
Alexander af Trolle
12/06/2022, 10:35 AMDavio
12/06/2022, 10:54 AMindexed
sibling, such as filterIndexed
, mapIndexed
etc, but not all. If you need to carry the index, say you want to do an anyIndexed
you can use withIndex, like "somestring".withIndex()
to create wrapped versions, in this instance you get an Iterable<IndexedValue<Char>>
where each IndexedValue contains an index property and a value property.Karloti
12/06/2022, 1:29 PMfun String.indexOf(n: Int): Int = asSequence()
.withIndex()
.runningFold(mutableMapOf<Char, Int>() to -1) { (m, r), (i, c) -> m to (m.put(c, i)?.coerceAtLeast(r) ?: r) }
.withIndex()
.indexOfFirst { (index, value) -> index - value.second - 1 == n }
https://github.com/karloti/advent-of-code-2022-kotlin/blob/main/src/Day06.kttodd.ginsberg
12/06/2022, 1:35 PMtodd.ginsberg
12/06/2022, 1:35 PMindexOfFirst
. That would have made mine better.Michael Böiers
12/06/2022, 1:37 PMwindowedSequence
and indexOfFirst
before today. Thank you AoC! 🙂Michael Böiers
12/06/2022, 1:37 PMKarloti
12/06/2022, 2:32 PMPaul Woitaschek
12/06/2022, 2:38 PMDavio
12/06/2022, 2:42 PMPaul Woitaschek
12/06/2022, 2:43 PMDavio
12/06/2022, 2:43 PMPaul Woitaschek
12/06/2022, 2:43 PMJohn Glynn
12/06/2022, 2:44 PMwindowed
+ indexOfFirst
slays.todd.ginsberg
12/06/2022, 2:45 PMindexOfFirst
instead of withIndex().windowed
that I ended up with. So much cleaner that way.!John Glynn
12/06/2022, 2:46 PMAbdul Khaliq
12/06/2022, 2:46 PMwindowedSequence()
instead of windowed()
.todd.ginsberg
12/06/2022, 2:48 PMRiccardo Lippolis
12/06/2022, 2:50 PMI really should have stopped to think this one throughbut there's no time to think! Gotta get the stars as quickly as possible! ⭐ (/sarcasm)
Abdul Khaliq
12/06/2022, 2:50 PMtodd.ginsberg
12/06/2022, 2:51 PMKarloti
12/06/2022, 3:04 PMPaul Woitaschek
12/06/2022, 3:10 PMPaul Woitaschek
12/06/2022, 3:11 PM@Setup
fun setUp() {
input = buildString {
repeat(100000) {
append("aaaa")
}
append("abcd")
}
}
On my machine it runs with 47ms vs 69ms / opKarloti
12/06/2022, 3:17 PMKarloti
12/06/2022, 3:17 PMtodd.ginsberg
12/06/2022, 3:18 PMDave Leeds
12/06/2022, 3:20 PM.first{}.let{ indexOf() }
, but loved learning about indexOfFirst{}
!wakingrufus
12/06/2022, 3:22 PMwakingrufus
12/06/2022, 3:27 PMKarloti
12/06/2022, 3:45 PMDave Leeds
12/06/2022, 3:49 PMs
instead of ms
😅Davio
12/06/2022, 3:50 PMprivate val set = hashSetOf<Char>()
private fun getStartMarker(messageLength: Int) = getInputAsLine()
.windowedSequence(messageLength)
.indexOfFirst { !it.hasDuplicates } + messageLength
private val String.hasDuplicates: Boolean get() {
set.clear()
return this.any { !set.add(it) }
}
Davio
12/06/2022, 3:52 PMPaul Woitaschek
12/06/2022, 3:54 PMLuke
12/06/2022, 4:06 PMwindowed
+ indexOfFirst
too. I still used a regex instead of toSet().size
thoughNeil Banman
12/06/2022, 4:58 PMPaul Woitaschek
12/06/2022, 5:19 PMAnirudh
12/06/2022, 5:21 PMVenkataramanan Parameswaran
12/06/2022, 5:25 PMVenkataramanan Parameswaran
12/06/2022, 5:25 PMAnirudh
12/06/2022, 5:35 PM* *
nppdvjthqldpwncqszvftbrmjlhg
^^^^^^^^^^^^^^
instead of just moving the window or appending the next element, "s"; the index could be jumped to after the 1st "q" (to the "l"):
* *
nppdvjthqldpwncqszvftbrmjlhg
^^^^^^^^^^^^^^
Neil Banman
12/06/2022, 5:36 PMNeil Banman
12/06/2022, 5:42 PMAnirudh
12/06/2022, 5:49 PMNeil Banman
12/06/2022, 6:24 PMwindowed
. The downside is abysmal performance. Once you abandon the functional approach to track the first character of a duplicate pair and the like, you may as well go with Sergei's or Alexander's approach. And those don't work with index skipping.Wael Ellithy
12/06/2022, 7:10 PMfun String.startOfMarker(size: Int): Int =
asSequence().windowed(size).indexOfFirst { it.toSet().size == size } + size