Véget ért az AoC2025, picit korábban, mint hagyományosan, ellenben a feladatok nem lettek könnyebbek!
Idén én is részt vettem az Advent of Code-ban, ami egy adventi kódolós kihívás, hagyományosan december elsején kezdődik, és december 25-én ér véget. Minden nap van egy feladat, egy probléma, ami színesítve van valamilyen karácsonyi szöveggel – ellenben az csak a díszítés, a hab alatt programozási és matematikai problémák vannak a való életből, amik elő jöhetnek egyes feladatoknál. Egy pár példa az idei évből: gráfok, Gauss-elimináció, kódfejtés, és egyéb finomságok. De nézzük is napról napra, hogy mik voltak a feladatok, és hogy én hogyan teljesítettem.
A feladatokat Kotlin nyelven oldottam meg, és github-ra is feltöltöttem az aznapi megoldásomat: https://github.com/T0liver/advent-of-code-2025
A cikket színesítettem az közösség hivatalos subreddit-jéről származó mémekkel, illetve vizualizációkkal, hogy annak aki nem követte idén is átláthatók legyenek a feladatok, aki pedig kódolt idén, az nevessen ezeken egy jót! https://www.reddit.com/r/adventofcode/
Az idei sztori az az, hogy az elf-ek felfedezték a projekt menedzsmentet, így könnyebb dolguk van a feladatok szervezésében, azonban rájöttek arra is, hogy túl kevés idejük van ahhoz, hogy rendesen feldíszíthessék az északi sarkot.
Első nap: a titkos bejárat
Az első napon egy kódfejtős feladat volt, ahol az északi sarki bázis ajtaját kellett kinyitni modulo segítségével. Ekkor még nem igazán jöttem bele a Kotlin nyelvbe se, meg az egész AoC-ba se, így valamit alkottam Pyton-ban meg C-ben, de végül megkaptam a csillagot!
Második nap: az ajándékbolt
A második napon az ajándékboltban kellet segíteni az elf-eknek, hogy megtalálják a lejárt portrékákat.
Meg voltak adva a termékek azonosítója intervallumokkal (pl. 10-100), és ezekből az intervallumokból kellett kiválogatni a hibás termékeket. Az számított az első részben hibás terméknek, amiben volt egy ismétlés, tehát a példaintervallumból ilyen a 11, a 22, a 33, …, a 99, de egy tágabb intervallumból a 1010 is, mert a 10 ismétlődik benne kétszer, amikor ezt leírjuk. A második részben ennél általánosabb algoritmust kellett írni, ami minden ismétlődést megtalál, nem csak azokat, amik kétszer vannak benne, hanem az összes szakaszt, ami ismétlődik egy számban, és a szám csak ilyen szakaszokból áll.
Én ennek elsőre Pythonban ugrottam neki, majd megírtam Kotlinban is, ugyanazt a logikát, amit az előbb felvázoltam.
Harmadik nap: lobby
A harmadik napon tovább jutottunk a bázisban, egy lobbi helyiségbe, ahol liftek vannak, azonban ezek nem üzemelnek, így nem tudunk tovább jutni. A liftek üzemeltethetőek elemekről, amiket viszont be kell kapcsolni a lehető legnagyobb értékkel. Ezek az elemek bankokba vannak rendezve, minden bankban 15 elem található.
Az első részben meg kellett találni minden bankban az a kettő elemet, aminek az értéke a legnagyobb számot tette ki, ha sorrendben egymás mellé rakjuk őket. Tehát pl.: 811111111111119 -> 89. Viszont ez még nem volt elegendő áram, így második részben pedig pontosan 12 elemet kellet kiválasztani minden egyes bankból, és ezekből képezni a legnagyobb számot, ami lehetséges, ami nehezebbé tette a problémát.
Az első résszel gyorsan végeztem, ellenben a másodikkal, ahol a közösség több tagjával egyetemben rá kellett jönnöm (szerencsére nekem gyorsabban ment mint másnak, a reddit alapján), hogy a brute-force nem fog gyors megoldásra vezetni, így átírtam a függvényeimet.
Negyedik nap: nyomda
Miután túljutottunk a lifteken egy nyomdában találjuk magunkat, ami elsőre zsákutca, ellenben az itt lévők tudják az utat: át kell törni a falat!!!4!!4! Bármennyire is abszurd, ők szívesen segítenek ebben, azonban a targoncák el voltak foglalva, mert épp dolgoznak. Így segíteni kellett nekik optimalizálni a munkát, hogy segíthessenek (rombolni) továbbjutni.
Éppen papír gurigákat szedtek le a polcokról a targoncák, azonban csak azokhoz a papír gurigákhoz tudnak ezek a targoncák hozzáférni, amiknek a környezetében csak kevesebb mint 4 másik guriga van. Így az első részben meg kellett adni azon gurigák számát, amiket el tudtak mozdítani, a második részben pedig tovább kellett iterálni, és megadni az összes guriga számát, amit az egyes eltávolítások után még tovább el tudnak távolítani.
Ez kellemes felüdülés volt az előző kettő feladat második részéhez képes, hiszen itt csak egy while loop-ba kellet betenni a már megírta algoritmust, és a végtermékeket összeadni. Huhh!
Ötödik nap: kávézó
Miután áttörték az elf-ek a falakat nekünk a kávézóban találjuk magunkat, ahol a összekeveredtek a hozzávalók. Mivel az élelmiszer-biztonság nem gyerekjáték, azért ezeket az összetevőket ki kell válogatni, nehogy romlott alapanyag kerüljön valamelyik ételbe. Szerencsére az elf-ek listát vezettek erről is, felírva minden alapanyag azonosítóját, és azokat az intervallumokat, amikbe eső alapanyagok frissek.
Az első rész egész egyszerű volt, meg kellet keresni az összes friss azonosítót, és ennek a száma volt a válasz. A második rész, azonban kicsit bonyolultabb volt, halmazelméleti kérdéseket feszegetve, ugyanis itt meg kellett adni, hogy hány darab azonosító lehet friss az intervallumok alapján.
Ennek elsőre úgy estem neki, hogy a Halmaz (Set), úgyis egy létező nyelvi elem, dobjunk be mindent egy nagy halmazba, majd ennek a halmaznak a mérete lesz a pontos válasz. Elsőre jónak is tűnik, nem? Hiszen a Halmaz típus teljesíti azt, hogy minden elem csak egyszer szerepeljen. Igen, csak ez ugyanakkor lefoglal minden elemnek elemnek memóriaterületet, és itt kellett rájönnöm, hogy az AoC-ban az adatok azok nem rövidek, hogy nyelvi elemekkel meg lehessen oldani, és a válaszok meg nem akkorák, hogy egy normális szám méretébe (Int, max: 232-1) beleférne, és érdemes minden nagyobbnak tűnő eredményt hosszú számként kezelni (Long, max: 263-1). Aki nem gondolkodott tovább könnyen járhatott így:
De a helyes algoritmus a következő módon működött:
Hatodik nap: szemétlerakó
Miután segítettük a kávézóban, továbbhaladva a szintek között egy filmes jelenet után egy szemétlerakóban találjuk magunkat, ami mágneses ajtókkal van bezárva – de itt is élnek lények! Egy cephalopod család lakik itt, akik segítenek kijutni a gödörből, ha segítünk a legkisebb cephalopod matek házijában.
A feladat a következő:
123 328 51 64
45 64 387 23
6 98 215 314
* + * +
Ahol nem a sorokat adjuk össze, hanem az oszlopokat az az alatt lévő művelet alapján. Legalábbis ez az első rész.
A második részben kiderül, hogy félreértettük, és még az oszlopokban a számokat se sor alapján, hanem oszlop alapján nézik, és azt is fordítva, tehát az első feladvány nem az, hogy 123 * 45 * 6 = 33210, hanem hogy 56 * 24 * 1 = 8544, ami egy másik eredmény…
Vizualizáció:
És mém:
Hetedik nap: laboratórium
Miután segítettünk a chephalopod kisgyerek matekházijában, és kijutottunk a szemétlerakó rejtelmei közül, egy tábla jelzi, a teleportációs labor helyét. Mivel teleportációval előbb túljutunk akadályokon, így benézünk ide. A teleportációs eszköz elromlott sajnos, de van egy rakat használati útmutató, ami alapján meg lehet javítani, és amik alapján kiderül, hogy a tachion sokszorosítóval van a probléma.
A bemenet egy karácsonyfához hasonlító dolog volt, aminek a tetején indul el a sugár, és ha a sugár alatt van egy sokszorozó, akkor a sugár a sokszorozótól balra, illetve jobbra folytatja az utat egyszerre, míg szépen a végére nem ér a „pályának”. Az első részben az volt a feladat, hogy kiszámítsuk a bemenet alapján (ami nyilván annyira nagy, hogy kézileg nem érdemes nekiugrani), hogy a fentről elinduló sugár hányszor fog ketté szorzódni, amíg végigér a pályán. Ezt egyszerű sztring műveletekkel meg lehetett oldani.
A második részben megint kiderült, hogy rosszul értelmeztük a feladatot, ugyanis ez egy kvantum tachion sokszorozó! Ez azt jelenti, hogy egy jel minden elágazásban két felé mehet, és megy is, de csak az egyik irányba megy. Ha nem érted, akkor jó, mert a kvantum az ilyen! Itt a megoldást az adta ki, hogy a tetejéről hány féle úton juthat el a sugár az aljára.
Nyolcadik nap: játszótér
A teleportáló eszköz működik! Rálépünk a portálra, és hirtelen egy másik helyen találjuk magunkat. Ez egy játszótér, ami tele van kapcsolódobozokkal, amik a gigantikus játszótér díszvilágításáért felelnek. Az elf-ek épp próbálják összekötni a fényeket, viszont tudniuk kell, hogy mennyi kábel kell az összeköttetéshez. Első részben az volt a feladat, hogy az 1000 legrövidebb távolság összekötése után, hány elemből áll a három legnagyobb egybefüggő, tulajdonképpen gráf. Miután ezt megválaszoltuk, a manók rájöttek, hogy egy kevés fény még, így a második részben az egész gráfot össze kellett kötni úgy, hogy mindig a legrövidebb éleket húzzuk be, a válaszként pedig azt kellet megmondani, hogy az utolsó kettő összekötött kapcsolódoboz X koordinátájának a szorzata az mennyi, csak hogy pontosan működő algoritmust kelljen írni.
Így aztán megírtam az algoritmus elméletből tanult gráfos algoritmust, ami kisebb csiszolások után jól működött!
Kilencedik nap: mozi
Ezek után belecsöppentünk egy moziterembe, ahol az elf-ek épp a padlót díszítették fel szőnyegekkel, és különböző színű csempékkel. A padló bizonyos csempéi pirosak voltak, és a feladatban ez számított, ugyanis az első részben meg kellett keresni azt a kettő piros csempét, amivel meg lehet határozni a legnagyobb területű téglalapot a padlón, hogy tudják az elf-ek mekkora szőnyegdarabbal számoljanak.
Természetesen miközben mi számoltuk a megoldást, új ötletük lett, és a piros csempék közé zöld csempéket helyeztek egyenes vonalban, ezáltal egy konkáv alakzatot létrehozva a padlón. A második részben azt kellett megválaszolni, hogy ebben a konkáv alakzatban mekkora a legnagyobb téglalap, amit el lehet helyezni, és a téglalap egésze benne van az alakzatban. Na ez már jobban feladta a leckét, ugyanis a csempék úgy voltak elhelyezve, hogy majdnem egy tökéletes kör legyen egy kis bökkenővel – volt egy hatalmas beszögellés az alakzatban! Így aztán minden keresés után ellenőrizni kellet, hogy benne van-e a téglalap egésze az alakzatban, ami nehezítette, és lassította a dolgokat.
Tizedik nap: az üzem
Kilépve a most már színes padlózatú moziteremből egy gyárban találjuk magunkat, ahol az elf-ek éppen a dekoráción sürgölődnek – vagyis sürgölődnének, hogyha nem lennének leállítva a gépek egy hiba miatt. Tanulmányozás után az is kiderül, hogy az inicializáláskor esik szét a folyamat, mert az inicializáló procedúrát megette egy Shiba Inu (a kutya). Ahhoz, hogy be lehessen kapcsolni, a megmaradt útmutatók alapján ki kellett logikázni, hogy hogyan kell az egyes gépeken megnyomni a gombokat, hogy azok bekapcsolódjanak. Mutatom egy gép felvázolását:
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
Az első része azt mutatja meg, hogy melyik jelzőknek kell égniük, azaz [.##.] alapján a másodiknak és a harmadiknak (a # jelölte a bekapcsolandó jelzőket). Ezek után a gombok voltak felsorolva, hogy melyik gomb, melyik jelzőfényt kapcsolja fel, illetve le. A végén pedig a joltage igények vannak a feladvány második részéhez.
Az első részben azt kellett megadni, hogy a masinákat hány kattintással lehet felkapcsolni, ha mindig a legkevesebbre törekszünk (hatékonysági okokból kifolyólag). Ezt viszonylag gyorsan, Gauss-eliminációval meg lehetett oldani, ahol egy n * m-es mátrix oszlopai az egyes gombok voltak, és az oszlopban ott volt egyes, ahányadik fényt az adott gomb fel tudta kapcsolni, és az utolsó oszlop pedig a kívánt fényállapot volt. Mutatom a példa bemenetre:

Ezek alapján már szinte szemmel is össze lehet rakni, hogy melyik gombokat kell bekapcsolnunk, de azért a Gauss-elimináció eredménye is a következő lett: a 4-es és az 5-ös (vagyis az 5-ös és a 6-os gombot, csak a táblázat, mint ahogy a megoldás is 0-tól indexel (mint ahogy minden az informatikában)) gombokat kell egyszer-egyszer megnyomni, hogy pontosan a megjelölt fények villanjanak fel. Egyszerű, nem?
De, ez még könnyedén ment, ellenben a második résszel, ami két napomba tellett (közben zh-tam kettőt, és igazán csak a második zh után tudtam megoldani). Itt már az volt a feladat, hogy az eddig elhanyagolt joltage igényeket kis kielégítsük, azaz, ami a két {} között van, pontosabban, hogy a gombokat úgy nyomjuk meg szimultán, hogy igazából a fényeknél pontosan annyi joltage (pont) legyen, amennyi az igény, és természetesen ezt is a legkevesebb gomb megnyomásával.
Véleményem, és mások szerint is ez volt a legnehezebb nap és feladat az összes közül, nekem két napomba tellett, de az átlag az az ilyen 1 nap volt, mivel ezt vagy annyira memória és processzor igényesen lehet megírni, hogy sok idő lefuttatni (már ha egyáltalán le tud futni, és nem telik meg a memória), vagy eléggé nehéz első ránézésre olyan algoritmust írni, ami gyorsan le tud futni, főleg, ha ismeretlen a nyelv, nem algoritmus tudós az ember (ezen persze az AoC megoldásával lehet javítani), vagy csak már régen volt a számításelmélet, meg az algoritmuselmélet. Nekem mellesleg ez volt a legtovább futó kódom, a többi feladat ilyen kb. 1 másodperc (vagy kevesebb) alatt kiköpte a megoldást, itt viszont fél percet várni kellett, mire mind a 156 gépezet joltage igényeit kiszámolta, de végül helyesen. Ha valaki megnézi a github repo-mban, ezt a rész találhatja az egyik legkaotikusabbnak, ahol picit össze-vissza van a kód, de szerencsére olvasható, és nem spagetti.
De emellett volt olyan is, akinek még volt elég ideje ezen a feladaton töprengeni, és készített egy egészen menő oldalt, ami vizualizálja a feladatot dobgépekkel. Érdemes ránézni, mivel több napnak is elkészítette az interaktív vizualizációját!
https://danmaps.github.io/aoc2025/public/index.html#day=10
Tizenegyedik nap: reaktor
Ebben a feladatban egy reaktorhoz értünk le, ahol a kis manók éppen egy új szervert üzemeltek be, és ezt a szervert össze kötötték a reaktorral – azonban ez nem volt sikeres, és nem jött létre a kapcsolat, mert voltak hibás modulok a rendszerben, ezért meg akarták tudni, hogy bizonyos helyekről hány út vezet a végső kimenetbe.
A feladat lényege az volt, hogy ezek a modulok igazából gráf csomópontok, mégpedig egy irányított, körmentes gráf csomópontjai (DAG), és ebben kellett megkeresni az összes utat, az első részben a „you” pontból az „out” pontba, a második részben pedig a „svr” (mint szerver) pontból ugyancsak az „out” pontba, azonban itt a „dac” (digital-to-analog) és a „fft” (fast-fourier transformation) pontokat is érinteni kellett.
Én ezt úgy oldottam meg, hogy a bemenetből készítettem egy topológikus elrendezést, amiben megkerestem mindig a legrövidebb utat a kezdő és a végpont között, majd ezt az utat „invalidáltam”, és újra kerestem a legrövidebb utat, ami az eredeti gráfban már a második legrövidebb út valójában, és így tovább, amíg már nem létezett út a kezdő és végpont között. A második részben ugyanezt csináltam, csak itt több darabra szedtem a gráfot és a keresést, hogy gyorsabb és hatékonyabb legyen. Először megkereste az utakat a „svr”-től a „ftt” pontig, majd az „ftt”-től a „dac” pontig, és végül a „dac” ponttól az „out” pontig, az összes létező út száma pedig ezen három keresés szorzata lett. Ezt elvégeztem még egyszer, csak felcseréltem az „ftt” és a „dac” pontokat a keresésben, hiszen, ahogyan a feladatkiírásban is szerepelt, a két pont tetszőleges sorrendben lehetséges. Helyes pedig azért lesz, és azért nem lesznek egyes utak többször számolva, mivel a gráf körmentes.
Tizenkettedik nap: karácsonyfa telep
A mai nap picit kaotikus volt számomra, mert a megoldás ilyen, működik, de hogy miért… valszeg mert a bemeneti fájlt kedvesen állították össze.
Az utolsó napon nem kettő, hanem csak egy feladatot kellett megoldani, mégpedig azt, hogy vannak furcsa alakú ajándékok, és ezeket el kell helyezni adott területű placcokra, és az is meg volt adva, hogy mennyiből hány darabot kell tenni. A kérdés az az volt, hogy az 1000 megadott helyzetből hányszor férnek bele a területbe az ajándékok össze puzzle-zva.
A megoldás pedig nem volt nehéz, mert ebbe az esetben (mivel kedves volt a bemeneti fájl), elég volt összeszorozni 9-el az egyes ajándékokat, és megnézni, hogy az belefér-e a terület lefelé való kerekítésébe. Ennyi. Ha nem lett volna kedves az alkotó, akkor még karácsonyig is ezen agyalnánk, hogy hogyan lehet ezt megoldani.
Illetve az idei AoC röviden:
A kész kalendárium!
Az utolsó feladat megoldása után a történet szerint az összes eddigi elf, akinek segítettünk a kaland folyamán megjelent, és hozták a megszerzett csillagokat, hogy feldíszítsék a karácsonyfát.
Elérkezve a végéhez, a naptár, ahol vártuk napról-napra a feladványokat kiszínesedett, és a következőképpen néz ki:

Ugye de szép?
Boldog karácsonyt minden kedves olvasómnak (így előre is)!
kiemelt kép forrása: Todd Ginsberg’s blog

Nagyon jó cikk! Nagyon szépen összeszedted a feladatokat! Kedvet kaptam, hogy én is megcsináljam ezt jövőre. Gratulálok a megoldáshoz! Várom a következő cikket!
Addig is csodaszép karácsonyt előre is!🎄
Lelkes olvasód
Szuper, külön tetszik, hogy egy fájlban tartod a kódot — egyszerű és praktikus. Várom a következő bejegyzést!!