blog picture

Advent of Code, dag 1

Geschreven door: Pim Vrolijks
Datum: 09-12-2024 22:52

Dag 1 start over het algemeen redelijk eenvoudig. Dus laten we eens zien wat we moeten doen om de eerste puzzel op te lossen. Vooropgesteld, de oplossing die ik bedenk kan wellicht eenvoudiger of op een andere manier worden gevonden. Maar dat is juist het leuke van deze puzzels, alleen het antwoord moet juist zijn, de weg er naar toe kan op vele manieren bewandeld worden. 

De eerste opdracht van dag 1:

Throughout the Chief's office, the historically significant locations are listed not by name but by a unique number called the location ID. To make sure they don't miss anything, The Historians split into two groups, each searching the office and trying to create their own complete list of location IDs.

There's just one problem: by holding the two lists up side by side (your puzzle input), it quickly becomes clear that the lists aren't very similar. Maybe you can help The Historians reconcile their lists?

For example:
3   4
4   3
2   5
1   3
3   9
3   3

Maybe the lists are only off by a small amount! To find out, pair up the numbers and measure how far apart they are. Pair up the smallest number in the left list with the smallest number in the right list, then the second-smallest left number with the second-smallest right number, and so on.

Within each pair, figure out how far apart the two numbers are; you'll need to add up all of those distances. For example, if you pair up a 3 from the left list with a 7 from the right list, the distance apart is 4; if you pair up a 9 with a 3, the distance apart is 6.

In the example list above, the pairs and distances would be as follows:

  • The smallest number in the left list is 1, and the smallest number in the right list is 3. The distance between them is 2.
  • The second-smallest number in the left list is 2, and the second-smallest number in the right list is another 3. The distance between them is 1.
  • The third-smallest number in both lists is 3, so the distance between them is 0.
  • The next numbers to pair up are 3 and 4, a distance of 1.
  • The fifth-smallest numbers in each list are 3 and 5, a distance of 2.
  • Finally, the largest number in the left list is 4, while the largest number in the right list is 9; these are a distance 5 apart.

To find the total distance between the left list and the right list, add up the distances between all of the pairs you found. In the example above, this is 2 + 1 + 0 + 1 + 2 + 5, a total distance of 11! What is the total distance between your lists?

Antwoord van de eerste puzzel:

Goed, dus we moeten allereerst de locaties van zowel de linker- als rechtrij op volgorde van laag naar hoog zetten. Daarna het verschil bepalen tussen de getallen die naast elkaar komen te staan en deze dan sommeren tot het juiste antwoord. 
Met de 6 gegeven rijen is dat natuurlijk makkelijk te doen. Maar de daadwerkelijke input bestaat uit 1000 regels met vijfcijferige getallen! That is another cookie!

Zodra we de puzzelinput in een tabel in een SQL database hebben gezet was het mijn idee om van de linker- en de rechterrijen twee tabellen te maken met een oplopend nummer zodat ik straks de twee tabellen naast elkaar kan zetten. 

CREATE TABLE #LeftInput (
    RowNum [int] IDENTITY(1,1) NOT NULL,
    Input [int] NOT NULL
    )

CREATE TABLE #RightInput (
    RowNum [int] IDENTITY(1,1) NOT NULL,
    Input [int] NOT NULL
    )
Door de Identity toe te wijzen wordt een insert in de tabel altijd aangemaakt met een opvolgendnummer.
Nu de tabellen bestaan kunnen we ze vullen. Daarbij weten we officieel niet hoelang elk Location ID is. Dus we zullen moeten kijken welke getallen we zien totdat we bij een " " komen waar het getal ophoudt. Dit moeten we zowel vanuit de linkerkant van een regel, als de rechterkant van de regel doen. Een mogelijkheid hiervoor is om in SQL gebruik te maken van de charindex (de index van een tekst waarop een gegeven teken voorkomt). We willen dus weten wanneer voor het eerst een " " voor komt in de regel. Dit willen we er vervolgens uithalen en omzetten naar een getal (int) zodat we ermee kunnen rekenen. Door de order by toe te voegen weten we zeker dat de data in een bepaalde volgorde in de tabel komt te staan. 

INSERT INTO #LeftInput ([Input])
SELECT CONVERT(int, LEFT(LocationList, charindex(' ', LocationList)-1))
FROM [AdventOfCode].[input2024].[Day1]
ORDER BY CONVERT(int, LEFT(LocationList, charindex(' ', LocationList)-1))

INSERT INTO #RightInput ([Input])
SELECT CONVERT(int, RIGHT(LocationList, charindex(' ', LocationList)-1))
FROM [AdventOfCode].[input2024].[Day1]
ORDER BY CONVERT(int, RIGHT(LocationList, charindex(' ', LocationList)-1))

Nu kunnen we alles bijelkaar gaan optellen. Omdat elke tabel dezelfde hoeveelheid regels heeft en dus dezelfde RowNum bevat kunnen we de getallen via die kolommen naast elkaar zetten.
Uit het gegeven voorbeeld blijkt dat je de afstand tussen twee getallen moet berekenen. Dit is niet simpelweg de ene van de ander aftrekken want dan kan je negatieve getallen krijgen. Dat is bij een afstand niet de bedoeling. Daarom zetten we met ABS() negatieve getallen om in positieve getallen. Als laatste sommeren we alles. 

SELECT SUM(ABS(t1.[Input] - t2.[Input])) AS [Diff]
FROM #LeftInput t1
INNER JOIN #RightInput t2
    ON t2.[RowNum] = t1.[RowNum]

Het antwoord van deze levert onze eerste gouden ster op!  

De tweede opdracht:

The Historians can't agree on which group made the mistakes or how to read most of the Chief's handwriting, but in the commotion you notice an interesting detail: a lot of location IDs appear in both lists! Maybe the other numbers aren't location IDs at all but rather misinterpreted handwriting.

This time, you'll need to figure out exactly how often each number from the left list appears in the right list. Calculate a total similarity score by adding up each number in the left list after multiplying it by the number of times that number appears in the right list.
Once again consider your left and right lists. What is their similatiry score?

Antwoord van de tweede puzzel:

Wat we nu moeten doen is tellen hoevaak de getallen in de rechterkolom (dus in #RightInput) voorkomen. Vervolgens vermenigvuldigen we die aantallen met de getallen uit de linkerkant. In eerste instantie komt hier een gigantisch getal uit. Maar ik bedacht me dat het niet gegeven is dat alle getallen in elke rij voorkomen, de getallen die wel in de linker- maar niet in de rechterrij voorkomen worden allemaal vermenigvuldigd met 0. 
Met onderstaande code tellen we de getallen in de rechterrij en slaan deze op in een common table expression:

;with cte_occurance AS (
    SELECT [Input]
          ,COUNT(*) AS [Occurance]
    FROM #RightInput
    GROUP BY [Input])
Vervolgens vermenigvuldigen we input uit de linkerrij met de aantallen die in "occurance" staan waarbij de input getallen die niet overeenkomen buiten beschouwing worden gelaten. 

SELECT SUM(t1.[Input] * t2.[Occurance])
FROM #LeftInput t1
LEFT JOIN cte_occurance t2
    ON t2.[Input] = t1.[Input]

De uitkomt uit deze sommatie blijkt de juiste te zijn! Twee gouden sterren in de tas!


Terug naar blogs

Laat als eerste een reactie achter!

Laat een reactie achter

Je mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *