Blog van Sammy

Ik plaatste een bericht op HN, en daarna werd mijn website overspoeld door AI-bot-verkeer

Een maand geleden plaatste ik het op Hacker News (HN) en het kreeg ongeveer honderd upvotes, geweldig! Het lijkt erop dat mensen echt moe zijn van het horen over LLM's en dat ze het fijn vonden om deze uit hun feed te kunnen filteren. Het was een goede demonstratie van waarom een tool als deze nuttig is. Alles ging goed, en toen…

Mijn website werd traag. Echt pijnlijk traag. Eerst schreef ik het toe aan de extra aandacht van een plotseling populair bericht. Zoals elke ontwikkelaar vierde ik het, maar zwoer ik ook dat ik mijn website in de toekomst veerkrachtiger zou maken. Vreemd genoeg hield de traagheid aan en werd het zelfs erger enkele dagen nadat mijn bericht live ging. De statistieken die ik bijhield, waren onlogisch: een handvol echt actieve, ingelogde gebruikers, maar een server die een exorbitant hoge belasting vertoonde.

Dus ben ik naar de data gaan kijken. Ik voegde logging toe op het hoogste niveau voor elk eindpunt (hoe vaak er een verzoek werd gedaan naar elk URL-pad) en ik ontdekte dat de meerderheid van de verzoeken geen poging deed om nieuwsartikelen op te halen! Ter referentie: mijn website is gebouwd als een single-page-applicatie, wat betekent dat de meerderheid van de verzoeken niet eens de javascript uitvoerde die nodig is om de pagina te renderen.

Bij verder onderzoek in de geaggregeerde NGINX-logs om misbruikers te vinden, bleek dat bijna de helft van ons verkeer van één specifieke gebruiker kwam. Ik zal geen namen noemen, maar ik zocht ze op en ze beschrijven zichzelf als een dienst die luistert naar wijzigingen op een website en deze vervolgens samenvat in een "AI slop" nieuwsbrief. En met 'luisteren naar wijzigingen' bedoel ik dat ze onze website vele malen per minuut bevragen. Geblokkeerd.

Verschillende anderen waren standaard bekende crawlers die zich vriendelijk als zodanig identificeerden: Claude bot, OpenAI bot, Google's search indexer en enkele anderen. Ik kwam zelfs een paar kwetsbaarheidsscanners tegen. Iemand probeerde in ieder geval toegang te krijgen tot -/wp-content/phpinfo.php (mijn website is geen Wordpress-site). Ik heb een robots.txt toegevoegd om de meeste AI-scanners te ontmoedigen, maar Google-bot en ander zoekverkeer toe te staan. Ook heb ik Claude gevraagd om alle kwetsbaarheids-paden te bevragen en de scanners na te bootsen om er zeker van te zijn dat ik niets lekte. Daarnaast heb ik redelijke rate limits toegevoegd, enzovoort.

De belangrijkste les is echter dat het tijd is om mijn website sneller te maken. Ik wil een website zijn die xxx QPS aan echt verkeer kan afhandelen en die beter schaalt, zelfs onder zware belasting. Geïnspireerd door deze gebeurtenis heb ik de afgelopen weken behoorlijk wat verbeteringen aangebracht in de onderliggende infrastructuur, wat zou moeten resulteren in aanzienlijke prestatiewinst voor alle gebruikers.

P.S. Als je het wilt bekijken, de website is volledig gratis en beschikbaar via de link.

Kort samengevat: het stelt je in staat om je eigen aanpassingen te definiëren, naast zaken als de scoretotaals van Hacker News. Je kunt het gebruiken om onderwerpen te filteren, zoals AI of LLM's, maar de onderwerpen zijn volledig willekeurig en je kunt je eigen aanpassingen programmeren.

LLM's gebruiken om de Emacs Web Browser weer geweldig te maken

Wanneer ik mensen vertel over de Emacs web browser, is hun eerste reactie: "Wacht, Emacs heeft een web browser?!", gevolgd door: "Ja... ik gok dat dat een soort web browser is".

De Emacs web browser is ontworpen om webpagina's te renderen in een terminal-gebaseerde, tekst-only omgeving en, nou ja, dat gaat precies zoals je zou verwachten. Het werkt goed voor HTML-only websites met weinig inhoud, maar niet zo goed voor andere zaken.

Het probleem is dat Emacs primair een tekst-editor is, maar het moderne internet is absoluut niet gebaseerd op platte tekst. Simpele HTML uit de jaren '90 heeft een duidelijke vertaling naar platte tekst, maar modern UI-design, met visuele styling, zware javascript en algemene chaos, minder.

De Emacs web browser zou geweldig zijn als we maar een manier konden vinden om terug in de tijd te gaan…

Oké, het plan is simpel. We nemen moderne webpagina's, herschrijven hun broncode naar ouderwetse, simpel gestylede HTML, en sturen dat vervolgens naar de Emacs web browser. We moeten alleen een manier vinden om dit gemakkelijk en op schaal te doen.

En daar komen LLM's om de hoek kijken. Het is fijn om ze op een manier te gebruiken die hopelijk de hoeveelheid spam-inhoud in de wereld vermindert.

In feite is het plan dat we een programma schrijven dat:

  1. Een webpagina opent in Firefox.
  2. De pagina laadt en alle javascript uitvoert.
  3. Een LLM vraagt om een herbruikbaar programma te genereren dat de inhoud van de huidige pagina transformeert in vereenvoudigde tekst.
  4. De gegenereerde javascript in de Firefox-browser injecteert.
  5. De nieuwe paginabron pakt en doorstuurt naar de Emacs web browser.

Ik gebruik het inmiddels en het werkt erg goed. Realistisch gezien kan ik dit nu op veel webpagina's gebruiken waar eww (Emacs Web Wowser) voorheen niet werkte.

Hieronder staan enkele voorbeelden van voor en na:

  • De documentatie voor Clojure's mapcat
  • Figuur 1: (voor) Gebruik van eww-readable
  • Figuur 2: (na) Gebruik van simpleweb-simplify-page

Het duurt even om het initiële modifier-programma te genereren, maar zodra dat gebeurd is, draait het vrij snel. Tijdens het dagelijkse surfen zijn er meestal geen extra LLM-aanroepen nodig. Ik gebruik het zelf en geniet van de ervaring.

De broncode staat hier: https://github.com/sstraust/simpleweb en is open-source en gratis te installeren.

Als technologie beter is geworden, waarom is dan alles slechter geworden?

Ik denk dat we allemaal het antwoord weten: slechte prikkels.

Technologie maakt systemen productiever, maar het maakt jou als persoon niet noodzakelijkerwijs productiever. De tools die computers efficiënter maken, stellen mensen ook in staat om efficiënter jouw tijd, aandacht en welzijn uit te buiten. Ik heb het over neurale netwerken, baby.

Ik merkte het probleem voor het eerst in 2018. Of liever gezegd, ik merkte dat ik een probleem had: ik besteedde drie uur per dag aan het kijken naar Starcraft 2-replays en vroeg me af waar de tijd was gebleven en hoe ik het weer eens tot 02:00 uur had uitgeprogrammeerd.

Wat interessant is, is dat ik deze problemen niet had tot laat in de jaren 2010. Ik had al sinds het midden van de jaren 2000 een computer met internetverbinding, en kort daarna een smartphone met Twitter, Reddit en dergelijke. Het is mogelijk dat ik in de loop der jaren minder veerkrachtig ben geworden, maar ik heb het vermoeden dat de computers zijn veranderd.

Ik kan mijn vinger er niet precies op leggen, maar ik heb het gevoel dat elke keer dat ik met een systeem of website interactie heb, ik een soort vijandig spel speel. Ik probeer gewoon mijn dag door te komen en misschien een kort artikel over computers te lezen, terwijl zij proberen uit te vogelen hoe ze me net iets langer op hun site kunnen houden.

Ik heb ook het gevoel dat nu software engineering is verschoven van een discipline van hobbyisten en enthousiastelingen naar leiders die steeds vaker via financiële of zakelijke trajecten zijn opgeleid, de grote tools waar we ooit van hielden, zowel extreem saai als extreem winstgevend zijn geworden.

Dus, wat kunnen we doen om dit te stoppen?

  • Ga naar buiten (touch grass). Echt, wanneer de wereld er zo uitziet, denk ik dat de beste oplossing is om simpelweg weg te gaan. Het is niet makkelijk, zeker omdat planning vaak online gebeurt, maar ik beloof dat een dag in het park schaken met vrienden beter is dan elke hoeveelheid tijd die je op internet kunt doorbrengen.
  • Ga de straat op. Ik denk dat protesteren effectief is en dat meer mensen dat zouden moeten doen. Als je bereid bent actie te ondernemen, laat je anderen zien dat zij dat ook kunnen.
  • Stop met teruggaan naar dezelfde machines. We hebben allemaal een soort 'gambler's fallacy' in ons: als het de eerste keer niet uitbetaalde, maar soms wel, proberen we het opnieuw. Maar zo werkt het niet echt. Als je geld verliest, is de les om te stoppen met munten in de machine te gooien.

Noot van de redacteur: Ik heb gewerkt aan een gratis aanpasbare nieuwsreader als een manier om mijn frustraties met het moderne internet te uiten. Als je deze niet gebruikt, raad ik aan om individuele blogs en websites te volgen, omdat het veel beter is om volledig van deze grote platforms af te gaan.

Noot van de redacteur 2: Ik heb dit laatste artikel nog niet aan mijn RSS-XML toegevoegd, omdat ik nog niet klaar ben om er meldingen voor te sturen. Dit gebeurt in de komende weken.

Deft versie 0.2.0

Nu dat Deft 0.2.0 is uitgebracht, is het een goed moment om te praten over wat ik heb gebouwd en waarom.

Het doel van de "everything-is-a-map" toolkit van Clojure is dat getters en setters tijdverspilling zijn. Clojure is grotendeels gebouwd als reactie op de slechte Java-workflow van 2008, waarbij je getters, setters en builders moest schrijven, wat leidde tot veel ballast waar niemand van genoot.

Het probleem is dat als je je data wilt representeren met de ingebouwde defprotocol en defrecord, en je functies wilt definiëren die afhankelijk zijn van de aanwezigheid van een bepaald veld, de enige manier om die informatie in het protocol te coderen is door getter- en setter-methoden toe te voegen. Dat is onsmakelijk.

Je kunt ook een combinatie van protocol + Malli-schema gebruiken, maar dan moet je bij gebruik specificeren: "deze functie neemt als input iets dat zowel dit protocol als dit Malli-schema implementeert". Ook onsmakelijk.

Wat we willen is iets dat we kunnen gebruiken in de stijl van defprotocol en defrecord, maar dat standaard alle getters, setters en map-achtige functionaliteiten biedt. Het belangrijkste inzicht is dat als een veld bestaat in een record, we alle andere goede zaken krijgen; we moeten dus alleen ondersteuning toevoegen voor protocollen met vereiste sleutels.

Deft v0.2.0 voegt ondersteuning toe voor namespaced keys in type- en protocoldefinities. Je kunt nu bijvoorbeeld dit doen:

(defp Positioned :required-keys [::pos - ::Point])

en

(deft Circle [::location/position radius])
(>Circle ::location/position [1 2] :radius 12)

Dit is nuttig omdat je nu methoden kunt definiëren die afhankelijk zijn van de aanwezigheid van die velden:

(defp Gremlin :extends [location/Positioned])
(defmethod game-object/get-hitbox ::Gremlin [self]
  (js/Matter.Bodies.rectangle
    (get-in self [::location/pos ::location/x])
    (get-in self [::location/pos ::location/y])
    15 15))

Bekijk het hier: https://github.com/sstraust/deft

Hoeveel LLM's is te veel LLM's?

Ik ben vorige week klaar met het lezen van On the Edge, en het was slecht. Niet dat ik Nate Silver niet respecteer; dat doe ik wel. Dus toen zijn fundamentele tekst over gokken en risico nemen een onsamenhangende puinhoop was, was ik verrast en teleurgesteld. Desondanks, als completionist in hart en nieren, ploeterde ik door tot het einde, waar ik werd begroet met dit bericht:

"ChatGPT was een aanzienlijke hulp bij het schrijven van dit boek, als creatieve muze bij het bedenken van zaken als hoofdstuk-subkoppen, metaforen en analogieën, en voor het verfijnen van mijn begrip van technische onderwerpen die waarschijnlijk goed vertegenwoordigd zijn in het corpus ervan."

Technisch gezien schreef hij het boek met de hand, en technisch gezien typte hij de letters op zijn toetsenbord, maar deed hij dat echt? Heeft hij zijn hele gedachte, geest en wezen in elk woord op de pagina gestoken? Misschien. Ik denk terug aan de klassieker Simple Made Easy, een video waarin een groot deel van de kernlezing is gebouwd op het definiëren van precieze taal en het precies zeggen van wat je bedoelt. Wanneer je dat werk uitbesteedt, sla je niet alleen woordkeuzes over, maar sla je ook het denkproces over, en mis je de organisatie en mentale helderheid.

Bij het lezen van Nate's boek is er een wezenlijk en merkbaar verschil tussen de taal die aanvoelt als ingebakken in de organisatorische structuur van Nate's mentaliteit, en de stukken die als een afterthought zijn toegevoegd. Vooral de latere hoofdstukken voelden alsof ze die mentale compactificatie misten die alles onder één visie samenbrengt. Ik ben verdrietig omdat dit een fenomenaal werk had kunnen zijn; het is duidelijk dat er veel moeite in is gestoken, vooral in interviews en dataverzameling, maar het voelt alsof het net dat ene laatste stukje inzicht mist om het helemaal af te maken.

Dus, hoeveel LLM's is te veel LLM's? Wat betreft menselijke connectie zou ik zeggen: bijna nul. Ik wil je AI-gegenereerde e-mails niet lezen, en ik wil zeker je AI-gegenereerde essays niet lezen. Ik zou liever je prompt lezen, want ik geef om wat jij, ja, jij persoonlijk denkt, en ik wil begrijpen wat je wilde communiceren.

Begrijp me niet verkeerd, ik hou van LLM's voor het juiste doel. Ik zou LLM's graag gebruiken op artsennotities om modellen te bouwen die voorspellen of de griep zich verspreidt. Maar als het gaat om schrijven, zeker dit soort schrijven, voelt het gewoon onnodig. Wanneer je je gedachten opschrijft, heb ik al precies wat ik wilde, en het voelt silly om daar een extra tussenstop aan toe te voegen.

Als pokerspeler en gametheoreticus zou Nate zeker de zin waarderen: "Als jij je niet de moeite kon doen om het te schrijven, dan kan ik me niet de moeite doen om het te lezen". En ondanks het geloof dat kunst los kan staan van de kunstenaar, voelt deze claim voor mij juist waar. Niet dat dezelfde woorden geproduceerd door een mens inherent anders zijn dan dezelfde woorden van een LLM, maar het beïnvloedt mijn kleine Bayesiaanse schatter.

Als de slimste persoon die ik ken 10.000 uur besteedt aan het schrijven, bewerken, polijsten en publiceren van een roman van 500 pagina's, vertelt me dat niet alleen dat die persoon gedachten had over een onderwerp, maar het vertelt me dat ze hebben besloten 10.000 uur van hun kostbare tijd en energie te besteden om dit idee aan mij te communiceren. Het voelt goed dat de tijd die ik nodig heb om het te lezen proportioneel is (en meestal minder is) aan de tijd die jij nodig had om het te schrijven, omdat het laat zien dat je geeft om de tijd en energie van deze uitwisseling.

En het is niet alleen volledig AI-gegenereerde "slop" die tegen deze barrière loopt. Wanneer je LLM's integreert in je schrijven, zelfs een klein beetje, mis je de mogelijkheid om je gedachten te verwerken en menselijke connectie te creëren.

Schaken bouwen in ongeveer 350 regels Clojure

Onlangs heb ik Deft uitgebracht, een Clojure-bibliotheek die types en protocollen definieert met eenvoudige maps. Om het uit te proberen, heb ik het spel schaken in Clojure geschreven.

Schaken is een goede test voor elk klasse- en interfacesysteem, omdat het redelijk klein en zelfvoorzienend is (met duidelijke keuzes voor klassen), maar het brengt ook de complexiteit van een echte applicatie met zich mee; je wilt beknopt schrijven, maar je moet nog steeds edge-cases afhandelen, zoals rokeren (castling) en en passant.

Ik heb alle stukken zelf getekend en dit kleine Reagent-snippet gebruikt om het display te renderen:

[:h-box
 (doall (for [x (range (count tiles))]
   ^{:key x}
   [:v-box
    (doall (for [y (reverse (range (count (nth tiles x)))]
      ^{:key y}
      [:p {:style {:background-color (cond
                    (= [x y] @currently-selected-location)  "yellow"
                    (= (mod (+ x y) 2) 1) "white"
                    :else "black")
                  :height "4rem"
                  :width "4rem"
                }
        :on-click (fn [] (move-selected-piece
                          game-board-atom
                          currently-selected-location
                          [x y]))}
       (if (not (nil? (get-in tiles [x y])))
         [:img {:src (image-path (::piece-type (get-in tiles [x y])))
                :style {:height "100%"
                        :width "100%"
                        :filter (when (= (::color (get-in tiles [x y])) ::black)
                                 "invert()")}}]
         "")]))]))]

Het interessante deel is hoe het bord-staat en alle stukken worden gerepresenteerd. Ik heb het voor de hand liggende gekozen en types gedefinieerd die een schaakstuk representeren, en vervolgens een bord als een 8x8 grid van stukken:

(deft ChessPiece [color piece-type])
(deft ChessBoard [tiles - [:vector [:vector [:or :nil ChessPiece]]]
                  curr-move - [:enum ::white ::black]
                  move-history - [:vector ChessMove]])

Voor het gedrag van de stukken heb ik protocollen gemaakt die definiëren hoe een stuk wordt weergegeven en hoe het kan bewegen:

(defp PieceType
  (image-path [this]))

(defp MovablePiece
  (is-valid-move-for-piece? [this game-board start-location end-location]))

Hier is een voorbeeld voor het paard:

(deft Knight []
  PieceType
  (image-path [this] (image-asset "knight_white.png"))
  MovablePiece
  (is-valid-move-for-piece?
    [this game-board start-location end-location]
    (and
      (let [direction (map abs (map - end-location start-location))]
        (or (and (= (first direction) 1) (= (second direction) 2))
            (and (= (first direction) 2) (= (second direction) 1))))
      (is-valid-end-location? game-board start-location end-location))))

is-valid-move-for-piece? geeft een true-false waarde terug voor de vraag "kan mijn stuk naar dit vak bewegen". Dit werkt prima voor de meeste stukken, maar is onvoldoende voor complexere zetten, zoals rokeren, waarbij meerdere stukken tegelijk bewegen. Om dit af te handelen, gebruiken we een andere multimethod:

(defmulti special-move-for-piece (fn [x & args] (:type x)))

Deze is alleen gedefinieerd voor speciale zetten en geeft de daadwerkelijke staat van het gewijzigde spelbord terug. Voor pionnen zou dat er zo uitzien:

(defmethod special-move-for-piece ::Pawn
  [this game-board start-location end-location]
  (let [curr-piece-color (::color (get-in (::tiles game-board) start-location))
        move-direction (into [] (map - end-location start-location))
        prev-move (last (::move-history game-board))]
    (cond
      ;; en passant
      (and (= (second move-direction)
              (if (= curr-piece-color ::white) 1 -1))
           (= (abs (first move-direction)) 1)
           (= (:type (::piece-type (::piece prev-move))) ::Pawn)
           (= (apply max (map abs (map - (::end-location prev-move) (::start-location prev-move)))) 2)
           (= end-location
              (into []
                    (map +
                         (map (fn [x] (/ x 2 )) (map - (::end-location prev-move) (::start-location prev-move)))
                         (::start-location prev-move)))))
      (-> game-board
          (update ::tiles assoc-in start-location nil)
          (update ::tiles assoc-in end-location
                  (get-in (::tiles game-board) start-location))
          (update ::tiles assoc-in (::end-location prev-move) nil))

      (and (is-valid-move-for-piece? this game-board start-location end-location)
           (or (= (second end-location) 0)
               (= (second end-location) 7)))
      (-> game-board
          (update ::tiles assoc-in start-location nil)
          (update ::tiles assoc-in end-location
                  (assoc (get-in (::tiles game-board) start-location)
                        ::piece-type (>Queen))))
      :else nil)))

Ik zal niet alle zetten voor elk stuk kopiëren, maar het was vrij rechttoe rechtaan om relevante methoden te definiëren voor alle verschillende stukken en speciale gevallen. Wanneer je deze code leest, lijkt het echt alsof iemand gewoon alle regels van het schaken heeft opgeschreven, en dat geeft me een goed gevoel over de organisatie van de code.

Maar nu de belangrijkste vraag: helpt deze bibliotheek echt? Heeft Deft ons leven beter gemaakt?

Ik denk van wel, om de volgende redenen:

  • Deft geeft ons de functies van zowel protocollen/records als multimethoden/plain-maps, waardoor we niet hoefden te beslissen welke tool het beste was voor ons gebruiksscenario. Dit vermindert de cognitieve belasting aanzienlijk.
  • In het bijzonder was het fijn om :default method dispatch te kunnen definiëren voor onze protocollen, en het was extreem fijn om protocol-methode definities vanuit de REPL te kunnen herladen zonder het hele schaakbord opnieuw te hoeven instantiëren.
  • Het was erg fijn om te kunnen afdwingen wanneer method-defs gedefinieerd moesten worden voor een bepaald type, en het was fijn om een eenvoudige manier te hebben om Malli-schema's toe te voegen.

Over het algemeen ben ik erg tevreden met het resultaat en zou ik zeggen dat de test van onze bibliotheek een succes was.

  • Je vindt de volledige code voor het spel hier: https://github.com/sstraust/deft/blob/master/examples/src/examples/chess.cljs
  • De bibliotheek hier: https://github.com/sstraust/deft
  • En de gedetailleerde video-uitleg hier: https://www.youtube.com/watch?v=lrofmFI1UJY

Announcing Deft: Een klasse- en interfacesysteem voor Clojure en ClojureScript

Vandaag breng ik Deft uit! Het is een bibliotheek die Clojure's bestaande klassensysteem vervangt door eenvoudige maps en Malli-schema's.

Het heeft me ongeveer 6 maanden gekost om het volledig uit te denken en het ontwerp precies goed te krijgen, dus het voelt goed om het eindelijk te publiceren.

  • De bibliotheek: https://github.com/sstraust/deft
  • Video Tutorial: https://www.youtube.com/watch?v=dlW6YzwUZ-M
  • Op Hacker News: https://news.ycombinator.com/item?id=46590958

Synopsis

Deze bibliotheek is voortgekomen uit frustraties met het bestaande type-ecosysteem van Clojure. Zowel defrecord/defprotocol als eenvoudige maps + multimethoden maken Clojure-programma's, in de manier waarop ze momenteel worden gebruikt, fundamenteel moeilijk te organiseren en te refactoren.

Het probleem is dat:

  • Clojure records gebruikmaken van single-colon (unnamespaced) keyword access om recordvelden op te zoeken.
  • Clojure records het niet toelaten om abstracte klassen te definiëren, of zaken die vertrouwen op complex dispatch-gedrag.
  • Clojure maps extreem moeilijk vast te leggen en stabiel te maken zijn. Zelfs met bibliotheken zoals Malli is het lastig om interfaces te declareren die uitleggen "wat kan ik met dit ding?".
  • Tenzij je extreem gedisciplineerd bent in het definiëren van Malli-schema's voor elk scenario, is het makkelijk dat zaken losgekoppeld raken tijdens destructuring, omdat gemiste veld-lookups nil teruggeven.

Het doel is om iets te bieden dat nog steeds prettig is om mee te werken, maar waarmee je het gedrag echt vast kunt leggen wanneer dat nodig is (en het toch ergonomisch en leuk houdt).

Een secundair doel was om iets te maken dat betrouwbaar en stabiel is, en (hopelijk) gemakkelijk te adopteren in bestaande codebases.

Mijn blog is nu op RSS

Als je dit leest, kan ik nu publiceren naar mijn blog met RSS. Ik gebruik org-rss-export-to-rss met wat zeer eenvoudige tooling. Ik heb nagedacht over het gebruik van Hugo, maar dat leek me te zwaar; ik hou wel van het minimalistische gevoel. Ik ben optimistisch dat Hugo beter zal zijn wanneer ik het goed heb ingesteld, en ik zal waarschijnlijk uiteindelijk enkele functies ervan nodig hebben, maar dat is een strijd voor een andere dag.

Hoe win je bij Wordle?

Ik heb deze week mijn eerste spel Wordle gespeeld, en ik deed het in 4 beurten! Oké, ik had een beetje geluk, maar het was niet alleen geluk. Tijdens het spelen had ik de kans om over enkele strategieën na te denken en zag ik enkele valkuilen die anderen misschien over het hoofd hebben gezien.

1. Raad geen letters die al groen zijn

Tenzij je probeert je laatste gok te doen om het spel te winnen, moet je niet dezelfde letter op dezelfde plek raden. Je hebt dat al geprobeerd, dus het opnieuw doen geeft je geen nieuwe informatie. Je "gok" is gegarandeerd fout, maar je sluit nu een andere mogelijke letter uit (of vindt deze!) wanneer je de puzzel daadwerkelijk probeert op te lossen.

Voorbeeld: Stel dat je B - A - _ - E - S hebt, allemaal groen. Je moet alleen de laatste letter raden, maar er zijn veel opties over. Onder de letters die je nog niet in dat vak hebt geprobeerd, werken D, K, N, R, S allemaal. Je zou elke letter individueel kunnen gokken, maar in het ergste geval duurt het vijf beurten. In plaats daarvan gok je D - R - I - N - K, een woord waarvan je weet dat het fout is; zo "gok" je alle letters tegelijk, waardoor je gegarandeerd in 2 beurten klaar bent (je gokt S als er geen geel verschijnt).

2. Wanneer je nieuwe letters raadt, plaats ze op plekken waar ze vaak voorkomen

Denk aan Wordle een beetje als een binaire zoekopdracht. Je doel is om met elke gok zoveel mogelijk informatie te verkrijgen. Als je gok de probleemruimte in tweeën splitst (bijv. je elimineert de helft van de mogelijke woorden als het groen wordt, en de andere helft als het geel wordt), leer je gemiddeld de meeste informatie.

Je mag een letter maar op één positie gokken. Als je wilt dat de twee uitkomsten (goed op die plek vs. ergens anders) ongeveer even waarschijnlijk zijn, dan moet de positie die je kiest zeer representatief zijn. Je leert gemiddeld veel meer over de letter 'Y' met een gok als R - A - I - N - Y, dan met een gok als Y - E - A - R - N.

3. Raad eerst de meest voorkomende letters

Hetzelfde principe als hierboven. Het is ofwel een van de 5 specifieke letters die je raadt, of het is een van de 21 andere letters. Je wilt de 5 kiezen die de probleemruimte het meest effectief in tweeën splitsen.

Een stap verder: zodra je een paar regels hebt geraden, wil je de meest voorkomende/meest effectief splitsende letters gokken, gegeven de letters die je al hebt. Q is een slechte eerste gok, maar als je al een U hebt staan, dan misschien wel…

4. Denk bij elke stap na over de lijst met mogelijke woorden

Onthoud dat je doel is om met elke letter "in tweeën te splitsen". Als je een gevoel hebt voor (of een willekeurige steekproef hebt van) de woorden in de ruimte, is het gemakkelijker om de letters/posities te kiezen die deze lijst het meest precies verdelen.

The Power Of Habit (Boekbespreking Deel 1)

Charles Duhigg was een verslaggever voor de New York Times, en dat merk je aan zijn schrijfstijl. Dit is een modern-wetenschappelijk rapport dat sensationeel is, inspirerend, en vaak zeer misleidend.

Dit boek heeft het allemaal: zelfhulp-transformaties van bankhangers naar