|| In zustand.m wird der Zustand des Tetris-Spiels geaendert.
|| Der Zustand umfasst die Daten des Spiels (wie liegen die Steine) 
|| ebenso wie Verwaltungsdaten


%include "parameter" || parameter.m
||hoehe, breite : Spielfeldgroesse
||tempo         : Spielgeschwindigkeit
||drehen, 
||rechts, links : Tasten zum bewegen der Steine

%include "eingabe"   || eingabe.m
||zeichen : erstes Zeichen des Eingabestreams
||rest    : der Rest des Streams ab dem Return

%include "zellen"    || zellen.m
||

%include "stein"     || stein.m
||neuerstein : num->stein

||-----
|| Der Zustand ist ADT:

abstype tzustand with

  startzustand :: num->tzustand   
    || Leerer Schirm, zufaelliger 1ter Stein (gemaess num)

  neuerzustand :: tzustand->teinzeichen->tzustand
    || Ein Zustand wird geaendert

  geaendert    :: tzustand->bool
    || Ist der Zustand geaendert?

  ende         :: tzustand->bool
    || Ist der Zust. Endzustand (Spielende)

  ausgeben     :: tzustand->[char]
    || Zustand wird in ASC gewandelt

  zufallszahl  :: tzustand->num        
    || Aus dem Zustand wird der Wert der aktuellen Zufallszahl extrahiert    




tzustand          == (tverwaltungsdaten, tspieldaten, taenderung)

tverwaltungsdaten == (tspielende,tcountdown, tzufallszahl)
tspielende        == bool
tcountdown        == num
tzufallszahl      == num

tspieldaten       == (tbildschirm, tspielstein)
tbildschirm       == tzellen
tspielstein       == tstein

taenderung        == bool  
|| Steht nicht mit bei den Verwaltungsdaten, da diese Flag haeufig
|| gebraucht wird und so der Zugriff weniger umstaendlich ist.




|| Der Startzustand wird berechnet, die Folge der Zufallszahlen 
|| wird mit zeit initiallisiert
startzustand zeit 
= ((False,0,zufall zeit), (startbild,neuerstein (zufall zeit)),True)
  
  where 

  startbild 
  = neuezellen (breite, hoehe, (maskestart breite hoehe))
  || neuezellen aus dem Modul zellen.m bekommt eine Maske und
  || erzeugt eine entsprechende Zellstruktur   


  maskestart breite hoehe 
  = rep breite '1',
    if hoehe =1
  = '1':(rep (breite-2) '0')++"1"++ maskestart breite (hoehe-1),
    otherwise
  


|| Der Zustand wird geaendert:
|| Zuerst werden die Aktionen des Spielers abgearbeitet,
|| dann faellt der Stein, falls wieder eine bestimmte Zeit verstrichen ist

neuerzustand zustand eingabe 
= absinken (steuern zustand eingabe)

  where

  steuern (verwaltungsdaten,(bildschirm,stein),aenderung) eingabe

  || wenn Drehung gewuenscht und kollisionsfrei: 
  || Stein drehen

  = (verwaltungsdaten,(bildschirm,(steindrehen stein)), True),
    if (eingabe = d) & (kollisionsfrei bildschirm (gibkoordinaten (steindrehen stein)) (steinstruktur (steindrehen stein)))

  || wenn Bewegung nach rechts gewuenscht und kollisionsfrei: 
  || Stein nach rechts
  
  = (verwaltungsdaten,(bildschirm,(steinrechts stein)), True),
    if (eingabe = r) & (kollisionsfrei bildschirm (gibkoordinaten (steinrechts stein)) (steinstruktur (steinlinks stein)))

  || wenn Bewegung nach links gewuenscht und kollisionsfrei : Stein nach links
  
  = (verwaltungsdaten,(bildschirm,(steinlinks stein)), True), 
    if (eingabe = l) & (kollisionsfrei bildschirm (gibkoordinaten (steinlinks stein)) (steinstruktur (steinlinks stein)))

  || 
  = (verwaltungsdaten, (bildschirm,stein),False),
    if (eingabe = 'O') & (system "oberon")=("","",0) 

  || sonst keine Steinbewegung
  
  = (verwaltungsdaten,(bildschirm,stein),False), 
    otherwise

  d = drehung
  r = rechts
  l = links


  absinken ((ende,countdown,zufi),(bild,stein),aenderung)
  = ((ende,countdown+1,zufi),(bild,stein),aenderung),
    if countdown < tempo  
    || Zeitpunkt zum absinken ist noch nicht gekommen

  = ((ende,0,zufi),(bild,steinunten stein),True),
    if (countdown = tempo) & (kollisionsfrei bild (gibkoordinaten (steinunten stein)) (steinstruktur (steinunten stein)))
    || abgesunken

  = ((ende,0,zufall zufi),(vereinigung bild (gibkoordinaten stein) (steinstruktur stein),steinneu),True),
    if (kollisionsfrei bild (gibkoordinaten steinneu) (steinstruktur steinneu)) 
    || unten angekommen: Neuer Stein
    
  = ((True,0,zufall zufi),(vereinigung bild (gibkoordinaten stein) (steinstruktur stein),steinneu),False),
    || Neuer Stein passt nicht mehr: Ende.
 
    otherwise

    where 
    steinneu = neuerstein (zufall zufi)


|| Abfragen
ende ((end,countdown,zufi),(spieldaten),aenderung)
= end

geaendert (verwaltung,spiel,aenderung)
= aenderung


zufallszahl ((end,count,zufi),spiel,aend)
= zufi


zufall :: num ->num
zufall x = ((x*547334)+11939) mod 5424563



|| Ausgabe wird von zellen.m erzeugt
ausgeben (verw,(bild,stein),aenderung)
= ausgabe bild (gibkoordinaten stein) (steinstruktur stein)