Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
"The question of whether a computer can think is no more interesting than the question of whether a submarine can swim" - Edsger Dijkstra
Ja om deze reden heb ik een 'directions' enum geïntroduceerd die ook een cardinalDirections() functie heeft die een lijstje met enkel de horizontale en verticale directions teruggeeft omdat je in sommige puzzels wel en in andere puzzels weer niet diagonaal mag lopen.mbe81 schreef op dinsdag 10 december 2024 @ 11:04:
Oh, wat heb ik lopen kloten!
spoiler:Ik dacht slim te zijn wilde met een loop door de mogelijke offsets heen lopen. Dus ik twee geneste for loops gemaakt van -1 tot +1 waarbij ik natuurlijk de 0,0 offset oversloeg. Na ruim anderhalf uur ploeteren bedenk ik me dat ik nu ook de diagonale offsets meeneem dus -1, -1 terwijl je alleen horizontaal of verticaal mag bewegen... Inmiddels deel 1 en 2 klaar. Nadat ik mijn fout had ontdekt was dat niet heel moeilijk meer.
"The question of whether a computer can think is no more interesting than the question of whether a submarine can swim" - Edsger Dijkstra
Heb volgensmij wel een O(n) oplossing te pakken. Maar de oplossing kan niet meer dan 256 negens in de input aan. Draait in ongeveer 0.5ms zonder recursie.
Rust
[ Voor 17% gewijzigd door HannoOttens op 10-12-2024 12:01 . Reden: Duidelijkere uitleg ]
Mooi of lelijk, het is voor mij perfect (en duidelijk) om eens in te verdiepen. Zou fijn zijn om voor eens en altijd af te zijn van de recursive foutenGropah schreef op dinsdag 10 december 2024 @ 10:26:
[...]
Even snel een paste voor je gemaakt: *klik voor Kotlin code*. Let wel; het is verre van mooi of geoptimaliseerd.
spoiler:InputReader bevat allerlei methods om data in te lezen. In dit geval een grid van chars en daar een map van een zelf gemaakt Point class naar een char. Die Point kent ook een fourNeighbors functie voor horizontale en verticale buren. Deque is een Double Edge que, gezien kotlin geen normale queue heeft. Denk dat de rest wel redelijk vanzelf sprekend isMocht dat toch niet zo zijn, laat het weten
Dag 10.
while (me.Alive) {
me.KickAss();
}
Alles wat recursief is kan in een while-lus. En als je je while-lus goed opzet lijkt het heel erg op je recursieve codeSatom schreef op dinsdag 10 december 2024 @ 11:20:
[...]
Mooi of lelijk, het is voor mij perfect (en duidelijk) om eens in te verdiepen. Zou fijn zijn om voor eens en altijd af te zijn van de recursive fouten(al is dat hoogstwaarschijnlijk wishful thinking)
Het helpt ook dat mijn shared library in dit project het parsen e.d. van grids wel erg makkelijk maakt. Dat scheelt een hoop code.
[ Voor 37% gewijzigd door Marcj op 10-12-2024 12:02 ]
Dat waardeer ik enorm. Ik probeer wel eens andermans oplossing te runnen om de performance te vergelijken of een bug te vinden, en het kost belachelijk veel tijd om uit te vinden:Friits schreef op dinsdag 10 december 2024 @ 09:01:
Ik schrijf iedere keer "alles" opnieuw. Vind het leuk als iedere oplossing gewoon een zelfstandig werkend stukje code is, vooral ook zodat anderen (zowel hier als op Reddit) het zonder gedoe kunnen lezen en uitvoeren. Python is ook redelijk compact, dus heel tijd of ruimte win ik er niet mee.
- Hoe ik de boel kan builden (Maven? Cargo? go? sbt‽)
- Hoe ik de oplossing kan runnen (waar staan de binaries? java -classpath ...? etc.)
- Hoe ik een ander invoerbestand kan specificeren.
Daarop voortbordurend, wat vind je hiervan? Geeft wat mij betreft de symmetrie tussen deel 1 en deel 2 mooier aan. (En is ook nog aanzienlijk sneller, al weet ik dat het je daar niet om te doen is.)Vandaag paste alles weer in 10 regels
Deze kun je prima parallel draaien met rayon. Op mijn M1 Pro gaat dit best vlotSoultaker schreef op dinsdag 10 december 2024 @ 08:18:
Qua extra data is er niet veel interessants te bedenken vandaag, maar voor wie toch wil testen, hier een iets groter invoerbestand: aoc-2024-day-10-challenge-1.zip
$ time pypy3 solve.py < aoc-2024-day-10-challenge-1.txt ...036 ...780 real 0m5.309s user 0m5.177s sys 0m0.084s
1
2
3
4
5
| Executing ├── Input parsed in 2,051µs ├── Part 1 calculated in 12,563µs: 152036 ├── Part 2 calculated in 9,792µs: 8621780 └── Total time: 24,431µs |
Mee eens.Marcj schreef op dinsdag 10 december 2024 @ 12:00:
Ok, ik had dus hetzelfde als de rest. Zo blijkt deel 1 eigenlijk ingewikkelder dan deel 2 wat mij betreft.
Sowieso lijkt het vaak zo omdat je voor deel 1 de basis moet leggen, waarbij je allerlei foutgevoelige problemen zoals invoer inlezen, de juiste data structuren kiezen, etc. moet oplossen. Als deel 2 dan een simpele variatie is op deel 1 (zoals op dag 7, bijvoorbeeld, waarbij je naast optellen en vermenigvuldigen ook nog concatenatie moest toevoegen als operator), dan is het verhoudingsgewijs weinig werk omdat je 90% van je code kunt hergebruiken.
Als ik naar mijn persoonlijke tijden kijk dan zie ik dat ik tot nu toe nooit significant meer tijd nodig heb gehad voor deel 2 dan voor deel 1, en regelmatig aanzienlijk minder:
Totaaltijd Duur deel 1 Duur deel 2 Relatief 1 00:02:56 00:01:57 00:00:59 50.43% 2 00:07:55 00:06:20 00:01:35 25.00% 3 00:08:02 00:05:21 00:02:41 50.16% 4 00:05:43 00:03:04 00:02:39 86.41% 5 00:10:23 00:05:05 00:05:18 104.26% 6 00:11:20 00:05:51 00:05:29 93.73% 7 00:05:57 00:04:45 00:01:12 25.26% 8 00:16:04 00:08:31 00:07:33 88.65% 9 00:18:41 00:09:11 00:09:30 103.45% 10 00:09:02 00:06:54 00:02:08 30.92%
Misschien verandert dat nog als de problemen later wat moeilijker worden (we zijn nog niet eens halverwege tenslotte).
"The question of whether a computer can think is no more interesting than the question of whether a submarine can swim" - Edsger Dijkstra
Mwah, dat ben ik niet helemaal met je eens. Het is wel zo dat deel 1 vaak nog simpel/brute-force op te lossen is, terwijl eenzelfde benadering bij deel 2 tot extreem geheugengebruik of doorlooptijd leidt.Mugwump schreef op dinsdag 10 december 2024 @ 13:17:
Ik had wel het idee dat vorig jaar deel 1 je wat vaker op het verkeerde been zette waardoor je uiteindelijk voor deel 2 de boel nog aardig op de kop moest zetten.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Ja dat is misschien een iets betere formulering en dat was dus vorig jaar in mijn beleving meer dan nu, maar ik begon vaak ook gewoon met de naïeve brute-force implementatie voor deel 1 en dan had je met deel 2 toch wel het meeste werk.Janoz schreef op dinsdag 10 december 2024 @ 13:19:
[...]
Mwah, dat ben ik niet helemaal met je eens. Het is wel zo dat deel 1 vaak nog simpel/brute-force op te lossen is, terwijl eenzelfde benadering bij deel 2 tot extreem geheugengebruik of doorlooptijd leidt.
Ik doe AoC dan ook vooral om wat ervaring met een nieuwe taal op te doen, maar ook om m'n algoritmische kennis wat op te vijzelen, want in de praktijk doe ik daar gewoon te weinig mee.
"The question of whether a computer can think is no more interesting than the question of whether a submarine can swim" - Edsger Dijkstra
Ik verwacht dat dat nog wel komt. Ook vorige jaren waren de eerste ~10 - 15 dagen vrij eenvoudig, maar wordt het daarna toch wel erg ingewikkeld.Janoz schreef op dinsdag 10 december 2024 @ 13:19:
[...]
Mwah, dat ben ik niet helemaal met je eens. Het is wel zo dat deel 1 vaak nog simpel/brute-force op te lossen is, terwijl eenzelfde benadering bij deel 2 tot extreem geheugengebruik of doorlooptijd leidt.
Dat klopt bij mij ook wel. Al is vandaag met maar 11 seconden verschil wel extreemSoultaker schreef op dinsdag 10 december 2024 @ 13:06:
[...]
...
Als ik naar mijn persoonlijke tijden kijk dan zie ik dat ik tot nu toe nooit significant meer tijd nodig heb gehad voor deel 2 dan voor deel 1, en regelmatig aanzienlijk minder:
...
Maar de tijden zijn bij mij geen goed indicatie, omdat ik vaak niet direct om 6 uur 's ochtends hier tijd voor heb. Dan probeer ik het op het werk tussendoor te doen

Dat had bij het probleem van vandaag ook best gekund. Bijvoorbeeld door wat nu deel 2 was als deel 1 te nemen (de meeste mensen leken het probleem zo toch al te interpreterenJanoz schreef op dinsdag 10 december 2024 @ 13:19:
Mwah, dat ben ik niet helemaal met je eens. Het is wel zo dat deel 1 vaak nog simpel/brute-force op te lossen is, terwijl eenzelfde benadering bij deel 2 tot extreem geheugengebruik of doorlooptijd leidt.
Als je een algoritmische uitdaging zoekt kun je m'n variant voor dag 2 proberen op te lossen. De code is best simpel (~10 regels in Python) als je eenmaal het juiste inzicht hebt.Mugwump schreef op dinsdag 10 december 2024 @ 13:27:
Ik doe AoC dan ook vooral om wat ervaring met een nieuwe taal op te doen, maar ook om m'n algoritmische kennis wat op te vijzelen, want in de praktijk doe ik daar gewoon te weinig mee.
Mooie uitdaging. Heb hem zojuist opgelost: https://github.com/Robbin...ain/day02/day2-variant.cc. Draait de test case in 49ms op mijn PC.Soultaker schreef op dinsdag 10 december 2024 @ 13:56:
[...]
Dat had bij het probleem van vandaag ook best gekund. Bijvoorbeeld door wat nu deel 2 was als deel 1 te nemen (de meeste mensen leken het probleem zo toch al te interpreteren) en dan bij deel 2 zeggen dat je twee cijfers moet nemen om de hoogte te bepalen (dus "123456" is 1,2,3,4,5,6 in deel 1, en 12, 34, 56 in deel 2). Om alle paden van 00 tot 99 te vinden moet je dan iets slims doen zoals @Robbinb1993 in z'n oplossing doet.
[...]
Als je een algoritmische uitdaging zoekt kun je m'n variant voor dag 2 proberen op te lossen. De code is best simpel (~10 regels in Python) als je eenmaal het juiste inzicht hebt.
Simpeler dan dit kan bijna niet.TrailBlazer schreef op dinsdag 10 december 2024 @ 17:49:
Iemand een leesbaar recursive voorbeeld in Python?
TrailBlazer schreef op dinsdag 10 december 2024 @ 17:49:
het zal wel heel stom zijn maar ik heb deel 1 opgelost met dijkstra. Alleen een recursive oplossing voor twee kom ik weer niet uit. Ik snap nooit hoe die werkenIemand een leesbaar recursive voorbeeld in Python?
In python ziet het er dan zo uit:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| from functools import lru_cache grid = [ "89010123", "78121874", "87430965", "96549874", "45678903", "32019012", "01329801", "10456732" ] N, M = len(grid), len(grid[0]) DX = [-1, 1, 0, 0] DY = [0, 0, -1, 1] @lru_cache(None) def solve(x, y): if grid[x][y] == '9': # Base case return 1 total_paths = 0 for dx, dy in zip(DX, DY): # Check all 4 directions nx, ny = x + dx, y + dy if 0 <= nx < N and 0 <= ny < M and int(grid[nx][ny]) == int(grid[x][y]) + 1: total_paths += solve(nx, ny) return total_paths # Compute total paths for cells starting with '0' ans_part2 = sum(solve(i, j) for i in range(N) for j in range(M) if grid[i][j] == '0') print("Total paths starting with '0':", ans_part2) |
Het kan waarschijnlijk wel compacter in Python maar ik schrijf zelf weinig Python.
[ Voor 41% gewijzigd door Robbinb1993 op 10-12-2024 19:04 ]
U riep?Robbinb1993 schreef op dinsdag 10 december 2024 @ 18:01:
Het kan waarschijnlijk wel compacter in Python maar ik schrijf zelf weinig Python.
e=enumerate;H={i+j*1j:c for i,r in e(open(0))for j,c in e(r)};V=[(v,v)for v in H if H[v]=='0'];[V:=[(s,v+n)for s,v in V for n in(-1j,1j,-1,1)if H.get(v+n)==h]for h in '123456789'];print(len({*V}),len(V))
Verder verveelde ik me dus heb ik deel 2 van vandaag ook even geïmplementeerd m.b.v. SciPy's convolve2d(). Even een kleine vingeroefening voordat we weer Game of Life-achtige puzzels krijgen. Voor wie benieuwd is, de code is prima leesbaar en staat hier.
Zoals gewoonlijk komt er bij mij weer een heel ander antwoord uit (bij deel 2)Soultaker schreef op dinsdag 10 december 2024 @ 08:18:
Qua extra data is er niet veel interessants te bedenken vandaag, maar voor wie toch wil testen, hier een iets groter invoerbestand: aoc-2024-day-10-challenge-1.zip
$ time pypy3 solve.py < aoc-2024-day-10-challenge-1.txt ...036 ...780 real 0m5.309s user 0m5.177s sys 0m0.084s

Wat krijgen jullie bij:
0123456789 1234567898 2345678987 3456789876 4567898765 5678987654 6789876543 7898765432 8987654321 9876543210
ik 20 en 1024.
.edit: oh jezus, ik deed offset = y * height + x, en de challenge input is niet vierkant

[ Voor 6% gewijzigd door .oisyn op 11-12-2024 01:15 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
En daarom hergebruik in een Grid type. Dat soort fouten heb ik al veel te vaak gemaakt..oisyn schreef op woensdag 11 december 2024 @ 00:08:
[...]
.edit: oh jezus, ik deed offset = y * height + x, en de challenge input is niet vierkant
Vandaag voor het eerst op tijd op, dus ben gewoon nr 1589 voor deel 2 in de wereld
Marcj schreef op woensdag 11 december 2024 @ 06:33:
Ik was bang dat vandaag een moeilijke zou worden en dat deel 2 echt ondoenelijk groot zou worden en we in de wiskunde moesten duiken. Maar uiteindelijk valt het mee met een standaard puzzel techniek:
spoiler:memoization
Vandaag voor het eerst op tijd op, dus ben gewoon nr 1589 voor deel 2 in de wereld
Same here, rank 2321 want ik was wat aan het klooien met PythonMarcj schreef op woensdag 11 december 2024 @ 06:33:
Ik was bang dat vandaag een moeilijke zou worden en dat deel 2 echt ondoenelijk groot zou worden en we in de wiskunde moesten duiken. Maar uiteindelijk valt het mee met een standaard puzzel techniek:
spoiler:memoization
Vandaag voor het eerst op tijd op, dus ben gewoon nr 1589 voor deel 2 in de wereld
Robbinb1993 schreef op woensdag 11 december 2024 @ 06:44:
[...]
spoiler:Ik memorize/cache alleen de lage values en daarmee los ik part 2 in 2 ms op.
Trouwens, die techniek is wel erg afhankelijk van de input. Ik heb voor de grap een grote input gemaakt: day11-big.txt
Zonder aanpassingen (wel 128 bits nodig) krijg ik dit:
1
2
3
4
5
| Executing ├── Input parsed in 31,199µs ├── Part 1 calculated in 356,364µs: ...10116 ├── Part 2 calculated in 322,397µs: ...09224 └── Total time: 710,035µs |
[ Voor 38% gewijzigd door Marcj op 11-12-2024 07:29 ]
Op deze manier haal @Soultaker en @Thorwing zeker niet in op het GoT leaderboard
Maar goed, gelukkig kon ik vandaag weer redelijk nette code schrijven en mijn "fans" op Reddit tevreden houden.
Exact de methode die ik ook had toegepast voor deel 2 in python. Ik had deel 1 wel gewoon brute force met lists gedaan omdat ik vermoedde bij deel 2 iets met volgordes of iets dergelijks te moeten gaan doen.Hagdos schreef op woensdag 11 december 2024 @ 06:46:
[...]
Same here, rank 2321 want ik was wat aan het klooien met Python
spoiler:Ik heb geen memoization gebruikt, maar wel een dict ipv een list. De volgorde van de stenen boeit me niet, dus als ik 1000 0-en heb opgeslagen reken ik die maar 1 keer uit, maar wel voor elke stap opnieuw.
Best wel zitten frotten om deel 1 correct te programmeren (ik kan blijkbaar niet zomaar een element van een vector pakken en die als variabele gebruiken, als dat element geen Clone implementeert in Rust
En natuurlijk moet je niet, als je eerst de lengte van een getal goed hebt berekend, delen door de lengte, maar splitsen op de (helft!) van de lengte

De kerstborrel van gisteren was niet bevorderlijk voor de denkkracht in de morgen zullen we maar zeggen.
Ah, gevonden: hier deed het me erg aan denken.
[ Voor 7% gewijzigd door FCA op 11-12-2024 07:57 ]
Verandert z'n sig te weinig.
Mag ik je wijzen op defaultdict en Counter uit Pythons collections module? Bij defaultdict kan je een functie meegeven die wordt uitgevoerd wanneer een key niet bestaat, zodat je niet overal "if x not in stones" hoeft te schrijven.bakkerjangert schreef op woensdag 11 december 2024 @ 07:44:
Exact de methode die ik ook had toegepast voor deel 2 in python.
Counter-objecten werken ongeveer hetzelfde, maar hebben al 0 als default-waarde, en ook een redelijk elegante manier om ze te initialiseren. Voorbeeldje
Ik kwam inderdaad ook op 1000 (of 999, max. 3 digits value) uit als optimaal. Waarden met een even aantal digits worden al opgesplitst in kleinere values, dus er valt in de range [1000, 9999] denk ik weinig extra winst te boeken t.o.v. extra geheugengebruik. Op jouw testcase haal ik 446 ms: https://github.com/Robbin...ain/day11/day11_int128.cc. Ben benieuwd of er nog een andere optimalisatie mogelijk is.Marcj schreef op woensdag 11 december 2024 @ 07:24:
[...]
spoiler:Dat is wel een slimme oplossing, niet aan gedacht. Wat voor limiet werkt bij jou goed dan? Bij mij lijkt 1000 ofzo het snelste te gaan.
Trouwens, die techniek is wel erg afhankelijk van de input. Ik heb voor de grap een grote input gemaakt: day11-big.txt
Zonder aanpassingen (wel 128 bits nodig) krijg ik dit:
code:
1 2 3 4 5 Executing ├── Input parsed in 31,199µs ├── Part 1 calculated in 356,364µs: ...10116 ├── Part 2 calculated in 322,397µs: ...09224 └── Total time: 710,035µs
Het maximum aantal steps lijkt ook weinig invloed te hebben op de tijd. Als ik het bijvoorbeeld ophoog naar 200 stappen voor part 2, dan blijft de runtime ongeveer hetzelfde.
Edit: Met precomputation van het aantal digits van values (ook tot een limiet) en machten van 10, kunnen we het proces van het splitsen van getallen met even aantal cijfers nog iets versnellen. Nu is de runtime 321ms.
Een oplossing waarbij alles in een hash map (unordered_map) wordt gecached doet er 4366 ms over bij mij voor de grote input: https://github.com/Robbin...day11/day11_int128_map.cc. Dus dat is wel significant langzamer.
[ Voor 23% gewijzigd door Robbinb1993 op 11-12-2024 08:47 ]
Mijn grid is read-only view op een slice, dus dat kon nietMarcj schreef op woensdag 11 december 2024 @ 06:30:
[...]
En daarom hergebruik in een Grid type. Dat soort fouten heb ik al veel te vaak gemaakt.

[ Voor 3% gewijzigd door .oisyn op 11-12-2024 09:04 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Dat hangt ook af van de invoer. Neem bijvoorbeeld deze: loopy-numbers-1.txt. Volgens mij groeit de oplossingstijd ongeveer lineair met het aantal iteraties dat je uitvoert.Robbinb1993 schreef op woensdag 11 december 2024 @ 08:05:
Het maximum aantal steps lijkt ook weinig invloed te hebben op de tijd. Als ik het bijvoorbeeld ophoog naar 200 stappen voor part 2, dan blijft de runtime ongeveer hetzelfde.
119 ms tegenover 81 ms voor de echte input, dus dat valt nog reuze mee hoe het groeit.Soultaker schreef op woensdag 11 december 2024 @ 09:35:
[...]
Dat hangt ook af van de invoer. Neem bijvoorbeeld deze: loopy-numbers-1.txt. Volgens mij groeit de oplossingstijd ongeveer lineair met het aantal iteraties dat je uitvoert.
https://github.com/remcos...r/adventofcode/Day11.java
Inderdaad, als ik het aantal stappen verdubbel, verdubbelt de executietijd ook ongeveer voor deze test case.Soultaker schreef op woensdag 11 december 2024 @ 09:35:
[...]
Dat hangt ook af van de invoer. Neem bijvoorbeeld deze: loopy-numbers-1.txt. Volgens mij groeit de oplossingstijd ongeveer lineair met het aantal iteraties dat je uitvoert.
1000 steps: 378ms.
2000 steps: 754ms.
4000 steps: 1484ms.
In dit geval is het verschil tussen de oplossing die alleen lage values cached en de oplossing die alles cached in een map ook kleiner. De map oplossing doet er voor 2000 steps 1277ms over.
[ Voor 17% gewijzigd door Robbinb1993 op 11-12-2024 09:53 ]
.edit: of, alternatief, wat is het antwoord van het voorbeeld van 125 17 voor 75 stappen?
.edit: argh jezus, ik zat het antwoord van het voorbeeld in te voeren ipv die van de daadwerkelijke puzzel input

Wat bedoel je precies? Heb je een stukje code?FCA schreef op woensdag 11 december 2024 @ 07:49:
Best wel zitten frotten om deel 1 correct te programmeren (ik kan blijkbaar niet zomaar een element van een vector pakken en die als variabele gebruiken, als dat element geen Clone implementeert in Rust, zelfs niet als ik expliciet clone aanroep)
[ Voor 16% gewijzigd door .oisyn op 11-12-2024 11:55 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Hier had ik ook last van; mijn proces zat op 180 GB memory usage voordat deze werd afgebroken en ik had toen nog geen antwoord... De tips hierboven hebben mij dus ook aardig geholpenSatom schreef op woensdag 11 december 2024 @ 12:16:
Dag 11 ook weer klaar, in eerste instantie had ik vanochtend een oplossing die enorm veel geheugen gebruikte
Draait in ongeveer 1ms
Rust
Heh, jouw blink() is ongeveer exact dezelfde als mijn num_stones_from_number()HannoOttens schreef op woensdag 11 december 2024 @ 15:02:
Zag de bui al hangen vandaag, dus meteen maar een oplossing gemaakt die voor beide parts zou werken!
Draait in ongeveer 1ms
Rust
Nog een microoptimization, als je `if let Some(v) = mem.get(...) doet kun je in 1 keer testen of het elemement aanwezig is en die ophalen. Nu zit je effectief 2x te hashen en de lookup te doen.
1ms vind ik wel apart, ik doe er 12ms over. En dan deel ik de hashmap van deel 1 ook nog eens met die van deel 2.
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Goed idee!.oisyn schreef op woensdag 11 december 2024 @ 15:28:
[...]
Heh, jouw blink() is ongeveer exact dezelfde als mijn num_stones_from_number()
Nog een microoptimization, als je `if let Some(v) = mem.get(...) doet kun je in 1 keer testen of het elemement aanwezig is en die ophalen. Nu zit je effectief 2x te hashen en de lookup te doen.
1ms vind ik wel apart, ik doe er 12ms over. En dan deel ik de hashmap van deel 1 ook nog eens met die van deel 2.
Ik zat trouwens eerst ook rond de 12ms, tot ik de types in mijn hashmap aanpaste naar van een u64 naar een u32

.edit: dat is in mijn geval ook zo. Bij jou niet?
[ Voor 15% gewijzigd door .oisyn op 11-12-2024 15:40 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ik had trouwens ook een langere duration toen ik een te grote ::with_capacity deed bij mijn hashmap. Mogelijk maakt dat ook nog verschil?
[ Voor 45% gewijzigd door HannoOttens op 11-12-2024 15:45 ]
De mijne had ongeveer 121k entries nodig. Als ik 'm iets groter dan dat zet heb ik een sweet spot wat tijd betreft. Veel groter maakt dat de tijd behoorlijk toeneemt idd.HannoOttens schreef op woensdag 11 december 2024 @ 15:43:
Ik had trouwens ook een langere duration toen ik een te grote ::with_capacity deed bij mijn hashmap. Mogelijk maakt dat ook nog verschil?
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Als ik 'm meteen init met die cap dan kom ik op 11ms
.edit: cap blijft hetzelfde als ik part1 en part2 hun eigen map geef.
[ Voor 51% gewijzigd door .oisyn op 11-12-2024 16:38 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Wauw.. ik heb nog heel even zitten twijfelen of ik mijn andere machine erbij zou pakken, die 64GB heeft. Die kon mijn oude oplossing van dag 6, 2021 wel oplossen na flink wat minuten en +- 50GBmbe81 schreef op woensdag 11 december 2024 @ 14:30:
[...]
Hier had ik ook last van; mijn proces zat op 180 GB memory usage voordat deze werd afgebroken en ik had toen nog geen antwoord... De tips hierboven hebben mij dus ook aardig geholpen
180GB? Dat is bijna valsspelenmbe81 schreef op woensdag 11 december 2024 @ 14:30:
[...]
Hier had ik ook last van; mijn proces zat op 180 GB memory usage voordat deze werd afgebroken en ik had toen nog geen antwoord... De tips hierboven hebben mij dus ook aardig geholpen
When life gives you lemons, start a battery factory
Draai jij je oplossingen op je telefoon of zo?KabouterSuper schreef op woensdag 11 december 2024 @ 18:19:
[...]
180GB? Dat is bijna valsspelen. Ik werk op 8GB waarvan er ongeveer 3GB beschikbaar is voor python.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Dit is ook wel een leermomentje. De meeste Advent of Code problemen hebben echt niet zo'n dikke bak nodig, dus de kans is groot dat je op het verkeerde spoor zit. Natuurlijk kan het soms werken om er meer geheugen tegenaan te gooien (net zoals het bij sommige brute force oplossingen werkt om een paar minuten langer te wachten), maar het is beter om even een stap terug te doen en te proberen te beredeneren of je überhaupt in de buurt van een werkbare oplossing bent.Satom schreef op woensdag 11 december 2024 @ 17:36:
Wauw.. ik heb nog heel even zitten twijfelen of ik mijn andere machine erbij zou pakken, die 64GB heeft.
Bij dit probleem is het bijvoorbeeld makkelijk en behulpzaam om te debug-printen hoeveel elementen je hebt na X stappen. Bijvoorbeeld elke 5 stappen, voor de voorbeeldinvoer:
5: 13 10: 109 15: 853 20: 6837 25: 55312 30: 445882 35: 3604697 40: 29115525 45: 235189097 50: 1900433601 55: 15358013692
Dan observeer je:
1. Na 50 stappen zit je op bijna 2 miljard elementen (met 4 bytes/element ~4 GB RAM).
2. Elke vijf stappen wordt de lijst ongeveer 8 keer zo groot.
Conclusie: om van 50 naar 75 te komen heb je ongeveer 825/5 = 85 = 215 = 32768 keer zoveel geheugen nodig als bij stap 50. Tenzij je een machine met meer dan 250 terabyte geheugen hebt is het zinloos om op deze manier door te gaan.
Haha, ik heb 48 GB geheugen dus er werd al flink geswapped.KabouterSuper schreef op woensdag 11 december 2024 @ 18:19:
[...]
180GB? Dat is bijna valsspelen. Ik werk op 8GB waarvan er ongeveer 3GB beschikbaar is voor python.
Die output had ik ook geprint inderdaad. Ik zag al dat het kansloos was om zo verder te gaan maar wist op dat moment niet echt een andere oplossing.Soultaker schreef op woensdag 11 december 2024 @ 19:02:
Bij dit probleem is het bijvoorbeeld makkelijk en behulpzaam om te debug-printen hoeveel elementen je hebt na X stappen.
In eerste instantie had ik verwacht dat recursie ook niet zo werken met zulke aantallen daar ik in het verleden wel eens stack overflows krijg als ik een fout had in mijn code en dus enorm veel functiecalls deed. Maar blijkbaar is dat in dit geval geen probleem.
Samen met de suggestie van memoization is het als de brandweer!
[ Voor 39% gewijzigd door mbe81 op 11-12-2024 19:14 ]
Haha, dat zou wel sneller zijn waarschijnlijk. Ik heb een sony vaio uit 2012 die maar niet kapot wil gaan (hoewel ik wel last krijg van loslatende toetsen) . En ik heb nog een reserve vaio voor extra onderdelen, dus ik ga nog wel een paar jaar vooruit kunnen met mijn laptop. Ach, dan maar geen draaitijden in micro- of nanoseconden.Janoz schreef op woensdag 11 december 2024 @ 18:53:
[...]
Draai jij je oplossingen op je telefoon of zo?
When life gives you lemons, start a battery factory
Dus net maar even deel twee gedaan. Dacht eerst nog aan memoization, maar simpelweg de counts voor elke waarde bijhouden in plaats van elke individuele waarde was al voldoende om het snel te doen. Nog wel wat lopen kloten met ints en longs, maar dat hoort erbij.
"The question of whether a computer can think is no more interesting than the question of whether a submarine can swim" - Edsger Dijkstra
Ik heb misschien wel een idee waardoor het toch kan, maar dat moet ik nog even uitwerken.
Blijkbaar maakt het ook nogal uit wat je puzzel input je hebt. @HannoOttens heeft aan 32 bits genoeg met zijnMugwump schreef op woensdag 11 december 2024 @ 19:50:
Nog wel wat lopen kloten met ints en longs, maar dat hoort erbij.
input
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Helemaal mee eens, daarom begin ik ook altijd met wat debug lijntjes (en de example input). Toen ik eenmaal bij dag 40 was aangekomen, had ik al weer door dat dit niet ging werken. Dat was het moment dat ik mij dag 6 van 2021 herinnerde!Soultaker schreef op woensdag 11 december 2024 @ 19:02:
[...]
Dit is ook wel een leermomentje. De meeste Advent of Code problemen hebben echt niet zo'n dikke bak nodig, dus de kans is groot dat je op het verkeerde spoor zit. Natuurlijk kan het soms werken om er meer geheugen tegenaan te gooien (net zoals het bij sommige brute force oplossingen werkt om een paar minuten langer te wachten), maar het is beter om even een stap terug te doen en te proberen te beredeneren of je überhaupt in de buurt van een werkbare oplossing bent.
Bij dit probleem is het bijvoorbeeld makkelijk en behulpzaam om te debug-printen hoeveel elementen je hebt na X stappen. Bijvoorbeeld elke 5 stappen, voor de voorbeeldinvoer:
5: 13 10: 109 15: 853 20: 6837 25: 55312 30: 445882 35: 3604697 40: 29115525 45: 235189097 50: 1900433601 55: 15358013692
Dan observeer je:
1. Na 50 stappen zit je op bijna 2 miljard elementen (met 4 bytes/element ~4 GB RAM).
2. Elke vijf stappen wordt de lijst ongeveer 8 keer zo groot.
Conclusie: om van 50 naar 75 te komen heb je ongeveer 825/5 = 85 = 215 = 32768 keer zoveel geheugen nodig als bij stap 50. Tenzij je een machine met meer dan 250 terabyte geheugen hebt is het zinloos om op deze manier door te gaan.
1. Eentje waarbij ik een HashMap maak en die iteratief update (zodat elke iteratie er voor elk uniek getal er maar 1 update is)
2. De recursief + memoizatie optie, uitgebreid besproken hierboven
3. Een hybride van de 2 hierboven: doe eerst 3 stappen recursief + memoization, maar geef geen totaal terug maar een HashMap van de oplossingsvector, en doe dat 25 keer. Je kunt de cache nu vaker herbruiken. De opsplitsing in 25x3 is empirisch bepaald: je hebt makkelijke opties voor 1x75 3x25, 5x15, 15x5 en 25x3, en 75x1, en dit was de snelste optie. (75x1 is natuurlijk een suboptimale implementatie van de hashmap implementatie, en 1x75 een suboptimale implementatie van de recursieve implementatie)
Interessant genoeg heb ik voor deel 1 de volgende ordening in termen van snelheid:
rec > map > hybrid (recursive is dus de snelste)
En voor deel 2:
map > hybrid > rec (de map is dus de snelste)
En als ik naar 125 iteraties ga (25x5):
hybrid > map > rec (hybride is het snelste)
Ik heb nog even zitten denken over een meer analytische oplossing, met cycles e.d. op basis van dit soort redeneringen, maar ik kan nu even niet de energie voor opbrengen.
Verandert z'n sig te weinig.
Ik kan het niet reproduceren nu (waarschijnlijk deed ik iets anders doms fout met m'n brakke hoofd van vanochtend. Het probleem leek in ieder geval dat.oisyn schreef op woensdag 11 december 2024 @ 11:42:
Zucht. Er gaat iets mis in deel 2, maar ik weet niet wat. Heeft iemand zijn input en zijn antwoorden voor me zodat ik kan checken?
.edit: of, alternatief, wat is het antwoord van het voorbeeld van 125 17 voor 75 stappen?
.edit: argh jezus, ik zat het antwoord van het voorbeeld in te voeren ipv die van de daadwerkelijke puzzel input
[...]
Wat bedoel je precies? Heb je een stukje code?
1
2
3
4
5
| fn main() { let x = vec![vec![0], vec![1]]; let y = x[0]; println!("{:?}", y); } |
niet werkt:
1
2
3
| 3 | let y = x[0]; | ^^^^ move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait | |
maar de suggestie:
1
2
3
4
5
| fn main() { let x = vec![vec![0], vec![1]]; let y = x[0].clone(); println!("{:?}", y); } |
ook vanochtend niet leek te werken, maar nu wel
Verandert z'n sig te weinig.
Ik had ook wel wat ideetjes maar niets dat praktisch tot betere performance leidde..oisyn schreef op woensdag 11 december 2024 @ 19:59:
Ik zie nog wel ruimte voor betere implementaties.
Bijvoorbeeld, lineaire algebra:
Ook heb ik geprobeerd het te modelleren als graafprobleem:
Bijvoorbeeld als je begint bij 100, dan krijg je een graaf met 1 component met 54 vertices waaronder 0 en 1, 1 component met 1709 vertices, en 2052 componenten met 1 vertex. Het probleem is dus dat het grootste component nog steeds vrij groot is, waardoor de decompositie weinig winst oplevert.
tl;dr: Geen van mijn ideeën leidt tot een aanpak die maar in de buurt komt van de andere opties.
Als je iets ontdekt dat significant sneller is dan de memoization-aanpak lijkt me dat zeer interessant!Ik heb misschien wel een idee waardoor het toch kan, maar dat moet ik nog even uitwerken.
Hm, dat is wel heel bijzonder! Volgens mij kom je met alleen “100” als invoer al een steen met 409.526.509.568 tegen, wat ruim buiten het bereik van een 32-bits integer is. Is de invoerdata echt zo zwak? Of gaat het toevallig goed? @HannoOttens kun je eens testen wat jouw oplossing doet met 100 als invoer? (Correct antwoord voor deel 2, dus met 75 iteraties, is 15669924873442.)Blijkbaar maakt het ook nogal uit wat je puzzel input je hebt. @HannoOttens heeft aan 32 bits genoeg met zijn input
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Ja ik heb al een paar keer het vermoeden gehad dat ik een ongunstige input toebedeeld had gekregen. Het was bij mij zelfs zo dat ik een Long nodig had voor de counts van de individuele getallen, niet alleen voor het totaal.oisyn schreef op woensdag 11 december 2024 @ 19:59:
Ik zie nog wel ruimte voor betere implementaties.
spoiler:Het ding met memoization is dat je alsnog heel veel werk dubbel doet. Als je voor een resultaat hebt voor een steen met waarde 6 met nog 10 stappen over, en je komt weer een 6 tegen maar dan met 11 stappen over, dan doe je dus al die 10 stappen opnieuw. Maar als je die 10 stappen wilt gebruiken om vervolgens 1 verder te gaan, dan moet je dus ook alle resultaten gaan opslaan, en gezien de grootte van het antwoord wordt dat ondoenlijk.
Ik heb misschien wel een idee waardoor het toch kan, maar dat moet ik nog even uitwerken.
[...]
Blijkbaar maakt het ook nogal uit wat je puzzel input je hebt. @HannoOttens heeft aan 32 bits genoeg met zijn
input
"The question of whether a computer can think is no more interesting than the question of whether a submarine can swim" - Edsger Dijkstra
Ja, dat was inderdaad duidelijk. Oplossing was om niet een vector terug te geven waar ik alleen in het eerste element geinteresseerd was, maar gewoon alleen het eerste element.oisyn schreef op woensdag 11 december 2024 @ 21:15:
@FCA Maar typisch wil je dat niet, dat maakt een kopie van de hele vector. Je kunt wel een element borrowen, maar als het een mutable borrow is dan kun je verder niet meer lezen (of schrijven) van/naar de vector.
Verandert z'n sig te weinig.
Ja daar heb ik het ook overMugwump schreef op woensdag 11 december 2024 @ 21:15:
[...]
Ja ik heb al een paar keer het vermoeden gehad dat ik een ongunstige input toebedeeld had gekregen. Het was bij mij zelfs zo dat ik een Long nodig had voor de counts van de individuele getallen, niet alleen voor het totaal
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Als we het trouwens hebben over crappy specs... ik develop AoC in een VM met 2CPU/8GB RAM, en draai daarbij ook nog eens de debug versie (zonder debugger attached) van de applicatie.

https://github.com/realma...de.Y2024/Solvers/Day11.cs
There's no place like 127.0.0.1
Idem voor de aanpak met transitie-matrix (die overigens niet binair hoeft te zijn: 2424 wordt gesplitst in 2 × 24). Sowieso viel de performance van scipy.sparse en in het bijzonder scipy.sparse.linalg.matrix_power() een beetje tegen. Het bleek sneller om een kleine dense matrix te gebruiken en zelf de indices te mappen. Hier staat mijn (werkende) probeersel.Soultaker schreef op woensdag 11 december 2024 @ 21:13:
spoiler:Je kunt het probleem modelleren als een sparse binaire transitie-matrix waarbij elke kolom maximaal twee enen bevat,
Toen per entry recursief berekenen en alleen een aantal teruggeven. Dat gaf geen memory problemen, maar deed er alsnog te lang over. Dus een cache is wel nodig. Gelukkig ging het daarna wel goed. Ookal cache ik maar elke 5 iteraties.
Overigens geef ik een nieuwe array door in de nieuwe iteratie. Ik zie dat veel anderen alleen het getal doorgeven. Aangezien je maar 75 iteraties hebt, valt het geheugengebruik wel mee.
Overigens, geen idee of het wat uitmaakt, maar ik sorteer mijn input lijst. Qua resultaat maakt de volgorde immers niet uit.
let the past be the past.
Deel 1 valt nog wel mee:
Voor deel 2:
So far so good. Waar het bij mij mis ging was dat ik helaas had aangenomen dat:
Duurde wel even voordat ik me dat ten eerste gerealiseerd had, en ten tweede correct opgelost had. Achteraf had ik misschien beter:
Maar ja, hindsight enzo...
Dat kan veel simpelerSoultaker schreef op donderdag 12 december 2024 @ 07:06:
Oef, wat ben ik lang bezig geweest met het debuggen van deel 2 vandaag. Kudo's aan de mensen die 'm in in een half uurtje opgelost hebben! (Ik ben zelf bijna een uur bezig geweest.)
Deel 1 valt nog wel mee:
spoiler:Je kunt het oppervlak van elke plot vinden met een flood fill. Dan is het aantal ingekleurde vlakjes het oppervlakte, en het aantal vakjes dat eraan grenzen je omtrek (wel zorgen dat je correct elk paar vakjes van verschillende types telt: een enkel vakje van een ander type in het midden van de plot telt 4x mee voor de omtrek, 1 keer voor elk van de buren).
Voor deel 2:
spoiler:Begin ik linksboven en trace ik de buitenkant van de plot, waarbij ik steeds naar links of naar rechts draai of naar voren loop. Aantal keer draaien = aantal hekstukken.
So far so good. Waar het bij mij mis ging was dat ik helaas had aangenomen dat:
spoiler:alleen de buitenkant tracen volstaat, terwijl je ook de gaten binnenin mee moet nemen.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Zelfde idee gebruikt, maar kostte even, zat flink te ruzieen met de borrow checker en ander geneuzelSoultaker schreef op donderdag 12 december 2024 @ 07:06:
Oef, wat ben ik lang bezig geweest met het debuggen van deel 2 vandaag. Kudo's aan de mensen die 'm in in een half uurtje opgelost hebben! (Ik ben zelf bijna een uur bezig geweest.)
Deel 1 valt nog wel mee:
spoiler:Je kunt het oppervlak van elke plot vinden met een flood fill. Dan is het aantal ingekleurde vlakjes het oppervlakte, en het aantal vakjes dat eraan grenzen je omtrek (wel zorgen dat je correct elk paar vakjes van verschillende types telt: een enkel vakje van een ander type in het midden van de plot telt 4x mee voor de omtrek, 1 keer voor elk van de buren).
Voor deel 2:
spoiler:Begin ik linksboven en trace ik de buitenkant van de plot, waarbij ik steeds naar links of naar rechts draai of naar voren loop. Aantal keer draaien = aantal hekstukken.
So far so good. Waar het bij mij mis ging was dat ik helaas had aangenomen dat:
spoiler:alleen de buitenkant tracen volstaat, terwijl je ook de gaten binnenin mee moet nemen.
Duurde wel even voordat ik me dat ten eerste gerealiseerd had, en ten tweede correct opgelost had. Achteraf had ik misschien beter:
spoiler:Alle bij deel 1 gevonden lijnstukken in een set gooien en dan stukken die in dezelfde richting lopen aan elkaar plakken tot je maximale rechte stukken hebt.
Maar ja, hindsight enzo...
Eerst ook de binnenbochten vergeten, en daarna de buitenbocht check verkeerd gedaan.
Niet de snelste oplossing, nog eens rustig nadenken of er snellere opties zijn.
Verandert z'n sig te weinig.
Je hebt helemaal gelijk, dat is veel simpeler. Dat verklaart ook waarom anderen zo snel waren.Janoz schreef op donderdag 12 december 2024 @ 07:32:
Dat kan veel simpeler
spoiler:Denk voor deel 2 aan hoekpaaltjes waar het hek tussen moet en je kunt ineens heel simpel gaan patternmatchen
Met wat puin ruimen is m'n oplossing nog wel netjes geworden, vind ik zelf: 12.py
FCA schreef op donderdag 12 december 2024 @ 07:37:
[spoiler]
Niet de snelste oplossing, nog eens rustig nadenken of er snellere opties zijn.
Misschien mis ik wat edge cases hoor. Ik zal het even proberen te coden...
Ik zag net de traagheid van mijn oplossing in deSoultaker schreef op donderdag 12 december 2024 @ 08:20:
[...]
Je hebt helemaal gelijk, dat is veel simpeler. Dat verklaart ook waarom anderen zo snel waren.
Met wat puin ruimen is m'n oplossing nog wel netjes geworden, vind ik zelf: 12.py
[...]
spoiler: deel 2Je hoeft toch maar één keer door de hele grid te gaan om alle hoekpunten van alle regions te bepalen, of ben ik nu gek? B.v. als het vakje linksboven letter x heeft en rechtsboven en linksonder niet, dan is dit een convexe hoek; als het vakje linksboven letter x heeft en rechtsboven en linksonder ook, maar rechtsonder niet, dan is dit een concave hoek. In andere gevallen is het een recht stuk of de binnenkant van een regio.
Misschien mis ik wat edge cases hoor. Ik zal het even proberen te coden...
Verandert z'n sig te weinig.
Ik vraag me af of het zin heeft om grotere invoer te maken voor dit probleem... de efficiënte implementaties zullen allemaal O(N) zijn, hoewel er mogelijk nog wel wat verschil in performance zit tussen de ene of de andere implementation.
Soultaker schreef op donderdag 12 december 2024 @ 08:20:
[...]
Je hebt helemaal gelijk, dat is veel simpeler. Dat verklaart ook waarom anderen zo snel waren.
Met wat puin ruimen is m'n oplossing nog wel netjes geworden, vind ik zelf: 12.py
[...]
spoiler: deel 2Je hoeft toch maar één keer door de hele grid te gaan om alle hoekpunten van alle regions te bepalen, of ben ik nu gek? B.v. als het vakje linksboven letter x heeft en rechtsboven en linksonder niet, dan is dit een convexe hoek; als het vakje linksboven letter x heeft en rechtsboven en linksonder ook, maar rechtsonder niet, dan is dit een concave hoek. In andere gevallen is het een recht stuk of de binnenkant van een regio.
Misschien mis ik wat edge cases hoor. Ik zal het even proberen te coden...
-----
UIteindelijk is dit wel weer een probleem wat relatief simpel is voor 'geschoolde' developers. In het wild kom je niet vaak iets van floodfills tegen terwijl dat een typisch opdrachtje is wanneer recursie en/of stacks uitgelegd worden.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Ik kan zo ook niet iets verzinnen waardoor het sneller dan O[N] kan. Verder vermoed ik dat veel instinkers al in de echte input zit.Soultaker schreef op donderdag 12 december 2024 @ 09:05:
spoiler: dag 12 deel 2Deel 2 kan inderdaad gewoon door 1 pass door de hele grid te maken, zie: 12-alt.py
Ik vraag me af of het zin heeft om grotere invoer te maken voor dit probleem... de efficiënte implementaties zullen allemaal O(N) zijn, hoewel er mogelijk nog wel wat verschil in performance zit tussen de ene of de andere implementation.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
Soultaker schreef op donderdag 12 december 2024 @ 09:05:
spoiler: dag 12 deel 2Deel 2 kan inderdaad gewoon door 1 pass door de hele grid te maken, zie: 12-alt.py
Ik vraag me af of het zin heeft om grotere invoer te maken voor dit probleem... de efficiënte implementaties zullen allemaal O(N) zijn, hoewel er mogelijk nog wel wat verschil in performance zit tussen de ene of de andere implementation.
https://github.com/Robbin.../blob/main/day12/day12.cc
2. Floodfill om de regio's te bepalen
3. per regio ofwel edges ofwel corners tellen
en volgens mij is sneller dan O(n) ook niet mogelijk: je moet elk punt toch minstens 1x bezoeken lijkt me.
Allebei de delen nu ~1.5ms per deel, waarvan ongeveer de helft de regiobepaling (die ik opnieuw doe voor elk deel).
Verandert z'n sig te weinig.
Sneller dan O(N), waarbij N = lengte*breedte is inderdaad niet mogelijk. Alleen het inlezen van de grid is al O(N). Dus het gaat dan vooral om de constante factor,FCA schreef op donderdag 12 december 2024 @ 10:31:
Nu een implementatie waarbij:
spoiler:1. eerst 1x door de array lopen en dan edges/corners tellen per grid point
2. Floodfill om de regio's te bepalen
3. per regio ofwel edges ofwel corners tellen
en volgens mij is sneller dan O(n) ook niet mogelijk: je moet elk punt toch minstens 1x bezoeken lijkt me.
Allebei de delen nu ~1.5ms per deel, waarvan ongeveer de helft de regiobepaling (die ik opnieuw doe voor elk deel).
[ Voor 6% gewijzigd door Robbinb1993 op 12-12-2024 11:09 ]
Memory mapped files, die pages kunnen dan gewoon uit de cache komenRobbinb1993 schreef op donderdag 12 december 2024 @ 10:35:
[...]
Alleen het inlezen van de grid is al O(N).
.edit: ok fair, nog steeds O(N/pagesize) = O(N)
[ Voor 21% gewijzigd door .oisyn op 12-12-2024 10:55 ]
Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.
Omdat ik hier al gelezen had welke richting het op moest voor deel 2 (had al door dat dat recht-toe, recht-aan niet zou gaan lukken) en ik net dag 7b (Bridge Repair) had opgelost, zag ik hier een kans.
Deel 1 had ik wel 'dom' opgelost en duurde 4,4 seconde. Met een tellertje erbij zag ik al dat elke iteratie langer duurde. Deel 2 - na wat optimalisatie - is nu klaar in 2940ms en dat is denk ik het snelste wat ik kan halen in Progress 4GL. Weer eens wat anders dan die snelle tijden
https://github.com/patric...ter/2024/Day-11/day-11b.p
... en gaat over tot de orde van de dag
Levert wel super lelijke code op maar het berekent netjes de randen.
https://github.com/gjong/...nt/years/y2024/Day12.java

Rust
Na het inleveren niet goed opgelet en er kwam doodleuk een ander antwoord uit... Omdat ik voor de performance de release build deed ook niet langer over nagedacht dat overflows dan niet meer naar voren komen

Mijn oplossing draait dan in een beschamende 15ms in plaats van de eerder geprofeteerde snelheden
Om te benchmarken kun je combined-1.txt en combined-2.txt gebruiken. Er zitten wat extra bestanden bij die je kunt gebruiken om te debuggen als je niet het goede antwoord krijgt (de combined bestanden zijn simpelweg de andere bestanden aan elkaar geplakt). Ik heb daarvoor ook de oplossingen in de zip file gestopt. Natuurlijk is de uitdaging om de correcte antwoorden zelf te reproduceren!
Referentie-tijden (dit kan zeker veel sneller in een andere taal dan Python):
$ time pypy3 solve.py < combined-1.txt ...54044 ...18790 real 0m0.626s user 0m0.565s sys 0m0.058s $ time pypy3 solve.py < combined-2.txt ...62592 ...00666 real 0m4.497s user 0m4.231s sys 0m0.253s
Overigens overweeg ik ook een carrière switch naar abstract kunstenaar:

Mooi hè?
Dream caused by floodfills around Soultakers gardens seconds before awakeningSoultaker schreef op donderdag 12 december 2024 @ 13:08:
[Overigens overweeg ik ook een carrière switch naar abstract kunstenaar:
[Afbeelding]
Mooi hè?
When life gives you lemons, start a battery factory
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'
combined-1.txt: 444.30ms
combined-2.txt: 4.22s
[ Voor 7% gewijzigd door HannoOttens op 12-12-2024 13:56 ]
Oplossing in Swift
Ja, echt wel weer mooie data die je gegeneerd hebt. Ik vraag me soms af waar je de tijd vandaag haalt!Soultaker schreef op donderdag 12 december 2024 @ 13:08:
Extra testdata voor dag 12: aoc-2024-day-12-challenge-1-and-2.zip
...
Overigens overweeg ik ook een carrière switch naar abstract kunstenaar:
[Afbeelding]
Mooi hè?
Ik zat eerst te klooien met ingewikkelde algorintmes, maar nadat ik besefte dat je hekken en hoeken makkelijk kunt definieren werd het een stuk simpler! Ik heb geloof ik 80% van mijn code weer kunnen weg gooien. Hier is mijn huidige resultaat in Rust. Trouwens, het meeste complexe is een nieuwe functie in mijn Grid object die regio's met dezelfde waarden kan detecteren. Misschien nog niet het meest efficient, maar hij kan er mee door voor nu.
De challenge run:
1
2
3
4
5
6
7
8
9
10
11
12
13
| $ day12 < combined-1.txt Executing ├── Input parsed in 54,770µs ├── Part 1 calculated in 18,396µs: ...54044 ├── Part 2 calculated in 45,702µs: ...18790 └── Total time: 118,937µs $ day12 < combined-2.txt Executing ├── Input parsed in 445,779µs ├── Part 1 calculated in 167,983µs: ...62592 ├── Part 2 calculated in 415,637µs: ...00666 └── Total time: 1,029,465µs |
Niet slecht volgens mij, maar het moet denk ik nog wel wat beter moet kunnen.
Code
[ Voor 31% gewijzigd door Friits op 12-12-2024 14:45 ]
combined-1: 64ms.Soultaker schreef op donderdag 12 december 2024 @ 13:08:
Extra testdata voor dag 12: aoc-2024-day-12-challenge-1-and-2.zip
Om te benchmarken kun je combined-1.txt en combined-2.txt gebruiken. Er zitten wat extra bestanden bij die je kunt gebruiken om te debuggen als je niet het goede antwoord krijgt (de combined bestanden zijn simpelweg de andere bestanden aan elkaar geplakt). Ik heb daarvoor ook de oplossingen in de zip file gestopt. Natuurlijk is de uitdaging om de correcte antwoorden zelf te reproduceren!
Referentie-tijden (dit kan zeker veel sneller in een andere taal dan Python):
$ time pypy3 solve.py < combined-1.txt ...54044 ...18790 real 0m0.626s user 0m0.565s sys 0m0.058s $ time pypy3 solve.py < combined-2.txt ...62592 ...00666 real 0m4.497s user 0m4.231s sys 0m0.253s
Overigens overweeg ik ook een carrière switch naar abstract kunstenaar:
[Afbeelding]
Mooi hè?
combined-2: 614ms.
https://github.com/Robbin.../blob/main/day12/day12.cc
Die viel me aardig mee.
Qua snelheid vast niet vergelijkbaar met snellere loopjes.. maar qua code wel lekker kort
:strip_exif()/f/image/eDOQrIEzdqZrGbdCfWIMIDrc.png?f=user_large)
- maak een netwerk van de matrix, en behoud alleen de verbindingen tussen gelijke letters.
- de componenten in de graaf zijn de verschillende blokken
- van iedere 'letter' is de omtrek gelijk aan (4 - aantal verbindingen naar naastgelegen letters)
- sommer dit per groep, en vermenigvuldig met groetsgrootte
DEEL 2
- maak een spatial grid van vierkanten, met afmetingen van input
- haal de groepen/blokken uit het antwoord van DEEL 1
:strip_exif()/f/image/GrZ1I0vQhH7GbWtpe1ALWZnl.png?f=user_large)
- simplificeer per blok, waardoor je alleen polylijnen (=omtrek) overhoudt.
:strip_exif()/f/image/6F34rfXsSNiFu2EIUS1jOdxA.png?f=user_large)
- per blok, per polylijn, kijk uit hoeveel punten de polylijn bestaat. (aantal punten - 1) is aantal lijndelen.
- sommeer per blok, en vermenigvuldig met blokgrootte
[ Voor 3% gewijzigd door breew op 12-12-2024 16:25 ]
Dat is zeker waar. Ook is het vaak behulpzaam om problemen als graaf te kunnen visualiseren. Daarmee was dag 25 van vorig jaar eigenlijk volledig op te lossen.Janoz schreef op donderdag 12 december 2024 @ 13:54:
Misschien moet ik ook maar eens een stukje graphics toevoegen aan mijn framework. Een plaatje is vaak duidelijker dan tig logregels of een bak cijfers.
Nou, het goed visualiseren van dag 8 van vorig jaar had ook veel kunnen helpenSoultaker schreef op donderdag 12 december 2024 @ 16:04:
[...]
Dat is zeker waar. Ook is het vaak behulpzaam om problemen als graaf te kunnen visualiseren. Daarmee was dag 25 van vorig jaar eigenlijk volledig op te lossen.
Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'