Algoritme.

 Lingo is een spelprogramma op de Nederlandse televisie waarbij twee paren deelnemers tegen elkaar strijden.
 Even zoeken op youtube brengt je zo naar enkele afleveringen om te bekijken.
 Er moet binnen 5 of 6 beurten een woord worden geraden uit een goedgekeurde lijst Nederlandse woorden.
 Een woord kan goed zijn of gedeeltelijk goed. Van een voorgesteld woord kan een letter op de juiste plaats
 staan; of in het woord voorkomen maar niet op de juiste plaats; of helemaal niet voorkomen.
 Het lingo concept is in de loop der jaren wel enigszins veranderd. Er waren 5-letter woorden, 6-letter
 woorden waarin het eerste woord al was gegeven etc. Meestal mocht men na een correct binnen het aantal
 beurten geraden woord een genummerde bal uit een grabbelton halen die in een soort 5-op-een-rij werd
 geplaatst, en dan was er ook nog een twaalfletterwoord dat geleidelijk werd ingevuld en geraden moest
 worden.
 Op de Belgische site www.nieuwsblad.be/woordkraker kun je een spel vinden dat lingo enigszins benadert.
 Een correcte letter wordt in het voorgestelde woord met groen aangegeven, wel voorkomend maar op onjuiste
 plaats als geel, en niet-voorkomend als grijs. Je mag 1X per dag meedoen, morgen is er weer een nieuw
 woord.

Het algoritme dat voor dit programma wordt gebruikt, werkt ongeveer als volgt:

Voor de gegeven letterbreedte (5 of 6) wordt er een woordenlijst ingelezen. Deze wordt vooraf even gesorteerd.
Voorzover dat nog niet was gebeurd. Mocht het voorkomen dat nieuwsblad een woord schijnt te willen laten
raden dat niet in die lijst staat dan kun je die toevoegen zonder al te veel zorgen over gesorteerdheid.
Andersom kun je woorden uit de lijst verwijderen waarvan nieuwsblad aangeeft dat ze niet worden geaccepteerd.
De woorden uit de lijst worden in een stringarray words$() ingeladen.
Er wordt een gelinkte lijst (list%() ) gemaakt die gelijk oploopt met deze words$() array. De lijst is alleen
voorwaarts gelinkt. De bedoeling van deze opzet is om simpel woorden uit de lijst te verwijderen zonder de
eigenlijke words$() array te veranderen (want af en toe hebben we die toch nog nodig).
De 'ij' wordt door Nieuwsblad als EEN letter beschouwd (dus 'ijstijd' zijn 5 letters) in het programma is 
het character na 'z', namelijk '{' hiervoor gebruikt. In de woordenlijst zie je steeds een '{' als 'ij' wordt
bedoeld. Als je woorden wilt toevoegen probeer hier dan rekening mee te houden: woorden van een bepaald
aantal letters in de juiste lijst en 'ij' invoeren als '{'.

Hoe bedien je het programma?
Je typt een voorstelwoord in (in dit programma moet dit gebeuren door op het 'toetsenbord' te klikken), of
je klikt op een van de woorden in de kolom die rechts verschijnt. Deze lijst kun je scrollen. In deze kolom
rechts, staan alleen de woorden die nog meedoen; hij wordt dus gaandeweg het spel steeds korter (hopelijk),
Een derde mogelijkheid is om het programma zelf woorden te laten voorstellen; je kunt hier evenwel overheen
'typen' (dwz. toetsenbord aanklikken) of een van de woorden rechts aanklikken, om de automatische keuze te
'overrulen'.
Als je tegen Nieuwsblad speelt, moet je eerst nog het zelfde voorstelwoord in de website van nieuwsblad
invoeren. Dan krijg je een kleurencode terug die je in dit programma moet invoeren, door gekleurde vakjes
op de latters te slepen.
Je kunt dan klikken op 'Raad' om de zaak in beweging te zetten. Er gebeuren dan drie dingen:
Als je tegen programma speelt, berekent het programma de kleuringen van het voorstelwoord.
Met voorstelwoord en de kleuringen, wordt een 'resultword' berekend dat bestaat uit !, ? em . karakters.
De '!' komt overeen met groen, de '?" met geel en de '.' met grijs.
Intern worden de woorden die er nog zijn, niet rechtstreeks veranderd met deze !!??.. codering.
Inplaats daarvan worden er een aantal interne tabellen bijgewerkt:
positiemogelijkheden(0..AantalLetters), minimumvandezeletter(0..26), maxvandezeletter(0..26)

In deze tabellen worden letters ge-codeerd als bitposities. Het werkt hier alleen met onderkastletters;
het zijn arrays dus die laat je graag beginnen met ...[0]. De letters lopen van a..z dus 'a' moet '0' worden:
'a' heeft ASCII waarde 97 dus om 'a' een waarde te geven doe je c=ASC"a" en c=c-97, of korter, c=ASC"a"-97.
Zo wordt 'a' = 0 en krijgt 'b'=1, 'c'=2,'d'=3,'e'=4 helemaal tot 'z' = 25 en '{' ('ij') =26.
Het heeft allemaal voordelen om letters zo te coderen. Je kunt bijvoorbeeld heel gemakkelijk kijken of een
letter, of een aantal letters, in een woord voorkomen. Codeer de gewenste zoekletters tot een mask
dwz. mask=1<<lettr1 + 1<<letter2 + 1<< letter3 enzovoorts; en codeer het woord tot een bitcombinatie:
word%=0:FOR i%= 1 TO AantalLetters%:char$=MID$(woord$,i%,1):c%=ASCchar$-ASC"a":word%=word%OR (1<<c%):NEXT

Bepaaal de EN functie van die twee grootheden. Als de functie '0' oplevert, dan komen de gezochte letters
niet in het woord voor. Is de functie iets anders dan kun je zelfs tellen hoeveel letters voorkomen:
de bewerking (woord AND -woord) levert een getal met maar een enkel '1' bit erin, en wel op de
least-significant-bit positie. Als je doet: n%=0:WHILE a%<>0:a%=a%ANDNOT(a%AND-a%):n%+=1:ENDWHILE dan geeft
n% het aantal '1' bits , dus in ons geval het aantal zoekletters dat in het te onderzoeken woord staan.

Positiemogelijkheden() is een array van 32-bit words, er zijn evenveel elementen als er letters in een woord
zijn (dus 5 of 6). Per 'word' wordt bijgehouden welke karakter op een bepaalde positie kan staan, dwz, als 
1e, 2e,3e.. tot laatste letter. Er zijn letters (a..z,{ ) bijvoorbeeld die wel in het eerste letter van het
woord kunnen voorkomen maar niet in tweede, wel in derde, niet in vierde of vijfde enzovoorts (dit is een
voorbeeld).
Als een letter groen is, dan is in het word op die positie, alleen de bitwaarde van -->die<-- letter '1'
dus bijvoorbeeld, als de tweede letter van het voorgestelde woord een 'a' is en hij komt terug met een '!'
dan wordt positiemogelijkheden(1) = 1. Want 'a' krijgt codering '0' en 1<<0 = 1. Als een 'c' de juiste
letter was geweest; c krijgt codering '2' (want c=ASC"c"-97)=2 dan was positiemogelijkheden(1)=(1<<2)=4.
Eerste letter komt in positiemogelijkheden(0), tweede in positiemogelijkheden(1), ... en de laatste in
positiemogelijkheden(AantalLetters%-1).
Een gele codering zorgt ervoor dat op die positie de letter mogelijkheid wordt gewist en op alle andere
zo wordt gelaten, dwz '1'. Gelaten, want aan het begin kan elke letter op elke plaats staan en de 
positiemogelijkheden() array heeft in het begin alle words gelijk aan (1<<27) -1. De '27' omdat er 26
letters zijn en een '{' als codering voor de 'ij'. Alle letters kunnen not '1' zijn, dus 1+2+4+8+16...
Een grijze codering wist de lettercodering uit alle posities, behalve als er al een groen of geel voor
die letter op een andere positie was voorbijgekomen. Dit staat in PROCwerkfreq_en_positie_bij, de centrale
procedure in dit programma.

minimumvandezeletter() houdt bij hoevaak in de opvolgende voorstelwoorden een bepaalde letter,
bijvoorbeeld 'e', is voorgekomen en met groen of geel beloond. Later, bij het uitdunnen van de woordenlijst
wordt deze eigenschap vergeleken met de woordenschat. Zijn er bijvoorbeeld 2 'k' - s goedgekeurd in het
voorstelwoord en heeft een bepaald woord niet twee 'k' -s of meer, dan moet hij uit de woordenlijst verdwijnen.

maxvandezeletter(0..26) houdt bij hoeveel er maximaal mogen voorkomen van een bepaalde letter.
Waar minimumvandezeletter begint met 0 en opklimt, begint 'maxvandezeletter' met AantalLetters% en wordt per
letter gaandeweg kleiner. Stel dat in een woord er een 'a' voorkomt met een groene kleur, en nog een 'a'
met een grijze kleur, dan weten we dat er maximaal 1 letter 'a' mag voorkomen; maxvandezeletter(0) =1
(codering voor 'a' = ASC"a" - 97=0). Later, bij bekijken van de woorden die nog in de lijst staan, wordt dit
gebruikt om woorden af te strepen; komen er in het woord meer letters van een bepaald type voor dan wat
'maxvandezeletter' aangeeft dan moet deze letter sneuvelen.

Vervolgens worden de woorden die nog in de lijst staan, vergeleken met de hierboven genoemde 3 arrays
(dus positiemogelijkheden, minimumvandezeletter,maxvandezeletter). De woorden worden niet echt verwijderd
maar in de lijst worden de voorwaartse pointers zo verzet dat als je de lijst doorloopt, je de afgekeurde
woorden niet meer tegenkomt.

Deze aanpak werkt redelijk maar heel af en toe krijg je het probleem dat nog maar 1 letter hoeft worden
ingevuld maar er kunnen heel veel letters op die plaats staan: bijvoorbeeld fitten, hitten, kitten, pitten,
ritten, titten, uitten, vitten, witten, zitten. 'ditten' uit 'ditten en datjes' kan zelfs nog. Daarvoor is
er een extra truuk, probeer een woord te vinden dat zoveel mogelijk van de mogelijke letters in zich verenigt.
dan kun je hopen dat je inplaats van 1 letter per gok, er drie of vier kwijt raakt. De woorden met zoveel
mogelijk letters, zul je niet meer in de todusver uitgedunde lijst vinden; doorloop hiervoor de volledige
woordenverzameling.
Een tweede optimalisatie is. als er (voorbeeld, 6 letterwoord) vier !!!! (groenen) voorkomen en een '?" 
(geel) en een '.' (grijs) dan kun je de letters op de '?' en '.' plaatsen onderling uitwisselen, en de '?' 
veranderen in een '!'.

Hierbij zijn we al weer aangekomen bij het voorstellen van een nieuw woord. De gevolgde methode is, doorloop
de lijst met nog bestaande woorden; turf hoevaak bepaalde letters daarin voorkomen; doorloop dan nogmaals
de verzameling woorden en geef elk van die woorden een score afgaand op hoevaak de letters voorkwamen.
Sorteer op score, en stel de hoogst scorende voor.


