PiF 8 | <terug> |
: west ( vaknr -- vaknr ) dup z mod 0= \ Begin van een regel? if z + then 1- ; : oost ( vaknr -- vaknr ) 1+ dup z mod 0= \ Begin van een regel? if z - then ;NOORD en ZUID lopen gevaar om buiten de sudoku te raken.
: noord ( vaknr -- vaknr ) z - dup 0< \ Buiten de sudoku? if zz + then ; : zuid ( vaknr -- vaknr ) z + dup zz < 0= \ Buiten de sudoku? if zz - then ;of
: zuid ( vaknr -- vaknr ) z + dup zz < ?exit \ Binnen de sudoku gebleven! zz - ;of
: zuid ( vaknr -- vaknr ) \ Vergelijk deze met NOORD [ zz z - ] literal - \ zz - z + dup 0< if zz + then ;Nog eens dezelfde woordjes, maar nu zonder IF (goede hersengymnastiek!).
: west ( vaknr -- vaknr ) z 2dup mod 0= and + 1- ; : oost ( vaknr -- vaknr ) 1+ z 2dup mod 0= and - ; : noord ( vaknr -- vaknr ) z - s>d zz and + ; : zuid ( vaknr -- vaknr ) [ zz z - ] literal - s>d zz and + ;De kortere IF-loze versies zet ik in de file sudo3.f
Bij het invullen moet je dus bijhouden in welke volgorde dat gebeurt (de historie). Bij het wissen kun je dan de weg terug afleggen. De meest voor de hand liggende structuur hiervoor is een stack (last in - first out) met de nummers van ingevulde vakjes. Het is onhandig om de Forth data stack ermee te belasten, want dat blokkeert het gewone stackverkeer.
Zelf een stack bouwen is gelukkig vrij simpel:
create (historie zz allot align \ Genoeg bytes voor alle vaknummers (historie 1- value hp \ Stackpointer, wijst naar topelement. : >h ( x -- ) hp 1+ dup to hp c! ; : h> ( -- x ) hp c@ hp 1- to hp ; : hleeg? ( -- vlag ) hp (historie u< ; : h-ini ( -- ) (historie 1- to hp ; \ Initiëer de stackEr is geen controle op underflow. Kijk, voordat je H> gebruikt, met HLEEG? of de stack misschien leeg is.
Als het programma verder goed in elkaar zit, kan een vakje hoogstens eenmaal op stack voorkomen. Overflowdetectie zou daarom alleen in een testfase tijdelijk zinvol kunnen zijn.
Het aantal vakjes in de sudoku mag niet groter zijn dan 256 (vaknrs 0..255) want dan passen de vaknummers niet meer in een byte. Voor grotere sudoku's moet de stack met cellen werken i.p.v. met bytes.
: VAKJE-INVULLEN Is er een geldig symbool ingetypt? IF Is het cursorvakje al ingevuld? ?EXIT Noteer de icode in het vakje. Zet het vaknr op de historie-stack. THEN ;Het is vaak handig om vooraf een pseudo-code te schrijven.
Met pseudo-code kun je voorkomen dat je al coderende verdwaalt in een woord dat al maar dikker en dikker dreigt te worden omdat je er aan begint voordat je weet waar het zal eindigen en er steeds weer dingen aan toevoegt die op het laatste moment noodzakelijk blijken te zijn of mogelijkheden moet uitsplitsen die ineens een uitzondering gaan vormen zodat de IF-THEN nestingen liefst ook nog met ELSE erbij groeien als kool en het stackgedrag alleen nog proefondervindelijk achteraf vast te stellen is waarmee er een voor derden ondoordringbare puree ontstaat die je zelf een dag later ook niet meer begrijpt net als deze veel te lange zin.
Zo moet het dus niet (om het effect te verhogen heb ik even geen komma's gebruikt). Een uitgebreid commentaar bij dit soort code maakt de code niet beter.
Hoe minder commentaar er nodig is, hoe beter de code.
En nu we het toch over commentaar hebben,
1) negate z + true ; \ Verwissel van teken en tel er z bij op. 2) negate z + true ; \ Bereken de icode.van 1) wordt je natuurlijk niets wijzer, 2) geeft een hint over wat er gaande is, het 'hoe' zie je wel in de code. Deze code vind je een tiental regels verderop.
SYMBOOL? stelt vast of het een geldig symbool betreft.
Als het antwoord TRUE is, wordt de interne code er bijgeleverd.
Dat is handig omdat we anders bij een geldig symbool vervolgens nog een keer de SCAN moeten toepassen om de icode te berekenen. Nu hebben we hem meteen klaar staan voor verdere verwerking.
: symbool? ( key -- false | icode true ) (symbolen z rot scan nip \ Positie vanaf stringeinde dup 0= ?exit negate z + true ; \ Bereken de icode.INGEVULD? kijkt of een vakje al ingevuld is en NOTEER zet de icode in het sudokuvakje.
: ingevuld? ( hier -- vlag ) (sdk + c@ z < ; : noteer ( icode hier -- ) (sdk + c! ;
In het woord DOEN komt nu de regel:
( key) dup symbool? if hier invullen exit thenAlle ingrediënten voor het woord INVULLEN zijn nu beschikbaar.
: invullen ( icode hier -- ) dup ingevuld? if 2drop exit then tuck \ hier icode hier noteer \ Noteer in de sudoku. >h ; \ Historie-administratieTot zover zijn we afgelopen zaterdag (8 dec 2007) gekomen.
: doen ( key -- key ) [char] [ over = if hier west to hier exit then [char] ] over = if hier oost to hier exit then [char] = over = if hier noord to hier exit then [char] ' over = if hier zuid to hier exit then dup symbool? if hier invullen exit then \ [char] \ over = if ... exit then <-- Opgave 8.1 \ bl over = if hier WIS exit then <-- Opgave 8.2 \ ... ( Andere opties) ;
1. Als je een backslash intypt gaat de cursor naar het laatst ingevulde vakje, als dat er tenminste is. Welke code komt er op de plaats van de puntjes te staan?
2. Met de spatiebalk kun je een vakje wissen, maar dat lukt alleen wanneer de cursor op het laatst ingevulde vakje staat.
: WIS ( hier -- ) ... ;
In sudo3.f vind je de code tot nu toe.
In deze file staat ook al de code die bij PiF 9 hoort voor het importeren van sudoku's. Daardoor wordt er, na het laden van de file, een heuse (demo) sudoku zichtbaar als je SU intypt.
Groeten,
| <terug> |