Created
December 13, 2022 16:03
-
-
Save zoldar/e4857df1b9906c7f418cbe8795c9ab15 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sequtils, strformat, strutils, algorithm | |
type | |
CheckResult = enum Valid, Equal, Invalid | |
PacketKind = enum Seq, Int | |
Packet = ref PacketObj | |
PacketObj = object | |
case kind: PacketKind | |
of Seq: seqVal: seq[Packet] | |
of Int: intVal: int | |
proc `$`(p: Packet): string = | |
if p.kind == Int: | |
result.add($p.intVal) | |
else: | |
result.add("Packet{") | |
for x in p.seqVal: | |
if result.len > "Packet{".len: result.add(",") | |
result.addQuoted(x) | |
result.add("}") | |
proc parsePacket(input: string): Packet = | |
if input.startsWith("["): | |
let contents = input[1..^2] | |
var depth: int | |
var elements: seq[string] | |
var element: seq[char] | |
for ch in contents: | |
case ch: | |
of '[': | |
element.add(ch) | |
depth.inc | |
of ']': | |
element.add(ch) | |
depth.dec | |
of ',': | |
if depth == 0: | |
elements.add(element.join) | |
element = @[] | |
else: | |
element.add(ch) | |
else: | |
element.add(ch) | |
if element.len > 0: elements.add(element.join) | |
return Packet(kind: Seq, seqVal: elements.mapIt(parsePacket(it))) | |
else: | |
return Packet(kind: Int, intVal: parseInt(input)) | |
proc readPackets(input: seq[string]): seq[Packet] = | |
input.filterIt(it != "").mapIt(parsePacket(it)) | |
proc checkPair(pair: (Packet, Packet)): CheckResult = | |
let (left, right) = pair | |
if left.kind == Int and right.kind == Int: | |
if left.intVal < right.intVal: | |
return Valid | |
elif left.intVal == right.intVal: | |
return Equal | |
else: | |
return Invalid | |
elif left.kind == Seq and right.kind == Int: | |
return checkPair((left, Packet(kind: Seq, seqVal: @[right]))) | |
elif left.kind == Int and right.kind == Seq: | |
return checkPair((Packet(kind: Seq, seqVal: @[left]), right)) | |
else: | |
for innerPair in zip(left.seqVal, right.seqVal): | |
let checkResult = checkPair(innerPair) | |
if checkResult in [Valid, Invalid]: | |
return checkResult | |
let leftLen = left.seqVal.len | |
let rightLen = right.seqVal.len | |
if leftLen == rightLen: | |
return Equal | |
elif leftLen < rightLen: | |
return Valid | |
else: | |
return Invalid | |
var sum: int | |
let packets = readPackets("day-13/input.txt".lines.toSeq) | |
for (idx, pair) in packets.distribute(packets.len div 2).pairs: | |
echo fmt"Pair #{idx+1}" | |
let left = pair[0] | |
let right = pair[1] | |
echo left | |
echo right | |
if checkPair((left, right)) in [Valid, Equal]: | |
echo "Valid!" | |
sum.inc(idx+1) | |
else: | |
echo "Invalid!" | |
echo "===" | |
echo fmt"Sum of indices of valid packet pairs: {sum}" | |
let dividerPackets = readPackets(@["[[2]]", "[[6]]"]) | |
var packetsWithDividers = packets.concat(dividerPackets) | |
packetsWithDividers.sort do (x, y: Packet) -> int: | |
case checkPair((x, y)): | |
of Invalid: 1 | |
of Equal: 0 | |
of Valid: -1 | |
var dividerIndexes: seq[int] | |
for (idx, packet) in packetsWithDividers.pairs: | |
if packet in dividerPackets: | |
dividerIndexes.add(idx + 1) | |
echo fmt"Decoder key: {dividerIndexes.foldl(a * b)}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment