Advent of Code 2021: administratieve rompslomp

Rachid Wilco Achter de schermen

December was weer de tijd van de puzzels van Advent of Code. Zoals altijd hebben we bij Infi ook onze eigen Infi-puzzel, die volgens traditie weer lekker moeilijk was. Maar de inzet was niet voor niets, want de beste inzendingen hebben onze exclusieve Infi-handdoek mogen ontvangen.

Bij Infi staan we elke keer weer te springen als de maand December in de buurt komt. Niet door de oliebollen of Sinterklaas, maar vanwege Advent of Code! Een advent kalender met elke ochtend een nieuwe programmeerpuzzel om je brein over te breken.

Al jaren zijn wij trouwe sponsoren en het is inmiddels ook traditie geworden om ieder jaar onze eigen Infi puzzel uit te brengen. Zo ook dit jaar. En een beloning voor het harde werk mag uiteraard ook niet ontbreken: De auteurs van de vijf beste (of gekste) oplossingen krijgen een exclusieve Infi handdoek toegestuurd. De allerbeste puzzelaar krijgt daarbovenop een gift card naar keuze!

Het thema van dit jaar is een feestelijke administratieve rompslomp: Help de Kerstman bij het ordenen van zijn speelgoed-onderdelen. De uitdaging is vervolgens om onderdelen als printplaten en batterijen om te zetten in lightsabers en ander speelgoed. Ook dit jaar hebben we weer kunnen genieten van de geniale oplossingen die zijn bedacht. Een paar van de uitspringers:

CeeScherp

Voor Geerten was enkel de oplossing vinden niet genoeg. Door middel van C# en een eigen NuGet package genaamd CeeScherp, weet hij een volledig Nederlandstalige solver neer te zetten. Alle benodigde types en datastructuren heeft hij nauwkeurig vertaald. In plaats van ‘int’ is het getal, en het is geen ‘Array’ maar een rij. Het resultaat is erg vloeiende code dat wegleest als een boek.

rij<sliert> regels = speelgoedLijst
    .Splits(new rij<karakt>('\n', '\r'), SliertOpsplitsOpties.VerwijderLegeInzendingen)
    .AlsRij();

getal alGevuldeRuimte = regels[0]
    .Splits(' ', SliertOpsplitsOpties.VerwijderLegeInzendingen)
    .En().NeemDeEerste().AlsGetal();

var alleOnderdelen = new Woordenboek<sliert, Onderdeel>();

 

Eval regex

Jeff vond het belangrijk om de antwoorden in stijl te printen:

console.log(`infi@nerd-pc ~/aoc2021 ▶ ${part1}`);

Verder besloot hij slim gebruik te maken van een combinatie van regex en `eval`, waarbij hij zich goed bewust was dat dat eigenlijk niet hoort:

/*
regex's _and_ eval? this might be against the geneva conventions
converts partslist into numerical expression.
example:
73 Schokdemper, 97 IJzer ->
73*(17 IJzer, 89 Staal), 97 IJzer ->
73*(17+89)+97, which is then "eval"-ed
*/
numParts:
    eval(info.split(":")[1].replace( /,/g, "+").replace( /[a-z ]/ig, ""))

 

Tail recursion

De inzendingen zijn natuurlijk niet compleet zonder een oplossing in een functionele taal.

Anita bedacht deze mooie recursieve oplossing in Scala:

@tailrec
def takeApart(partsMap: Map[String, Map[String, Int]]): Map[String, Map[String, Int]] =
    if (!partsMap.values.flatMap(_.keys).exists(partsMap.contains)) partsMap
    else takeApart(partsMap.map { case (toy, parts) => toy -> parts.toList.flatMap {
    case (part, n) =>
        if (partsMap.contains(part))
        partsMap(part).map { case (innerPart, m) => innerPart -> n * m }
        else Map(part -> n)
    }.groupBy(_._1).map { case (k, v) => k -> v.map(_._2).sum } })

 

We waren dit jaar weer blij verrast door het aantal inzendingen. Het zijn er te veel om hier allemaal te laten zien, maar we hebben veel verschillende oplossingen zien langskomen.

Van C# tot C++, Java en Python, Go en Rust, ieder had zijn eigen manier om de puzzel op te lossen. En dat is dan ook het mooie van Advent of Code: iedereen begint met dezelfde puzzel, en lost die dan op zijn eigen manier op.

Hopelijk hebben jullie genoten van onze puzzel, wij hebben er in ieder geval weer veel plezier gehad van het bedenken van de puzzel. En hopelijk zien we jullie in december weer terug!

Een afspraak maken bij ons op kantoor of wil je even iemand spreken? Stuur ons een mail of bel met Jolanda.