4d2006-02 Listings

Hexadoku-Rätsel-Vorgaben erzeugen

\ HEXADOKU.FTH   by Fred Behringer 

HEX

\ In Turbo-Forth und ZF vorhanden, jedoch nicht ANS
\ -------------------------------------------------

: ON ( ad -- ) -1 SWAP ! ;
: OFF ( ad -- ) 0 SWAP ! ;


\ Matrixaufbau
\ ------------

\ Alle Bearbeitungen (Zeilen-/Spalten-Vertauschung etc) nur fuer MATRIX.
\ Bei VORGABE wird zunaechst MATRIX nach V-MATRIX kopiert und die Vorgabewerte
\ werden in MATRIX gesammelt.
\ XCH-M tauscht MATRIX und V-MATRIX gegeneinander aus.

\ Hexadoku-Matrix, zeilenweise, pro Element ein Byte
VARIABLE MATRIX 0FF ALLOT

\ Vorgabe-Matrix, vom selben Aufbau wie MATRIX
VARIABLE V-MATRIX 0FF ALLOT

\ MATRIX nach V-MATRIX kopieren
: CPY-M ( -- ) 100 0
   DO MATRIX I + C@ V-MATRIX I + C! LOOP ;

\ MATRIX mit V-MATRIX vertauschen
: XCH-M ( -- ) 100 0
   DO MATRIX I + C@ V-MATRIX I + C@ MATRIX I + C! V-MATRIX I + C! LOOP ;

\ MATRIX zu etwa 50% mit vorgegebenen Elementen belegen
\ seed = Anfangsbyte im RAM fuer Zufallsauswahl
\ Kleinerer Belegungsprozentsatz gelingt durch mehrfache Anwendung
: AUSWAHL ( seed -- )
   100 0 DO DUP I + C@ 1 AND 0= IF 20 I MATRIX + C! THEN LOOP DROP ;

\ Vorher MATRIX sichern
: VORGABE ( seed -- ) CPY-M AUSWAHL XCH-M ;


\ MATRIX-Elemente
\ ---------------

\ Adresse ad[ij] von Element a[ij] in MATRIX, i = Zeile, j = Spalte
: AD[IJ] ( i j -- ad[ij] ) SWAP 10 * + MATRIX + ;

\ Hole Element a[ij] von MATRIX
: A[IJ]@ ( i j -- a[ij] ) AD[IJ] C@ ;

\ Speichere Element a[ij] nach MATRIX
: A[IJ]! ( a[ij] i j -- ) AD[IJ] C! ;


\ Zeilen und Spalten
\ ------------------

\ Hole Zeile  i von MATRIX, letztes Element zuerst auf Stack, I=j !
: A[I.]@ ( i -- a[i.] ) 00 0F DO DUP I A[ij]@ SWAP -1 +LOOP DROP ;

\ Hole Spalte j von MATRIX, letztes Element zuerst auf Stack, I=i !
: A[.J]@ ( j -- a[.j] ) 00 0F DO I OVER A[IJ]@ SWAP -1 +LOOP DROP ;

\ Speichere  Zeile i von MATRIX, juengstes Stack-Element zuerst ins RAM, I=j !
: A[I.]! ( a[i.] i -- ) 10 00 DO SWAP OVER I A[IJ]! LOOP DROP ;

\ Speichere Spalte j von MATRIX, juengstes Stack-Element zuerst ins RAM, I=i !
: A[.J]! ( a[i.] j -- ) 10 00 DO SWAP OVER I SWAP A[IJ]! LOOP DROP ;


\ Rotationen und Konstantenaddition
\ ---------------------------------

\ Linksrotation der Zeile i von MATRIX um 1 Spalte
: ROL1[I.] ( i -- ) >R R@ 0 A[ij]@ R@ A[i.]@ DROP R> A[i.]! ;

\ Linksrotation der Zeile i von MATRIX um 4 Spalten
: ROL4[I.] ( i -- ) 4 0 DO DUP ROL1[I.] LOOP DROP ;

\ Addition von 4*n zu saemtlichen Elementen von MATRIX
: ADD4 ( n -- ) 4 *
    100 0 DO DUP MATRIX I + C@ + 10 MOD MATRIX I + C! LOOP DROP ;

\ Rechtsrotation der Zeile i von MATRIX um 1 Spalte
: ROR1[I.] ( i -- ) >R R@ A[i.]@ R@ 0F A[ij]@ R> A[i.]! DROP ;

\ Rechtsrotation der Zeile i von MATRIX um 4 Spalten
: ROR4[I.] ( i -- ) 4 0 DO DUP ROR1[I.] LOOP DROP ;


\ Bildschirmdarstellungen
\ -----------------------

\ Spaltensprung
: J+ ( i -- ) DUP 0> SWAP 4 MOD 0= AND IF SPACE THEN ;

\ ASCII --> Ziffernausgabe
: ZIFF ( n i -- ) J+ DUP 0F U> IF EMIT SPACE ELSE . THEN ;

\ Zeilensprung
: I+ ( i -- ) DUP 0> SWAP 4 MOD 0= AND IF    CR THEN ;

\ Bildschirmdarstellung von MATRIX
: .M ( -- ) 10 0 DO I I+ CR I A[I.]@ 10 0 DO I ZIFF LOOP LOOP ;

\ Bildschirmdarstellung von V-MATRIX
: .V ( -- )  CR 10 0
   DO I I+ 24 SPACES 10 0
      DO V-MATRIX J 10 * + I + C@ I ZIFF
      LOOP CR
   LOOP ;

\ Bildschirmdarstellung von MATRIX & V-MATRIX
: .M&V ( -- ) CR 10 0
   DO 10 0 DO   MATRIX J 10 * + I + C@ I ZIFF LOOP 5 SPACES
      10 0 DO V-MATRIX J 10 * + I + C@ I ZIFF LOOP CR I 1+ I+
   LOOP ;


\ Abwandlungen von MATRIX
\ -----------------------

\ Kanonische Matrix --> MATRIX
: KANON ( -- )
   00 0F DO I -1 +LOOP 00 A[I.]!
   10 01 DO I 4 MOD 0=
           IF   I 04 - A[I.]@ I A[I.]! I ROL1[I.]
           ELSE I 01 - A[I.]@ I A[I.]! I ROL4[I.]
           THEN
         LOOP ;

\ Linkskanonische Matrix --> MATRIX
: KANONL ( -- ) KANON ;

\ Rechtskanonische Matrix --> MATRIX; entspricht KANON mit ROR statt ROL.
: KANONR ( -- )
   00 0F DO I -1 +LOOP 00 A[I.]!
   10 01 DO I 4 MOD 0=
           IF   I 04 - A[I.]@ I A[I.]! I ROR1[I.]
           ELSE I 01 - A[I.]@ I A[I.]! I ROR4[I.]
           THEN
         LOOP ;

\ Transponierte von MATRIX, a[ij] <--> a[ji] fuer i < j
: TRANSP ( -- )
   10 0 DO
   10 0 DO I J < IF I J A[IJ]@ J I A[IJ]@ I J A[IJ]! J I A[IJ]! THEN
        LOOP
        LOOP ;

\ Viererquadrate und Streifen
\ ---------------------------

\ Aus Zeile/Spalte mach Viererquadrat  (0...f)
: IJ>V ( i j -- v )  4 / SWAP 4 / 4 * + ;

\ Aus Zeile/Spalte mach Querstreifen   (0...3)
: IJ>Q ( i j -- q )  DROP 4 / 4 * ;

\ Aus Zeile/Spalte mach Laengsstreifen (0...3)
: IJ>L ( i j -- l )  NIP  4 / 4 * ;

\ Aus Quer/Laengs  mach Viererquadrat  (0...f)
: QL>V ( q l -- v )  SWAP 4 * + ;

\ Aus Viererquadrat mach Quer/Laengs   (0..3, 0..3)
: V>QL ( v -- q l )  4 /MOD SWAP ;

\ Tausche Zeile  i1 in MATRIX gegen Zeile  i2
: XCHI ( i1 i2 -- )
   >R >R R@ A[I.]@ R> R@ SWAP >R A[I.]@ R> A[I.]! R> A[I.]! ;

\ Tausche Spalte j1 in MATRIX gegen Spalte j2
: XCHJ ( j1 j2 -- )
   >R >R R@ A[.J]@ R> R@ SWAP >R A[.J]@ R> A[.J]! R> A[.J]! ;

\ Kehre Zeilenfolge  in MATRIX um ( i <--> 0f-i )
: INVERSI ( -- )  8 0 DO I 0F I - XCHI LOOP ;

\ Kehre Spaltenfolge in MATRIX um ( j <--> 0f-j )
: INVERSJ ( -- )  8 0 DO I 0F I - XCHJ LOOP ;

\ Tausche Querstreifen   q1 in MATRIX gegen Querstreifen   q2
: XCHQ ( q1 q2 -- ) 4 MOD SWAP 4 MOD
   4 0 DO 2DUP 4 * I + SWAP 4 * I + XCHI LOOP 2DROP ;

\ Tausche Laengsstreifen l1 in MATRIX gegen Laengsstreifen l2
: XCHL ( l1 l2 -- ) TRANSP XCHQ TRANSP ;


\ Hauptprogramm: Folge von Hexadokus
\ ----------------------------------

\ Zaehler
VARIABLE INDEX

\ Bildschirmanzeige mit zugehoeriger Loesung (LOES? = ON/OFF)?
VARIABLE LOES?
LOES? ON       \ Default
\ Start von HEXA bei kanonischer MATRIX?
VARIABLE KANON?
KANON? ON      \ Default

\ Beliebig viele Vorgabematrizen erzeugen und anzeigen.
\ Bei LOES? OFF nur Vorgaben, bei LOES? ON auch Loesungen.
\ KANON? ON : Start mit kanonischer MATRIX
\ Return-Taste oder [q] oder [Q] = raus, andere Taste = naechstes Bild.
: HEXA ( -- ) 
   ." Taste oder ( [ret] oder [q] oder [Q] ) druecken!" CR
   2000 INDEX ! ( seed zu Beginn der Folge )
   KANON? @ IF KANON THEN
   BEGIN
     KEY DUP
     0D ( [ret] ) = OVER 71 ( q ) = OR SWAP 51 ( Q ) = OR IF EXIT THEN
     5 INDEX +!
     INDEX @ C@ 1 AND IF TRANSP  THEN 3 INDEX +!
     INDEX @ C@ 1 AND IF INVERSI THEN 3 INDEX +!
     INDEX @ C@ 1 AND IF INVERSJ THEN 3 INDEX +!
     INDEX @ C@ INDEX @ 1+ C@    XCHQ 3 INDEX +!
     INDEX @ C@ INDEX @ 1+ C@    XCHL 3 INDEX +!
     INDEX @ C@                  ADD4 3 INDEX +!
     INDEX @ C@ 4 / 4 * 10 MOD DUP
     INDEX @ 1+ C@ 4 MOD + SWAP INDEX @ 2 + C@ 4 MOD + XCHI 5 INDEX +!
     INDEX @ C@ 4 / 4 * 10 MOD DUP
     INDEX @ 1+ C@ 4 MOD + SWAP INDEX @ 2 + C@ 4 MOD + XCHJ 5 INDEX +!
     INDEX @ VORGABE LOES? @ IF .M&V ELSE .V THEN
     CR ." Weiter mit Taste, raus mit [ret] oder [q] oder [Q] !"
   AGAIN ;


\ Zulaessigkeitspruefungen
\ ------------------------

\ Tritt n in Zeile i mindestens zweimal auf ? Meldung, wenn ja.
\ Funktioniert auch fuer Leerstellen (n=20h)
: 2*INI? ( n i -- )
   INDEX OFF 10 * MATRIX +
   10 0 DO 2DUP I + C@ = IF 1 INDEX +! THEN LOOP 2DROP
   INDEX @ 1 > ABORT" Mindestens zweimal!" ;

\ Tritt n in Spalte j mindestens zweimal auf ? Meldung, wenn ja.
\ Funktioniert auch fuer Leerstellen (n=20h)
: 2*INJ? ( n j -- ) TRANSP 2*INI? TRANSP ;

\ Tritt n im Viererquadrat v mindestens zweimal auf ?
\ Funktioniert auch fuer Leerstellen (n=20h)
: 2*INV? ( n v -- )
   INDEX OFF V>QL SWAP 10 * + 4 * MATRIX +
   4 0 DO 2DUP I + C@ = IF 1 INDEX +! THEN LOOP 10 +
   4 0 DO 2DUP I + C@ = IF 1 INDEX +! THEN LOOP 10 +
   4 0 DO 2DUP I + C@ = IF 1 INDEX +! THEN LOOP 10 +
   4 0 DO 2DUP I + C@ = IF 1 INDEX +! THEN LOOP 10 + 2DROP
   INDEX @ 1 > ABORT" Mindestens zweimal!" ;

\ Ist MATRIX zulaessig? Meldung, wenn nicht.
: MOK? ( -- )
   10 0 DO 10 0 DO J I 2*INI? LOOP LOOP
   10 0 DO 10 0 DO J I 2*INJ? LOOP LOOP
   10 0 DO 10 0 DO J I 2*INV? LOOP LOOP ;

\ finis