Advent of Code 2021 day 13
12/13/2022, 5:00 AMKroppeb
12/13/2022, 5:12 AMSergei Petunin
12/13/2022, 5:53 AMcompareTo
method, the second part was a breeze.Jonathan Kolberg
12/13/2022, 6:16 AM[2,3,4] vs 4
ok, since it says that if the right list runs out first it is not ok?Sergei Petunin
12/13/2022, 6:17 AMSergei Petunin
12/13/2022, 6:18 AMKroppeb
12/13/2022, 6:21 AMJonathan Kolberg
12/13/2022, 6:22 AMSergei Petunin
12/13/2022, 6:24 AMMarcin Wisniowski
12/13/2022, 6:28 AMephemient
12/13/2022, 6:39 AMJonathan Kolberg
12/13/2022, 6:52 AMMichael de Kaste
12/13/2022, 7:12 AMobject Day13 : Challenge() {
private val regex = """(,)|(?=\[)|(?=])|(?<=\[)|(?<=])""".toRegex()
val parsed = input.lines().filter(String::isNotBlank).map(::lineToNode)
private fun lineToNode(line: String) = buildList<MutableList<Node>> {
add(mutableListOf())
line.split(regex).filter(String::isNotBlank).forEach { t ->
when(t){
"[" -> add(mutableListOf())
"]" -> removeLast().also { last().add(Holder(*it.toTypedArray())) }
else -> last().add(Value(t.toInt()))
}
}
}[0][0]
override fun part1() = parsed.chunked(2)
.mapIndexed { index, (a,b) -> if(a < b) index + 1 else 0 }
.sum()
override fun part2(): Any? {
val packet1 = Holder(Holder(Value(2)))
val packet2 = Holder(Holder(Value(6)))
val list = (parsed + packet1 + packet2).sorted()
return (1 + list.indexOf(packet1)) * (1 + list.indexOf(packet2))
}
}
sealed interface Node : Comparable<Node>
class Holder(vararg val nodes: Node) : Node{
override fun compareTo(other: Node): Int = when(other){
is Value -> compareTo(Holder(other))
is Holder -> nodes.zip(other.nodes, Node::compareTo).firstOrNull { it != 0 }
?: nodes.size.compareTo(other.nodes.size)
}
}
class Value(val int: Int) : Node {
override fun compareTo(other: Node): Int = when(other){
is Value -> int.compareTo(<http://other.int|other.int>)
is Holder -> Holder(this).compareTo(other)
}
}
sealed interfaces to the rescueDan Fingal-Surma
12/13/2022, 7:54 AMsealed interface PacketData : Comparable<PacketData>
so part 2 was easyDan Fingal-Surma
12/13/2022, 8:14 AMDan Fingal-Surma
12/13/2022, 8:23 AMphldavies
12/13/2022, 8:29 AMComparable<PacketEntry>
phldavies
12/13/2022, 8:37 AMarrow.core
having
Iterable<A>.compareTo(other: Iterable<A>)
let me skip part of the implementationDavio
12/13/2022, 8:59 AMhttps://media.tenor.com/nwoJ4BS0XHYAAAAS/oh-no-anyway.gif▾
Davio
12/13/2022, 9:00 AMsorted()
with 2 indexOf
calls and call it a day 🙂Davio
12/13/2022, 9:02 AMDavio
12/13/2022, 9:04 AMephemient
12/13/2022, 9:13 AMephemient
12/13/2022, 9:14 AMcompareTo
means that if it would have blown the stack, it wouldn't have been avoided anywayephemient
12/13/2022, 9:17 AMphldavies
12/13/2022, 9:19 AMsorted()
and mapIndexedNotNull { idx, it -> if(it in dividers) idx + 1 else null }
were quicker to throw down as neededDavio
12/13/2022, 9:35 AMval packetList = getInputAsList()
.split { it.isBlank() }
.map { parsePacketPair(it) }
.plus(Pair(divider1, divider2))
.flatMap { listOf(it.first, it.second) }
return (packetList.count { it < divider1 } + 1) * (packetList.count { it < divider2 } + 1)
Jan Durovec
12/13/2022, 9:37 AMsort
is faster to write whereas just counting smaller lists is O(n). I first used sort, submitted the solution and then refactored to linear solution before committing to repo.ephemient
12/13/2022, 9:41 AMJan Durovec
12/13/2022, 9:41 AMephemient
12/13/2022, 9:42 AMDavio
12/13/2022, 9:45 AMreturn getInputAsList()
.split { it.isBlank() }
.map { parsePacketPair(it) }
.plus(Pair(divider1, divider2))
.flatMap { listOf(it.first, it.second) }
.sorted()
.mapIndexedNotNull { index, packet -> if (packet === divider1 || packet === divider2) index + 1 else null }
.reduce(Int::times)
It may not be the most performant (although it is decent), but it's pretty straightforward: split and map are parsing the input, then insert the dividers (as I used pairs in part 1 I reused that bit) and make one giant list (removing the pairs), then just sort, find the indices of the dividers and multiply themDavio
12/13/2022, 9:46 AMAlex LO
12/13/2022, 10:04 AMephemient
12/13/2022, 10:05 AMAlex LO
12/13/2022, 10:05 AMAlex LO
12/13/2022, 10:06 AMephemient
12/13/2022, 10:17 AMAlex LO
12/13/2022, 10:17 AMephemient
12/13/2022, 10:18 AMDan Fingal-Surma
12/13/2022, 10:21 AM@Suppress("CyclomaticComplexMethod", "NestedBlockDepth", "ReturnCount")
lolephemient
12/13/2022, 10:27 AMDavio
12/13/2022, 11:14 AMwhen
you can't match literals and conditions? Would be nice if you could do something like:
when (c) {
'[' ->
Char::isDigit ->
}
Michael Böiers
12/13/2022, 11:24 AMMichael Böiers
12/13/2022, 11:24 AMDavio
12/13/2022, 11:27 AMMichael Böiers
12/13/2022, 11:28 AMDavio
12/13/2022, 11:28 AMPaul Woitaschek
12/13/2022, 1:49 PMCharles Flynn
12/13/2022, 3:30 PMAlex LO
12/13/2022, 3:55 PMOzioma Ogbe
12/13/2022, 3:58 PMOzioma Ogbe
12/13/2022, 4:00 PMCharles Flynn
12/13/2022, 4:06 PMCharles Flynn
12/13/2022, 4:07 PMJson.parseToJsonElement(it)
Not sure if that was cheating or not 🙂Davio
12/13/2022, 4:23 PMephemient
12/13/2022, 4:25 PMJacob Moulton
12/13/2022, 5:49 PMDavio
12/13/2022, 6:01 PMphldavies
12/13/2022, 6:09 PMDavio
12/13/2022, 6:49 PMDavio
12/13/2022, 7:00 PMprivate fun parsePacket(line: String) = parseJson(Json.decodeFromString<JsonArray>(line))
private fun parseJson(jsonElement: JsonElement) : Packet {
return when (jsonElement) {
is JsonArray -> PacketList(jsonElement.map { parseJson(it) })
is JsonPrimitive -> PacketValue(<http://jsonElement.int|jsonElement.int>)
else -> throw IllegalStateException()
}
}
So some good ol' recursion to parse arrays in arrays in arrays...Fredrik Rødland
12/13/2022, 8:45 PMzip
call when comparing the lists, and found that using asSequence
on the result from zip
reduced the number of comparisons considerably
part 1 - 2266 => 598
part 2 - (sort of entire list) 32933 => 10427todd.ginsberg
12/13/2022, 8:46 PMzip
Fredrik Rødland
12/13/2022, 8:47 PMtodd.ginsberg
12/13/2022, 8:48 PMÇAĞRI YILDIRIM
12/13/2022, 8:48 PMtodd.ginsberg
12/13/2022, 8:49 PMSequence<String>
instead of Iterator<String>
and I gave up on it because I was getting frustrated. Maybe I’ll come back to it after.Fredrik Rødland
12/13/2022, 8:50 PMjson-simple
from google)Fredrik Rødland
12/13/2022, 8:50 PMfun from(input: Any): Packet {
return when (input) {
is String -> from(JSONValue.parse(input))
is JSONArray -> ListPacket(input.map { from(it!!) })
is Long -> IntPacket(input.toInt())
is Packet -> input
else -> error("$input type is " + input.javaClass)
}
}
Davio
12/13/2022, 8:51 PMFredrik Rødland
12/13/2022, 8:58 PM.firstOrNull { it != 0 } ?: subPackets.size.compareTo(other.subPackets.size)
could be simplified to
.firstOrNull { it != 0 } ?: (size - other.size)
which I find neat - but maybe a bit more obscure?Joakim Tall
12/13/2022, 9:04 PMJoakim Tall
12/13/2022, 9:05 PMJoakim Tall
12/13/2022, 9:29 PMzipWithNull
😄maiatoday
12/13/2022, 9:35 PMindexOf
gives some stack overflow error so I ended up chasing through the list and manually counting elements lower than the dividers.maiatoday
12/13/2022, 9:35 PMDan Fingal-Surma
12/13/2022, 9:38 PMsealed interface PacketData : Comparable<PacketData>
data class ListValue(val values: List<PacketData>) : PacketData {
override fun toString() = values.toString()
override operator fun compareTo(other: PacketData): Int = when (other) {
is ListValue -> values.zip(other.values).asSequence()
.map { (a, b) -> a.compareTo(b) }
.firstOrNull { it != 0 } ?: values.size.compareTo(other.values.size)
else -> compareTo(ListValue(listOf(other)))
}
}
data class IntValue(val value: Int) : PacketData {
override fun toString() = value.toString()
override operator fun compareTo(other: PacketData): Int = when (other) {
is IntValue -> value.compareTo(other.value)
else -> ListValue(listOf(this)).compareTo(other)
}
}
xxfast
12/13/2022, 9:56 PMfun format(line: String): List<Any> =
buildList {
var index = 0
var number = ""
while (true) {
if (index > line.lastIndex) break
var char = line[index++]
when {
char == ',' && number.isNotBlank() -> {
add(number.toInt())
number = ""
}
char.isDigit() -> number += char
char == '[' -> {
val start = index
var depth = 1
while (depth != 0) {
char = line[index++]
if (char == '[') depth++
if (char == ']') depth--
}
val end = index - 1
add(format(line.substring(start until end)).toList())
}
}
}
if (number.isNotBlank()) add(number.toInt())
}
.also { check("[${line}]" == it.toString().replace(" ", "")) { "Failed to parse $line" } }
wakingrufus
12/13/2022, 11:31 PM