Hoe de bot denkt
De pagina Bot speelt geen opname af. Hij draait het echte spel, een Rust/WebAssembly-planner via bot-engine.js, een kleine workerpool wanneer de browser extra cores meldt, en een dunne driver in bot.js in dezelfde pagina. De previews op de landingspagina's laden dezelfde Rust/WebAssembly-planner en wachten net als de Bot-pagina op WebAssembly voordat ze het spel besturen. De planner geeft een DOS-pijltjesscancode terug, waarna de driver dezelfde toets indrukt als een speler.
bot.html; hij leest live variabelen uit de port en drukt toetsen in zoals een speler dat zou doen. Behalve een administratieve ingreep — springen naar het gekozen LEVEL — laat hij de regels en engine ongemoeid.1. Waar de bot draait
De botpagina host het echte spel direct. Hij laadt game.js, daarna bot-engine.js (de WebAssembly-planner en workercoordinator), en daarna bot.js. De driver wacht tot bot-engine.wasm klaar is voordat hij een zet indrukt. Hij regelt nog steeds tabs, herstarts, snelheid en toetsaanslagen:
const stalled = idle > 120 || (idle > 24 && repeats >= 3);
const forceRisk = stalled || movesSincePickup >= 250;
let sc = await planner.decide({ idle, looping, headTrail, budgetMs: routeBudget(forceRisk), forceRisk });
if(sc === null) sc = randomLegalScancode(); // planner geeft op of een beveiliging is getript
if(sc !== null) pushKey(keyOf[sc]); // anders: geen enkele legale zet -> slang sterft
Die plek is bewust gekozen. De game gebruikt const- en let-globals zoals T, BTEL, ETEL, LEVEL, HART, KLAVER en pushKey(). Scripts in dezelfde pagina kunnen die namen zien, ook al zijn het geen gewone window-eigenschappen. Zo kan de bot peek() aanroepen, T[BTEL] lezen en via pushKey() toetsen indrukken alsof hij onderdeel van de pagina is.
Levelsprong
Hij sluit level 1, zet LEVEL = TARGET - 1, drukt een keer F10, en laat de eigen gameloop het gekozen level openen.
Snapshotplanner
Elke beslissing kopieert het CP437-speelveld naar een compacte array, waarna de zoekactie die snapshot gebruikt in plaats van steeds de gerenderde speltoestand te lezen.
Echte invoer
Hij stuurt DOS-achtige uitgebreide toetsstrings: omhoog ' H', omlaag ' P', links ' K', rechts ' M'.
Herstartlogica
Als de slang sterft, ziet de driver het afwikkelen of het lagere levenaantal, zet het volgende diepe level klaar, en sluit de herstartprompt.
2. Welke data hij ziet
De bot gebruikt hetzelfde schermgeheugenmodel als het spel. Er is geen nette lijst met objecten; hij leest tekens uit VRAM met peek(offset). Het slangenlijf wordt opgebouwd uit de game-array T, van staartindex ETEL tot kopindex BTEL.
| Gamewaarde | Betekenis voor de bot | Effect op planning |
|---|---|---|
32 | Leeg vak | Vrij betreedbaar. |
3 ♥ | Hart | Voedsel van 10 punten; laat de slang groeien. |
5 ♣ | Klaver | Voedsel van 25 punten; laat de slang groeien. |
1 ☺ | Smiley | Kost 50 punten, laat de slang toch groeien en spawnt een vervanger; wordt bewust uitgegeven wanneer dat het pad terug naar de staart open houdt. |
10 ◙ | Steen | Duwbaar als het vak erachter leeg is. |
24, 26, 27 ↑→← | Bewegende pijlen | Altijd fataal, inclusief vakken waar ze zo naartoe gaan. |
219 | Slangenkop | De game gebruikt dit voor botsingen; de bot volgt de kop via T[BTEL]. |
Aan het begin van elke beslissing kopieert bot-engine.js de CP437-tekens, de slangoffsets uit T, de pijlentabel D en het recente koppositiespoor naar vaste WebAssembly-buffers. Als workers beschikbaar zijn, heeft elke worker zijn eigen WebAssembly-instance en krijgt hij dezelfde snapshot, zodat hij kan denken zonder gedeelde muteerbare gametoestand. Voor denkbeeldige routes bewaart de Rust-planner alleen verschillen, zoals een geduwde steen of een leeg geworden staartvak, in plaats van voor elke tak de volledige VRAM-array te kopiëren.
3. Een besliscyclus
Elke zet volgt dezelfde ladder. In single-threadmodus wint de eerste strategie die een richting oplevert. In workermodus draait de coordinator de basisplanner naast diepere zoekprofielen: een diepere volledige planner, een diepere urgente/afrondplanner, en bij genoeg cores een agressieve stallbreker. Resultaten krijgen een strategietier, zodat een diepere worker de basis alleen vervangt wanneer hij een even goede of betere soort zet bewijst. Daarna drukt de bot die toets, wacht volgens de snelheidsschuif en rekent opnieuw vanuit de nieuwe live toestand. Boven op de ladder zitten twee toezeggingen. In het eindspel krijgt hij een nulde sport: met nog maar een paar items probeert de planner eerst een complete gesimuleerde toer te certificeren die alles opeet, en neemt die in zijn geheel. En wanneer een voedselzoekactie wint, geeft de planner zijn hele gecertificeerde route terug — de driver speelt die stap voor stap af, met hercontrole per zet, in plaats van elke tik opnieuw te plannen.
Pijlengevaar wordt per tick opnieuw berekend en binnen die tick onthouden.
Eerst een ondiepe zoekactie naar nabije harten of klavers, zonder smileys.
Als het veld krap is of de slang lang is, kiest de planner eerst een bewezen zet naar open ruimte voordat hij ver voedsel najagt.
Als dichtbij niets veilig is en ademruimte niet wint, zoekt de planner verder. Een smileyroute mag pas goed scoren wanneer die de terugweg open houdt of een cluster met volgend voedsel bereikbaar maakt.
Als de kop posities herhaalt of de score lang stil staat, gaat de bot voedsel afdwingen. Als er niet op tijd een volledig bewezen route is, kiest hij een directe drukzet richting bereikbaar voedsel.
Als laatste veiligheidsfallback kiest hij een directe zet die nog door de lokale controles komt.
Als geen route bewezen kan worden, geeft de planner toch de beste direct legale zet terug. De bot drukt nooit zelf Escape.
const decide = options => {
model = capture();
resetDanger();
const urgent = options.idle >= 18 || options.looping;
const forceRisk = options.forceRisk === true;
routeDeadline = now() + options.budgetMs;
let proved = null;
try {
proved = forceRisk
? pressureFood(true, true) ??
nearFood(true) ??
routeFood(true)
: nearFood(false) ??
routeFood(false) ??
pressureFood(false, urgent);
} finally {
routeDeadline = 0;
}
return forceRisk
? proved ?? pressureStep([false, true]) ?? riskyMove() ??
survivalMove([false, true]) ?? lastChanceMove()
: proved ?? (urgent ? pressureStep() : null) ??
survivalMove() ?? lastChanceMove();
};
De looping-vlag komt uit een korte reeks kopposities. De WebAssembly-planner krijgt dat spoor nu ook direct, zodat gesimuleerde routes die over recente hete vakken teruglopen strategische schuld betalen, tenzij ze voedsel dichterbij brengen of staarttoegang bewaren. Als dezelfde kop-offset vaker terugkomt terwijl de score niet stijgt, behandelt de bot staartvolgen als verdacht en schakelt hij over op voedseldruk. De forceRisk-tak hierboven is de eigen ontsnappingsladder van de planner — de meest agressieve voedselgreep, de steen-graafdrukzet, het staartvolgen voor lange slangen, en dan de lokale overlevingszetten, terwijl hij die schuld voor recente vakken verviervoudigt zodat elke geforceerde zet een vers vak inloopt. De live driver zet die tak aan wanneer de slang stilstaat of te lang geen echte pickup eet, en geeft de planner dan extra tijd voordat een willekeurige terugval wordt overwogen. breathingMove() werkt anders: die stap komt vóór verre voedselroutes wanneer de huidige regio krap is, en weegt staartbereik, uitgangen en overlevingsdiepte zwaarder dan directe punten. In die krappe stand kan een smiley beter zijn dan een verre schone pickup als de smileyroute een pad terug naar de bewegende staart houdt. Als de bewijsplanners geen route kunnen certificeren binnen het tijdbudget, kiest pressureStep() een veilige directe zet die de afstand tot bereikbaar voedsel verkleint. Als zelfs dat faalt, geeft lastChanceMove() de minst slechte direct legale zet terug; botpagina's blijven zetten doen tot de slang echt vastzit (geen enkele legale zet) of het level leeg is.
4. Pijlengevaar
Een leeg vak kan een paar ticks later fataal zijn. danger(offset) markeert een doel onveilig als er al een pijl staat, als een voorspelde toekomstige pijl er straks in stapt, of als een pijl via de rand terugkomt.
peek(o) is 24, 26 of 27.De pijlen zijn volledig deterministisch, dus de WebAssembly-planner simuleert ze exact, 28 ticks vooruit — inclusief de stilstandregel van het spel: een pijl die tegen een muur of het slangenlijf botst wacht op zijn plek in plaats van erdoorheen te vliegen. Elke gesimuleerde tak kijkt naar het gevaarmasker dat bij zijn toekomstige stap hoort, dus een route kan een pijlbaan echt timen: vakken die nu leeg lijken maar gekruist gaan worden vallen af, en een gestrande pijl wordt precies verwacht waar hij werkelijk wacht.
5. Zetten simuleren
De kern is move(state, scancode, allowSmile). Die geeft een nieuwe denkbeeldige toestand terug als de zet legaal is, of null als hij botst, omkeert, sterft of een onmogelijke steen wil duwen.
| Regel | Hoe de bot hem toepast |
|---|---|
| Niet direct omkeren | De tegenovergestelde richting van de huidige richting wordt geweigerd. |
| Geen gevaar | Als danger(next) waar is, valt de zet af. |
| Geen zelfbotsing | Een vak in bodySet is verboden. |
| Smileys optioneel | Verboden tijdens schone zoekactie; later alleen waardevol wanneer de groei wordt terugverdiend met een terugweg, kamertoegang of meerdere bereikbare pickups. |
| Stenen duwen | Een steen kan alleen een vak vooruit als dat vak leeg is. |
| Groei | Harten, klavers en smileys laten het lijf groeien; lege zetten verwijderen eerst de staart. |
| Eerste zet bewaren | Elke tak onthoudt alleen de eerste echte toets die straks gedrukt moet worden. |
Hierdoor kan de bot redeneren over het duwen van stenen en over zijn eigen staart die wegschuift. Hij zoekt niet alleen een geometrisch pad door het huidige beeld; hij simuleert hoe het lijf van de slang eruitziet na elke stap op dat pad.
6. Voedsel zoeken
Voedsel zoeken is verdeeld over drie planners. Ze starten allemaal bij de kop, simuleren lijf en geduwde stenen, en bewaren alleen de eerste toets van een winnende route.
| Planner | Wanneer | Limieten | Voorkeur |
|---|---|---|---|
nearFood() | Voor elke brede zoekactie; in krappe posities kan de smileypass vóór een verre schone route komen. | Diepte 10, of 14 met weinig items. | Zeer hoge afstandsstraf: veilig dichtbij voedsel wint. |
routeFood() | De normale voorzichtige routezoeker. | Diepte 98, of 145 in de eindfase; tot 3500-7000 toestanden. | Overleving eerst: bewezen uitweg, staartbereik, uitgangen en ruimte. |
pressureFood() | Bij stilstand, lussen of wanneer gewone veilige voedselzoekers niets vinden. | Diepte 85-155; tot 5000-9000 toestanden. | Meer druk richting voedsel, maar nog steeds zonder duidelijke vallen. |
In de eindfase zoekt de bot dieper, omdat de laatste harten en klavers vaak precies in lastige hoeken liggen. Smileys blijven tweede keus: de bot wil schoon voedsel, maar hij mag er een eten als dat de terugweg open houdt of een bruikbaar cluster met volgend voedsel opent.
De steendoolhoven vragen een extra truc. Daar ligt bijna elk overgebleven hart of klaver achter stenen, en gewone afstand behandelt een steen als muur — dus de voedselzoeker vindt niets en de bot zou alleen rondjes draaien in een open hoek. Dan valt de drukzet terug op een graaf-afstand: een staptelling die door een steenvak mag lopen wanneer het vak er net achter leeg is, want dan kan die steen geduwd worden. De bot volgt die helling en duwt zich naar het ingesloten voedsel in plaats van te cirkelen. De graafrichting is alleen een trekkracht, geen belofte, dus hij stuurt ermee maar overstemt nooit de valcontroles hieronder.
7. Valcontroles
Een hart bereiken is niet genoeg. Veel slechte slangenbots volgen de kortste route en ontdekken te laat dat het voedsel in een doodlopende zak lag. Daarom test Sneekie's bot kandidaten met meerdere signalen, inclusief een bewezen uitweg na het oppakken, vrijgehouden kamerdeuren en vroegere detectie van zelfinsluiting in kleine kamers of smalle doorgangen.
Uitgangen
legalCount() telt hoeveel zetten direct na het eten nog mogelijk zijn. Nul wordt geweigerd; een uitgang krijgt een zware straf.
Bereikbare ruimte
spaceInfo() vult vanaf de gesimuleerde kop en respecteert richting, muren, lijf, stenen, voedsel en gevaar.
Staartbereik
Dezelfde flood fill noteert of de kop de staart kan bereiken. Dat betekent meestal een bewegende ontsnappingsroute.
Overlevingsdiepte
survivalDepth() kijkt met een kleine beam search hoeveel toekomstige zetten mogelijk blijven.
Uitweg
escapeProof() simuleert extra zetten na het oppakken en vereist een pad naar open ruimte of terug richting de bewegende staart.
Kamerdeuren
In de kamerroosters herkent de planner deuren van twee vakken breed en controleert hij dat minstens een deurstrook met de vakken direct ervoor en erna vrij blijft.
Terugkeerpoorten
Buiten kamerlevels behandelt hij smalle doorgangen als kwetsbare poorten: een route die nog maar een dun pad terug naar de staart overlaat krijgt strategische schuld.
Recent spoor
Routes die dezelfde recente vakken opnieuw bezoeken krijgen straf, lager wanneer dat bezoek staartbereik opent of werkelijk dichter bij voedsel komt.
Lokale veegbeurt
Elke zoekactie meet de afstand tot het dichtstbijzijnde bereikbare voedsel en rekent kandidaten per vak boven dat anker een schuld aan; op de kamerlevels kost het verlaten van een kamer die nog voedsel bevat een regioschuld. Nabije harten worden gegeten voordat de bot het scherm oversteekt.
Regioplan
Op de lijn- en kamerdoolhoven deelt de planner het doolhof op in regio's verbonden door smalle gangen en verplicht hij zichzelf de huidige regio schoon te vegen; voedsel elders betaalt tot die tijd een schuld. Zo blijven er geen half opgegeten hoeken achter het groeiende lijf liggen.
Normale voedselroutes moeten na het oppakken een bewezen terugweg naar de bewegende staart houden. Urgente druk mag alleen als laatste redmiddel een zeer ruime losgeraakte regio gebruiken, en alleen in de smileypass — een schone route geeft de terugweg nooit op, want een brug van −50 die de staart bewaart is altijd de betere ruil. Kleine regio's, eenvaks-flessenhalzen, geblokkeerde kamerdeuren, verslechterde deurstroken, kwetsbare terugkeerpoorten en vroege staartafsnijdingen worden gefilterd voordat hun korte-termijnbeloning kan winnen. Het laatste woord is aan de zelfinsluitbewaker: op elk level, ook in het eindspel, wordt een zet die de kop in een zak kleiner dan het lijf drukt omgebogen naar de ruimste veilige richting — en wanneer de enige uitweg een smiley is, betaalt de bot de −50 liever dan zichzelf in te metselen.
8. Noodzetten
Rond de normale veilige voedselplanners heeft de bot vier noodgedragingen. Ze voorkomen bevriezen, en de laatste is een bewuste staartvolg-discipline voor lange slangen.
| Noodplan | Doel | Gedrag |
|---|---|---|
breathingMove() | Vakken vermijden | Loopt vóór verre voedselroutes wanneer het veld krap is of de slang lang is. Hij verkiest staartbereik, toekomstige uitgangen, vrije kamerdeuren en open ruimte. |
pressureFood() | Lussen breken | Loopt bij idle >= 18 of wanneer het recente kopspoor herhaalde posities toont. Hij zoekt voedsel met lichtere overlevingspoorten, eerst zonder smileys, daarna met smileys. |
tailChaseMove() | Eindspel lange slang | Zodra het lijf op open velden ongeveer 80 vakken telt, of op krappe doolhofvelden ongeveer 24, kiest hij de veilige zet met de diepste gegarandeerde overleving terwijl de staart bereikbaar blijft — in de praktijk volgt hij zijn eigen staart en vult hij ruimte in plaats van zichzelf op te sluiten. Korte slangen slaan dit over. |
survivalMove() | Korte brug | De lichtere laatste fallback. Hij scoort directe zetten op ruimte, uitgangen, een algemene trek naar het dichtstbijzijnde bereikbare voedsel, terugwegruimte, smileykosten of -bonus, stenen en rechtdoor gaan. |
Zo krijgt de bot een overlevingsinstinct zonder dat dat instinct het eerste antwoord op elk moeilijk veld wordt. Als de kaart zegt "nog niet eten", mag hij kort naar een groter open gebied bewegen, maar herhaalde kopposities laten de volgende beslissingen voedseldruk verkiezen. Kan ook druk geen route bewijzen, dan blijft de bot alleen bewegen zolang de lokale fallback een overleefbare stap vindt.
9. Routes scoren
Na de veiligheidsfilters krijgt een voedselkandidaat een score. De WebAssembly-planner rolt veelbelovende kandidaten ook door tot maximaal drie pickups, met lagere waarde voor later voedsel maar met opnieuw een bewezen uitweg. De gewichtentabel zelf is afstelbaar: een offline tuner kan elke constante overschrijven via een WebAssembly-buffer en betere waarden zoeken tegen de spelsimulator. De normale route-score geeft overleving het meeste gewicht, daarna punten, en pas daarna kortheid:
score += survivalDepth * 5600
score += exits * 2400
score += reachableSpace * 16
score += escapeSpace * 8
score += escapeTailReach ? +44000 : 0
score += itemPoints * 150
score -= routeDistance * 260
score -= cellsBeyondNearestFood * 900 (met plafond)
score -= leavesARoomStillHoldingFood ? regionDebt : 0
score += returnPreservingSmileys * 8800
score += smileyEscapeBonus
score += preservedRoomDoorLanes
score -= smileysEaten * 10500
score -= blockedRoomDoorLanes
score -= stonesPushed * 55
score -= oneExitAfterEating ? 18000 : 0
De grote gewichten voor staartbereik, overlevingsdiepte, bewezen uitweg, vrije kamerdeuren, terugkeerpoorten en recent spoor zijn het anti-valgedrag. Een iets langere route met toegang tot de staart en een uitweg wint van een korte route een krappe hoek in, of van nog een rondje door dezelfde oude vakken. Klavers blijven belangrijk omdat ze meer punten waard zijn dan harten, maar ze overstemmen de overlevingstests niet. De score kijkt ook voorbij de eerste pickup: bereikbare voedselclusters en vervolg-pickups tellen mee met korting naar afstand, zodat een rijk cluster aan de overkant van het scherm niet langer wint van een hart naast de kop, terwijl smileys duur blijven tenzij ze toegang bewaren of zo'n cluster veilig openen. Een pickup die tegen een muur ligt krijgt nog maar een mild uitstel dat meegroeit met de lijflengte, zodat harten in hoekjes vroeg worden opgeruimd, zolang de slang nog kort is en de zak nog veilig.
De twee nieuwere voedselplanners gebruiken bewust andere gewichten:
| Planner | Belangrijkste scoringsverschil |
|---|---|
nearFood() | Past een zeer grote term -distance * 6200 toe. Dit voorkomt dat de bot veilig voedsel negeert dat maar een paar zetten weg ligt. |
pressureFood() | Gebruikt kleinere val- en smileystraffen bij urgentie, plus een kleinere afstandsstraf. Zo ontsnapt hij aan staartlussen door echte voortgang te boeken. |
survivalMove() | Zoekt geen volledige voedselroute. Hij scoort directe legale zetten op open ruimte, een trek naar het dichtstbijzijnde bereikbare voedsel, uitgangen, smileykosten, steenkosten en de voorkeur voor rechtdoor. |
Twee extra krachten vormen de score. Een smiley kost −50, en op deze levels spawnt elke pickup er een nieuwe, dus het veld vult zich met smileys; de planner verlaagt de straf alleen wanneer er een echt naar bereikbaar voedsel overbrugt, en houdt anders de volle straf, zodat de bot niet voor niets aan smileys knabbelt. Als laatste controle, nadat een zet is gekozen, weigert de bot helemaal om op een smiley te stappen wanneer een hart bereikbaar is zonder er een te kruisen, zodat hij nooit de −50 betaalt voor een pickup die hij een vakje eromheen had kunnen bereiken — tenzij die smiley precies is wat het pad terug naar de staart open houdt. Een bewuste ontsnappingssmiley wordt nooit overstemd, en de zelfinsluitbewaker, die altijd als laatste loopt, kan er zelf een kiezen wanneer elke schone richting het lijf zou insluiten. En omdat de levelbonus elke zet wegloopt en bij het uitspelen in de score wordt geboekt, komt er een kleine extra afstandsstraf — geschaald met de resterende bonus — zodra er nog maar een paar items over zijn, wat de bot naar de kortste afrondroute duwt in plaats van te treuzelen op de laatste pickups. Beide zijn tie-breakers: ze overstemmen nooit de overlevingsfilters.
10. Snelheidslimieten
De bot moet tussen zichtbare zetten kunnen denken. Daarom zijn er harde caps:
danger()gebruikt een generatiecache.nearFood()blijft de ondiepe eerste pass.routeFood()kan 3500 toestanden scannen, of 7000 in eindfase of urgentie.pressureFood()kan 5000 toestanden scannen, of 9000 wanneer urgent.survivalDepth()is een beam search en bewaart in WebAssembly tot 128 toestanden per diepte.escapeProof()bewaart tot 160 beste toestanden per diepte na het oppakken terwijl hij bewijst dat de voedselroute een uitweg heeft.- Voedsel zoeken is ondieper bij gewone beslissingen midden in een level en gaat pas dieper tegen het einde van een level.
- De schuifregelaar zet het doeltempo tussen toetsaanslagen; plannertijd telt mee binnen dat tempo wanneer dat past, en extra workerthreads krijgen grotere routezoekbudgetten dan de basisplanner.
De schuifregelaar klikt vast op deze snelheden: 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100. Lage waarden laten de bot langer wachten tussen zetten; hoge waarden drukken veel sneller toetsen in, tot ongeveer 45 ms per zet. Normale plannertijd wordt van die wachttijd afgetrokken; als een zoekactie langer duurt dan het doeltempo, gaat de volgende toets meteen door.
delay = round(45 + 375 * ((100 - speedValue) / 100) ** 1.6)
11. Win, dood, herstart
De botpagina heeft zeven tabs: levels 2-8. Winst flitst groen, falen flitst rood, en beide gaan daarna door naar de volgende tab. Na level 8 gaat hij terug naar level 2. De winstflits gebruikt dezelfde korte puls als de vastloopflits voordat het volgende level laadt.
| Voorwaarde | Resultaat |
|---|---|
LEVEL === TARGET + 1 && LIVE > 0 | Schoon gehaald. Groen flitsen en door naar het volgende gekozen level. |
LEVEL !== TARGET | Het spel sprong weg of eindigde. Beschouw als falen en flits rood. |
BTEL beweegt niet meer | De slang is ingesloten of beweegt niet. Blijf zetten doen; de run eindigt alleen in dood als er geen legale zet meer is, anders in een leeg level. |
| Planner geeft geen zet terug | Val terug op een willekeurige legale zet. De vastloopsequentie, inclusief de rode flits, wordt alleen gebruikt als er helemaal geen legale zet bestaat — de slang zit echt vast. |
| Geen scorewinst gedurende 120 beslissingen, of 24 met herhaalde kopposities | Blijf de WebAssembly-planner raadplegen, maar zet forceRisk. Daardoor weegt recente-lus-schuld veel zwaarder, krijgt de planner meer tijd, en krijgen verse vakken, voedseldruk, stenen graven en terugweg-bewarende zetten voorrang. Een willekeurige legale terugval gebeurt alleen als de planner geen zet teruggeeft. |
| 250 zetten zonder hart of klaver te eten (smileys tellen niet mee) | Dezelfde forceRisk-plannerroute, zodat een lange droge reeks een sterkere Wasm-ontsnappingszoektocht wordt in plaats van een herstart. Het is geen dood- of herstart-trigger meer. |
Score wordt gebruikt voor het idle-signaal in plaats van itemaantal, omdat late harten klavers kunnen spawnen. De laatste klaver kan een lange route vragen zonder dat de score meteen verandert, dus de bot blijft zoeken in plaats van de stille score als mislukking te lezen. De aparte pickup-limiet van 250 zetten telt alleen echt voedsel — een smiley van −50 is geen vooruitgang, dus knabbelen aan smileys kan niet meer voorkomen dat de limiet trips — en wanneer hij trips, schakelt hij de bot enkel over op geforceerde Wasm-ontsnappingsplanning, nooit een dood of herstart.
12. Grenzen en afwegingen
De bot is bewust praktisch, niet perfect. Hij lost niet het hele level als een enorm plan op, want het bord verandert na elke pickup, geduwde steen, gespawnde klaver en vijandentick. In plaats daarvan plant hij voortdurend opnieuw vanuit de live toestand.
- Hij simuleert het lijf en geduwde stenen, maar niet een volledige meer-tick-toekomst van alle vijanden.
- Hij behandelt huidig en volgend pijlengevaar voorzichtig en rekent na de echte game-update opnieuw.
- Zijn state-hash is compact en bedoeld om te snoeien, niet om elk borddetail te bewaren.
- Hij kan een smiley kiezen wanneer schone voedselroutes falen, of wanneer het bord krap is en de smiley de terugweg open houdt.
- De survival-beam bevoordeelt veel uitgangen en kan smalle maar technisch veilige routes missen.
Kort gezegd: de bot denkt als een voorzichtige slangen-speler. Hij wil dichtbij voedsel, maar alleen als dat voedsel ademruimte overlaat. Wordt het krap, dan zijn open ruimte en toekomstige uitgangen belangrijk, in een steendoolhof graaft hij naar ingesloten voedsel, en zodra hij lang wordt valt hij terug op het volgen van zijn eigen staart om de diepste overleving te houden en ruimte te vullen.