%include "parameter" || parameter.m

|| Stein und Spielfeld sind jeweils rechteckige Strukturen 
|| aus Zellen. In den unteren Funktionen ist die erste Zellstruktur
|| das Spielfeld, die zweite der Stein inklusive relativer Koordinaten.
|| 
|| Dieser Abschnitt erscheint mir Software-technisch nicht so toll (WAM),
|| aber ich war im ersten/zweiten Semester...


koordinaten == (num,num)
|| Koordinaten z.B. eines Steins: oben links: (0,0)

tmaske   == [char]
|| 0 = Leer, 1 = Voll,  Rest wird ignoriert



abstype tzellen with 

|| Erzeugungsfunktion: Maske ist Liste von '0'/'1', sonstige 
|| Zeichen werden ignoriert, es wird mit Leerzeichen aufgefuellt 
|| bzw. abgeschnitten, falls Hoehe und Breite nicht stimmen

  neuezellen     :: (tbreite,thoehe,tmaske)            -> tzellen
  

|| Prueft, ob bei 2 Strukturen volle Zellen uebereinander liegen

  kollisionsfrei :: tzellen -> koordinaten -> tzellen -> bool


|| Bildschirm und Stein werden uebereinandergelegt und ausgegeben

  ausgabe        :: tzellen -> koordinaten -> tzellen -> [char]


|| Bildschirm und Stein werden vereinigt

  vereinigung    :: tzellen -> koordinaten -> tzellen -> tzellen
  zeilenloeschen :: tzellen                           -> tzellen



|| -----------------------------------------
|| Achtung! Implementation!


|| Diese Implementation implementiert eine Struktur als Tupel
|| (Breite, Hoehe, [Voll | Leer]
|| Dass jede Struktur nur 1 Liste ist, fuehrt zu ziemlich 
|| fiesen Funktionen weiter unten. 

|| Besser waere wohl eine Liste pro Zeile gewesen, also 
|| [ [Voll|Leer] ]  . Will's jemand umschreiben?



|| Typdefinition
tzellen ==  (tbreite,thoehe,[tzelle])
|| rechteckige Struktur, z.B Spielfeld


tbreite ==  num
|| breite der struktur


thoehe  ==  num
|| hoehe der struktur 


tzelle  ::= Leer | Voll
|| jede Zelle der Struktur kann belegt oder nicht belegt sein






|| Aus Angaben ueber die Breite und Hoehe und mit
|| einer Maske wird eine neue Zellstruktur erzeugt:

neuezellen (breit,hoch,maske) 
= (breit, hoch, neuezellen2 (breit*hoch) maske)

  where 

  neuezellen2 0       maske 
  = []

  neuezellen2 zaehler []    
  = rep zaehler Leer

  neuezellen2 zaehler maske 
  = Voll : (neuezellen2 (zaehler-1) (tl maske)), 
    if hd maske = '1'

  neuezellen2 zaehler maske 
  = Leer : (neuezellen2 (zaehler-1) (tl maske)), 
    if hd maske = '0'

  neuezellen2 zaehler maske 
  = neuezellen2 zaehler (tl maske), 
    otherwise





|| Bildschirmausgabe der Ueberlagerung eines Spielfeldes
|| mit einem Stein:

ausgabe bild koordinaten stein
= randli ++ oben bild koordinaten stein

||= seq (force bildschirm) (randli ++ bildschirm)

  where

  || Linker Rand:
  || Der Bildschirm wird (hoffentlich) geloescht (bei manchen 
  || Verbindungen klappt dies nicht), und zwar mit dem
  || Kommando '\f' (Seitenvorschub, das ausgegeben wird.
  || Weiter wird der Bildschirm eingerueckt (siehe parameter.m).
  
  randli 
  = '\f':(spaces randlinks)


  || nur ein alias 
  ||bildschirm
  ||= oben bild koordinaten stein


  || Oben herausragende Bereiche des Steins werden abgeschnitten
  oben bild (x,y) (brstein,hostein,stein) 
  = links bild x 0 brstein (hostein+y) (drop ((-y)*brstein) stein),
    if y<0
  = links bild x y brstein hostein stein,
    if y>=0


  || Links herausragende Bereiche des Steins werden abgeschnitten
  links bild x y brstein hostein stein
  = rechts bild 0 y (brstein+x) (-x) hostein (drop (-x) stein),
    if x<0
  = rechts bild x y brstein 0 hostein stein,
    if x>=0
 

  || Rechts herausragende Bereiche des Steins werden abgeschnitten
  rechts (brbild,hobild,bild) x y innen aussen hostein stein
  = ausdruck 0 brbild bild x y (innen-ueber) (aussen+ueber) hostein stein,
    if ueber >0
  = ausdruck 0 brbild bild x y innen aussen hostein stein,
    if ueber <=0

    where 
    
    ueber 
    = x+innen-brbild    


  || Hintergrund und Steinrest werden ausgegeben, 
  || jeweils 1 Zeichen, dann wird geguckt, ob der rechte Rand des
  || Bildes erreicht wird


  ausdruck i brbild bild x y in aus hostein stein
  = ['\n'],
    if bild = []
  = '[':']':rand (i+1) brbild (tl bild) x y in aus hostein (tl stein),
    if imbereich & gefuellt
  = ' ':' ':rand (i+1) brbild (tl bild) x y in aus hostein (tl stein),
    if imbereich
  = '[':']':rand (i+1) brbild (tl bild) x y in aus hostein stein,
    if (hd bild = Voll)
  = ' ':' ':rand (i+1) brbild (tl bild) x y in aus hostein stein,
    if (hd bild = Leer)

    where 

    imbereich
    = (spalte>=x) & (spalte=y) & (zeile y) & ((j div brbild) < (y + hostein))
          



|| Ein Stein und das Spielfeld werden vereinigt.
|| Falls dadurch vollstaendig gefuellte Zeilen entstehen, werden diese 
|| geloescht (ausgenommen der untersten Zeile, dem Boden).


vereinigung bild koordinaten stein
= zeilenloeschen (xbild bild, ybild bild, oben bild koordinaten stein)

|| Zur Erklaerung dieses schlechten Codes:
|| Eigentlich steht da
|| oben(links(rechts(vereinigen bild, koordinaten stein))) 

|| Also werden zuerst (mal wieder) oben, links, rechts ueberstehende 
|| Stuecke vom Stein abgeschnitten, und dann Bild und Stein vereinigt.

|| Auf da Ergebnis wird dann zeilenloeschen angewandt.
|| Viel Spass.


  where

  xbild (x,y,bild) 
  = x

  ybild (x,y,bild)
  = y


  || Oben herausragende Bereiche des Steins werden abgeschnitten
  oben bild (x,y) (brstein,hostein,stein) 
  = links bild x 0 brstein (hostein+y) (drop ((-y)*brstein) stein),
    if y<0
  = links bild x y brstein hostein stein,
    if y>=0


  || Links herausragende Bereiche des Steins werden abgeschnitten
  links bild x y brstein hostein stein
  = rechts bild 0 y (brstein+x) (-x) hostein (drop (-x) stein),
    if x<0
  = rechts bild x y brstein 0 hostein stein,
    if x>=0
 

  || Rechts herausragende Bereiche des Steins werden abgeschnitten
  rechts (brbild,hobild,bild) x y innen aussen hostein stein
  = vereinigen 0 brbild bild x y (innen-ueber) (aussen+ueber) hostein stein,
    if ueber >0
  = vereinigen 0 brbild bild x y innen aussen hostein stein,
    if ueber <=0

    where 
    
    ueber 
    = x+innen-brbild    


  || Bildschirm und Steinrest werden vereinigt
  vereinigen i brbild bild x y in aus hostein stein
  = [],
    if bild = []
  = Voll:rand (i+1) brbild (tl bild) x y in aus hostein (tl stein),
    if imbereich & gefuellt
  = Leer:rand (i+1) brbild (tl bild) x y in aus hostein (tl stein),
    if imbereich
  = Voll:rand (i+1) brbild (tl bild) x y in aus hostein stein,
    if (hd bild = Voll)
  = Leer:rand (i+1) brbild (tl bild) x y in aus hostein stein,
    if (hd bild = Leer)

    where 

    imbereich
    = (spalte>=x) & (spalte=y) & (zeile y) & ((j div brbild) < (y + hostein))
  



|| Volle Zeilen, werden geloescht, wenn es sich nicht um die 
|| letzte Zeile (den Boden) handelt
  
zeilenloeschen (x,y,bild)
= (x,y,loeschen x y bild [] 0)
   
loeschen breite hoehe bild bildneu geloescht
= leerzeilen breite (bildneu++bild) geloescht, if hoehe = 1
= loeschen breite (hoehe-1) (drop breite bild) bildneu (geloescht+1), 
  if (voll zeile)
= loeschen breite (hoehe-1) (drop breite bild) (bildneu++zeile) geloescht,
  if ~(voll zeile)
    
  where 
  zeile        = take breite bild
  
  voll [] = True
  voll z  = voll (tl z), if (hd z = Voll)
  voll z  = False, if (hd z = Leer)
    
leerzeilen breite bild 0 
= bild
leerzeilen breite bild geloescht
= leerzeilen breite (leerzeile++bild) (geloescht-1)
  where
  leerzeile = Voll : (rep (breite-2) Leer) ++ [Voll]



|| Prueft, ob Stein und Bildschirm Kollisionen haben,
|| Zwei volle Zellen also uebereinanderliegen
|| Noch dabei? Den Codeaufbau muessten Sie jetzt kennen...


kollisionsfrei (brbild,hobild,bild) (x,y) (brstein,hostein,stein)
= oben brbild hobild bild x y brstein hostein stein brstein

  where

  ||1. ragt Stein oben heraus?  

  oben brbild hobild bild x y brstein hostein stein brschnitt
  = unten brbild hobild bild x 0 brstein (hostein+y) unterteil brschnitt,
    if y<0
  = unten brbild hobild bild x y brstein hostein stein brschnitt, 
    if y>=0

    where

    unterteil 
    = drop ((-y)*brstein) stein

  ||2. ragt Stein unten heraus?

  unten brbild hobild bild x y brstein hostein stein brschnitt
  = links brbild hobild bild x y brstein (hobild-y) stein brschnitt,
    if (y+hostein)>hobild
  = links brbild hobild bild x y brstein hostein stein brschnitt,
    if (y+hostein)<=hobild


  ||3. ragt Stein links heraus?

  links brbild hobild bild x y brstein hostein stein brschnitt
  = rechts brbild hobild bild 0 y brstein hostein rechtsteil (brstein+x),
    if x<0

  = rechts brbild hobild bild x y brstein hostein stein brschnitt,
    if x>=0   

    where 

    rechtsteil = drop (-x) stein
	
  ||4. ragt Stein rechts heraus?

  rechts brbild hobild bild x y brstein hostein stein brschnitt
  = vergleich hostein brbild bildrest brstein stein (brbild-x),
    if (x+brschnitt)>brbild
  = vergleich hostein brbild bildrest brstein stein brschnitt,
    if (x+brschnitt)<=brbild
	
    where

    bildrest 
    = drop (brbild*y+x) bild
  
  ||5. Vergleich

  vergleich zaehler brbild bild brstein stein brschnitt
  = kofrei (take brschnitt bild) (take brschnitt stein),
    if zaehler=1
  = vergleich (zaehler-1) brbild restbild brstein reststein brschnitt,
    if kofrei (take brschnitt bild) (take brschnitt stein)
  = False, 
    otherwise

    where

    restbild 
    = drop brbild bild

    reststein 
    = drop brstein stein

  kofrei [] []     
  = True
  kofrei (x:xx) (y:yy) 
  = False, 
    if ((x=Voll) & (y=Voll))
  = kofrei xx yy, 
    otherwise