Disclaimer: Welkom bij onze TechBlog!
Dit is een artikel in ons TechBlog. Ons Techblog bevat artikelen, geschreven door onze developers, over dingen die ze zijn tegengekomen tijdens hun werkzaamheden. Deze artikelen gaan (meestal) over een technisch onderwerp, en zijn met name bedoeld om te vermaken en (soms) te informeren. De kortste weg naar de conclusie is zelden onze favoriete.

maandag 2 november
Tekst: Mark Coenradie
Afbeeldingen: Jeroen Mimpen

1.824,9 kilometer, twintig miljoen routes en een beetje hulp van AI

Mark en Sernin in het station na hun deelname aan de Kilometer Kampioen.

Onlangs won ik samen met Sernin van de Krol de Kilometer Kampioen.

In 24 uur legden we 1.824,9 geldige kilometers per trein af, slechts 4,6 kilometer meer dan de nummer twee. De software die ik in de loop der jaren heb ontwikkeld, en dit jaar weer heb verbeterd met behulp van AI, heeft daarbij een belangrijke rol gespeeld.

Een puzzel die ingewikkelder is dan je denkt

De Kilometer Kampioen wordt georganiseerd door Treinreiziger.nl. Het doel is eenvoudig: leg binnen 24 uur zoveel mogelijk kilometers per trein af. Er zijn een paar beperkingen, zoals een verplichte stempelpost op Rotterdam Centraal en regels over het opnieuw afleggen van dezelfde trajecten. Deze regels veranderen elke editie, zodat het steeds een net andere puzzel wordt.

Ik doe al sinds de eerste editie in 2015 mee, op één keer na die qua planning ongelukkig uitkwam. Vanaf het begin heb ik software geschreven om de optimale route te vinden.

In 2015 was dat vooral een kwestie van heel veel mogelijke routes doorrekenen en daar flink wat computertijd tegenaan gooien. Dat werkte redelijk, maar was niet bepaald efficiënt.

Mark rekent treinroutes door op een computer die zoveel warmte produceert dat er rook vanaf komt.

In 2015 hoefde de verwarming binnen niet aan wanneer ik routes aan het berekenen was.

Het probleem is namelijk wiskundig behoorlijk ingewikkeld. Een gewone reisplanner zoekt de snelste route van A naar B. Wij zoeken juist een route die zoveel mogelijk kilometers oplevert, binnen een vaste tijd en rekening houdend met alle wedstrijdregels.

De wiskunde

Even een stukje voor de mede-nerds: deze puzzel lijkt op wat in de wiskunde een time-dependent orienteering problem wordt genoemd. Een belangrijk verschil met een gewone routeplanner is dat de opbrengst van een traject meetelt en niet alleen de reistijd. Bovendien veranderen de mogelijke verbindingen voortdurend: een overstap is om 10.00 uur misschien mogelijk, maar om 10.05 uur niet meer.

Dit soort optimalisatieproblemen is NP-moeilijk. Dat betekent niet dat het theoretisch gezien onmogelijk is om een optimale oplossing te vinden, maar wel dat er geen efficiënte algemene methode bekend is om dat voor grote problemen te doen. Het aantal mogelijke combinaties groeit zo snel dat simpelweg alles uitproberen praktisch onhaalbaar wordt.

Op de achterkant van een bierviltje: er zijn ongeveer 400 stations in Nederland; op al deze stations zou je theoretisch gezien kunnen beginnen. Als je ongeveer 60 stations passeert met een overstapmogelijkheid en daarbij gemiddeld op 2 treinen kunt overstappen (of kunt blijven zitten), kom je op 42 quadriljard verschillende routes (een quadriljard is een 1 met 27 nullen). Dat is meer dan het aantal zandkorrels op aarde of sterren in het waarneembare universum.

Casper en Mark discussiëren over een getal met 21 nullen.

Je moet dus slim zoeken en onderweg ontzettend veel mogelijkheden uitsluiten. Daarmee vind je goede routes, maar je weet niet meer zeker of je ook de allerbeste hebt gevonden.

In de loop der jaren is mijn software steeds verder ontwikkeld. Iedere editie kwamen er verbeteringen bij. Dit jaar zijn we opnieuw met slimmere algoritmes aan de slag gegaan. Sernin en ik hebben daarnaast onze gevonden routes met elkaar uitgewisseld om te kijken waar we nog kilometers konden winnen.

Uiteindelijk stonden er ongeveer twintig miljoen routes in de database.

Een collega draagt nog een treinroute aan voor Marks verzameling van twintig miljoen routes.

Een routeplanner bouwen in twintig minuten

Dit jaar kwam er nog iets nieuws bij: AI. We gebruiken AI inmiddels dagelijks bij het ontwikkelen van software, dus ik was benieuwd hoe ver je kunt komen bij een probleem waar ik zelf al jaren aan werk.

Meerdere collega's gingen ermee aan de slag. Het opvallendste resultaat kwam van Jeroen, die met GPT-5.6-Sol een eigen routeplanner bouwde. Astra was op dat moment nog niet beschikbaar.

Na ongeveer twintig minuten had hij werkende software. De dienstregeling werd correct ingelezen en het algoritme produceerde meteen een route die meer kilometers opleverde dan mijn beste route op dat moment. Dat had ik absoluut niet verwacht, vooral omdat alle data exact klopte.

Jeroen noemt zichzelf de nieuwe kilometerkampioen terwijl Mark zijn route bekijkt.

Meneer voert één prompt uit en reserveert alvast een plek op het podium.

Er zat alleen wel één fout in. Nou ja, fout… De route ging met de Eurostar richting Londen, om vervolgens in Rotterdam weer uit te stappen. Dat klinkt als een creatieve oplossing, maar de Eurostar naar Londen werkt anders dan een gewone trein. Je moet minimaal twintig minuten voor vertrek aanwezig zijn voor de veiligheidscontrole, iets wat het model niet had meegerekend. Bovendien mag je bij de stop in Rotterdam niet uitstappen, omdat je administratief het Schengengebied al verlaten hebt.

De wedstrijdregels verbieden de Eurostar niet expliciet, maar dat betekent nog niet dat je zo'n verbinding daadwerkelijk kunt gebruiken. Ook een gewone dagkaart is niet geldig.

Toen ik deze fout eenmaal ontdekt had, heeft Jeroen de Eurostar naar Londen uitgesloten. Hetzelfde gold voor de verbindingen naar Brussel en Parijs (de voormalige Thalys, tegenwoordig ook Eurostar). Die treinen zouden technisch gezien wel gebruikt kunnen worden, maar vielen niet onder onze dagkaart. Uiteindelijk zou het gebruik daarvan hooguit vijf minuten tijdwinst opleveren, en dat vonden we de ongeveer 80 euro extra niet waard.

Na die aanpassingen kwam er nog steeds een interessante route uit. Sterker nog, de routes die mijn collega's met AI vonden, zouden steevast in de top 10 gestaan hebben. Dat zegt wel iets over hoe toegankelijk softwareontwikkeling inmiddels is geworden.

Mark en Sernin staan op Rotterdam Centraal terwijl Jeroen niet uit de Eurostar mag stappen.

Twintig minuten om een routeplanner te bouwen. Twee werkdagen om Jeroen terug te krijgen.

Twee routeplanners weten meer dan één

Wat misschien nog interessanter was dan de snelheid waarmee Jeroen de route vond, was wat we er vervolgens mee konden doen. In zijn beste routes zaten verbindingen die bij mij niet naar boven kwamen. Dat betekende dat er ergens in mijn algoritme een beperking zat die mogelijk onnodig was.

Deels zocht ik dat handmatig uit. Ik vergeleek de routes en probeerde te achterhalen waarom mijn software een bepaalde mogelijkheid had uitgesloten. Andere keren gaf ik de route aan een AI-model, in mijn geval Opus of Sonnet, met ongeveer de opdracht: zoek uit waarom mijn algoritme deze route niet vindt. Dat werkte verrassend goed.

Mijn reispartner Sernin en ik hebben ook onderling onze beste routes uitgewisseld. Doordat we verschillende implementaties hadden, konden we de resultaten vergelijken. Dat laatste is belangrijk: een AI-model vragen of zijn eigen code correct is, geeft niet altijd een betrouwbaar antwoord. Een AI-model vragen of andermans code correct is, levert ook niet altijd iets bruikbaars op. Maar als twee onafhankelijk ontwikkelde algoritmes verschillende uitkomsten geven, weet je dat er iets te onderzoeken valt.

Zo hebben de verschillende routeplanners elkaar uiteindelijk geholpen om beter te worden.

Ook heb ik veel unittests laten schrijven, iets waar ik eerder niet aan toegekomen zou zijn. Bijvoorbeeld voor de logica rond overstappen, of voor het opknippen en weer samenvoegen van stukken van een route. Dat zijn relatief kleine onderdelen waarvan je precies kunt definiëren wat de juiste uitkomst moet zijn, en waar je makkelijk een foutje maakt. Ideaal om door AI te laten uitwerken, zolang je de tests en de verwachtingen zelf goed controleert.

Drie minuten overstappen is niet altijd drie minuten overstappen

Een route die volgens de dienstregeling mogelijk is, hoeft in de praktijk nog geen goede route te zijn.

Neem een overstap van drie minuten. Als beide treinen aan weerszijden van hetzelfde perron stoppen, is dat eigenlijk altijd prima te doen. Bij het opstellen van een dienstregeling wordt hier ook rekening mee gehouden, mits het een “zinnige” overstap voor normale reizigers is en bijvoorbeeld geen overstap op een trein in de tegengestelde richting. Op een groot station, waar je via de trap en een tunnel naar een ander perron moet, kan dezelfde overstaptijd behoorlijk riskant zijn. Dat soort kennis zit niet vanzelf in zo’n algoritme.

Mark en Sernin proberen een onhaalbare overstap van één minuut te maken.

We hadden om een treinroute gevraagd, niet om een atletiekprogramma.

Hetzelfde geldt voor de betrouwbaarheid van treinen. Sommige treinseries hebben nu eenmaal vaker last van vertragingen en uitval dan andere. De ICE's vanuit Duitsland zijn daar een goed voorbeeld van. Die rijden vaker mét vertraging dan zonder, en vertragingen van een uur of meer zijn bepaald geen uitzondering. Een route waarbij je afhankelijk bent van een krappe aansluiting op zo'n trein, kan op papier uitstekend zijn, maar in werkelijkheid een behoorlijk risico opleveren.

Een ICE lijkt op tijd te arriveren, maar Mark merkt op dat het de trein van gisteren is.

De ICE komt eraan. Dat is voorlopig nauwkeurig genoeg.

Je moet daarom niet alleen kijken naar hoeveel kilometers een route oplevert, maar ook naar hoe groot de kans is dat je die kilometers daadwerkelijk kunt afleggen. En zelfs dan gaat er gedurende 24 uur vrijwel zeker iets mis.

Daarom was de belangrijkste verbetering van mijn software dit jaar misschien niet het vinden van een betere route vooraf, maar de mogelijkheid om tijdens de wedstrijd steeds opnieuw te plannen.

Wat als de dienstregeling niet meer klopt?

Iedereen kent de klachten over vertragingen en uitgevallen treinen. Ik rij ook regelmatig in het buitenland met de trein en vind die klachten daarom schromelijk overdreven. In de vier edities van de Kilometer Kampioen waar ik aan meedeed, hebben we ook maar één keer noemenswaardige vertraging opgelopen.

Natuurlijk ging niet alles op de minuut volgens plan. De Intercity Direct blijft een zwakke schakel van het Nederlandse spoorwegnet. Die had een aantal minuten vertraging, waardoor we moesten overschakelen op een alternatief. Ook hadden we oorspronkelijk een ICE gepland, maar gezien de vertragingen konden we uiteindelijk beter een gewone intercity nemen.

Bij eerdere edities had ik veel informatie in m’n hoofd en gingen we ter plekke puzzelen. Welke treinen kun je nog halen? Waar kun je overstappen? En wat betekent dat voor de rest van de route?

Dit jaar hadden we ook daar software voor gebouwd. Op ieder moment konden we de route opnieuw laten berekenen, rekening houdend met onze actuele positie en de mogelijkheden voor de resterende tijd. Hoe verder de dag vorderde, hoe kleiner de puzzel en de noodzaak om handmatig bij te sturen. Het opnieuw berekenen, al dan niet met wat hulp, hebben we gedurende de wedstrijd eigenlijk de hele dag gedaan.

Mark en Sernin rennen met een routekaart langs een trein op zoek naar hun volgende verbinding.

We hadden twintig miljoen routes. Allemaal vanaf een ander perron, natuurlijk.

Juist bij het ontwikkelen van deze functionaliteit heeft AI me veel tijd bespaard. Ik wist uit eerdere edities precies waarom ik dit wilde hebben en welke functionaliteit ik nodig had. Maar het daadwerkelijk bouwen ging met hulp van AI een stuk sneller.

Ik denk dat dit uiteindelijk doorslaggevend is geweest. Bij een onverwachte situatie konden we snel zien welke mogelijkheden we nog hadden. En bij een wedstrijd waarbij de eerste twee plaatsen uiteindelijk slechts 4,6 kilometer uit elkaar liggen, kan één goede beslissing het verschil maken.

Waren we eigenlijk wel de beste?

Gedurende de ochtend en middag werden we steeds zelfverzekerder. We kwamen andere deelnemers tegen en spraken over de afstanden die iedereen had gepland. Niemand die we tegenkwamen, leek een route van meer dan 1.800 kilometer te hebben.

We begonnen voorzichtig te denken dat we weleens een heel goede kans maakten. Later op de dag hadden online toch meerdere deelnemers ingevuld dat ze meer dan 1.800 kilometer zouden gaan halen. En ondertussen waren er op verschillende plaatsen in Nederland kleine en grotere verstoringen die de plannen van deelnemers behoorlijk in de war stuurden.

We wisten dus helemaal niet meer zo goed hoe we ervoor stonden. Zelf waren we uiteindelijk behoorlijk tevreden over onze 1.824,9 kilometer, maar we hielden er serieus rekening mee dat we misschien tweede of derde waren geworden.

De volgende middag werd ik gebeld door de organisatie, nadat die alle inzendingen had gecontroleerd. We hadden gewonnen! Na al die jaren was dat natuurlijk een kroon op ons werk.

Jeroen kijkt vanaf de bank naar de winnaars en beweert dat zij geluk hadden dat hij niet meedeed.

De beste stuurlui zitten op de bank. Nog steeds onverslagen in alle wedstrijden waar hij niet aan meedeed. Toch denk ik dat we ons voorlopig geen zorgen hoeven te maken over concurrentie uit deze hoek.

Wat dit zegt over ons dagelijkse werk

De Kilometer Kampioen is voor mij vooral een leuke uitdaging. Maar er zijn natuurlijk veel parallellen met hoe we software ontwikkelen voor onze klanten.

We gebruiken dagelijks AI-modellen om sneller te programmeren. Dat werkt vooral goed wanneer je het werk kunt opdelen in overzichtelijke onderdelen en de resultaten vervolgens kunt controleren. Een algoritme implementeren, unittests schrijven, code analyseren of een alternatieve oplossing bedenken: het zijn allemaal taken waarbij AI veel tijd kan besparen.

Het experiment met de routeplanners liet ook zien hoe nuttig het kan zijn om verschillende modellen of implementaties met elkaar te vergelijken. Je hoeft niet altijd zelf ieder detail na te lopen om een probleem te vinden. Soms is het verschil tussen twee uitkomsten al voldoende om te ontdekken dat ergens een verkeerde aanname zit.

Maar je moet wél weten waarop je moet letten. Bij de Kilometer Kampioen gaat dat bijvoorbeeld over de ligging van perrons, de betrouwbaarheid van treinverbindingen en de vraag of een theoretisch mogelijke route ook echt uitvoerbaar is. In ons dagelijkse werk hebben we vergelijkbare voordelen van onze jarenlange ervaring met software voor financiële dienstverleners. We kennen de terminologie, begrijpen de processen en weten welke uitzonderingen en valkuilen je in de praktijk kunt tegenkomen.

Dat helpt al bij het gesprek met een klant. Je begrijpt sneller wat iemand bedoelt en kunt gerichter doorvragen. En bij het ontwikkelen helpt die kennis om de juiste structuur en datamodellen te kiezen, en om problemen te voorkomen die anders misschien pas veel later aan het licht komen. AI neemt meer en meer programmeerwerk uit handen, maar de kwaliteit van de software hangt nog steeds af van de keuzes die je maakt. En om goede keuzes te maken, moet je begrijpen welk probleem je eigenlijk aan het oplossen bent.

De routeplanner van Jeroen was daarvan een mooi voorbeeld. In twintig minuten had hij met één prompt iets gebouwd waar je vroeger dagen over gedaan had, en de resultaten waren indrukwekkend. Tegelijkertijd was er nog wel iemand nodig om te constateren dat uitstappen uit de Eurostar in Rotterdam geen optie was.

Mijn eigen ervaring zat dit jaar vooral in het besef dat we niet alleen een optimale route nodig hadden, maar ook software waarmee we snel konden reageren als de werkelijkheid anders liep dan gepland. En met 1.824,9 kilometer bleek dat dit jaar net genoeg voor de winst.

Mark toont een artikel in het Noordhollands Dagblad over de Kilometer Kampioen.