// VIERTRIS 1.0
//
// Brettspiel für 2 Personen
//
// Peter Buzanits
// Entwickelt mit JDK 1.0.2
//
// Projektbeginn 3.11.1996
// Version 1.0   6.11.1996
//


import java.awt.*;
import java.applet.*;
import java.lang.*;


/**
    shape repräsentiert einen rechteckigen Ausschnitt des Applets
*/

abstract class shape
{
   int höhe, breite;
   punkt ursprung;

   public shape(punkt p, int b, int h)
   {
      höhe = h; breite = b;
      ursprung = p;
   }

   public boolean in(int globX, int globY)
   {
      return globX>=ursprung.x && globX<=ursprung.x+breite-1 &&
             globY>=ursprung.y && globY<=ursprung.y+höhe-1;
   }

   abstract public boolean MausKlick(int globX, int globY);
   abstract public void Paint(Graphics g);
}


/**
     punkt ist ein Punkt im Applet
*/

class punkt
{
   int x,y;

   public punkt(int X, int Y) { x = X; y = Y; }
   public punkt() { x = 0; y = 0; }
}


/**
     spielfeld ist das Spielbrett mit 64 Feldern
*/

class spielfeld extends shape
{
   feld[][] position = new feld[8][8];      // position[zeile][spalte]

   int feldhöhe = höhe / 8;
   int feldbreite = breite / 8;

   int AktuellerSpieler; 
   intanzeige anz1, anz2, ebene;
   coloranzeige nächster;
   Viertris viertris;

   public spielfeld(punkt p, int b, int h)
   {
      super(p, b, h);
      AktuellerSpieler = 1;
   }

   public boolean MausKlick(int globX, int globY)
   {
      int locX = globX - ursprung.x;
      int spalte = locX / feldbreite;

      if (füllstand(spalte) == 8) return false;

      position[füllstand(spalte)][spalte] = new feld(AktuellerSpieler);
      auswertung(1);           // auswertung in 1. Rekursionstiefe
      AktuellerSpieler = (AktuellerSpieler==1 ? 2 : 1);
      nächster.set(AktuellerSpieler==1 ? Color.red : Color.blue);
      return true;
   }

   private int füllstand(int spalte)
   {
      for(int zeile = 7; zeile >= 0; zeile--)
         if (position[zeile][spalte] != null) return zeile+1;
      return 0;
   }

   private void auswertung(int rekursion)
   {
      int WAAGRECHT = 1;
      int SENKRECHT = 2;
      int HAUPTDIAG = 3;
      int NEBENDIAG = 4;

      boolean marked = false;
      int anzahl;

      // Waagrechte Linien

      for(int zeile=0; zeile<8; zeile++)
         for(int spalte=0; spalte<5; spalte++)
         {
            anzahl = zähle(zeile, spalte, WAAGRECHT);
            if (anzahl >= 4)
            {
               for(int i=spalte; i<spalte+anzahl; i++) 
                  position[zeile][i].markiere();

               int gewinner = position[zeile][spalte].besitzer();
               int punkte = (anzahl-2) * rekursion;
               if (gewinner==1) anz1.add(punkte);
                                else anz2.add(punkte);
               if (anzahl > 4) spalte += anzahl-4;

               marked = true;
            }
         }

      // Senkrechte Linien

      for(int spalte=0; spalte<8; spalte++)
         for(int zeile=0; zeile<5; zeile++)
         {
            anzahl = zähle(zeile, spalte, SENKRECHT);
            if (anzahl >= 4)
            {
               for(int i=zeile; i<zeile+anzahl; i++) 
                  position[i][spalte].markiere();

               int gewinner = position[zeile][spalte].besitzer();
               int punkte = (anzahl-2) * rekursion;
               if (gewinner==1) anz1.add(punkte);
                                else anz2.add(punkte);
               if (anzahl > 4) zeile += anzahl-4;

               marked = true;
            }
         }

      // Hauptdiagonale

      for(int zeile=0; zeile<5; zeile++)
         for(int spalte=0; spalte<5; spalte++)
         {
            anzahl = zähle(zeile, spalte, HAUPTDIAG);
            if (anzahl >= 4)
            {
               int z, s;
               for(z=zeile, s=spalte; z<zeile+anzahl && s<spalte+anzahl; z++, s++) 
                  position[z][s].markiere();

               int gewinner = position[zeile][spalte].besitzer();
               int punkte = (anzahl-2) * rekursion;
               if (gewinner==1) anz1.add(punkte);
                                else anz2.add(punkte);
               if (anzahl > 4) {spalte += anzahl-4; zeile += anzahl-4;}

               marked = true;
            }
         }

      // Nebendiagonale

      for(int zeile=0; zeile<5; zeile++)
         for(int spalte=3; spalte<8; spalte++)
         {
            anzahl = zähle(zeile, spalte, NEBENDIAG);
            if (anzahl >= 4)
            {
               int z, s;
               for(z=zeile, s=spalte; z<zeile+anzahl && s>spalte-anzahl; z++, s--) 
                  position[z][s].markiere();

               int gewinner = position[zeile][spalte].besitzer();
               int punkte = (anzahl-2) * rekursion;
               if (gewinner==1) anz1.add(punkte);
                                else anz2.add(punkte);
               if (anzahl > 4) {spalte -= anzahl-4; zeile += anzahl-4;}

               marked = true;
            }
         }

      ebene.set(0);

      if (marked)
      {
         ebene.set(rekursion);
         viertris.Update();
         try{Thread.currentThread().sleep(3000);} catch(InterruptedException e){}
         sinke();
         auswertung(rekursion + 1);
      }
   }

   private int zähle(int zeile, int spalte, int richtung)
   {
      int spieler;
      int ret = 1;
      int z,s;

      try{ spieler = position[zeile][spalte].besitzer(); }
      catch(NullPointerException e) { return 0; }

      switch(richtung){
      case 1: // Waagrecht
         for(s=spalte+1; s<8; s++)
            try{ if (position[zeile][s].besitzer() == spieler) ret++;
                    else return ret; }
            catch(NullPointerException e) { return ret; }
         break;
      case 2: // Senkrecht
         for(z=zeile+1; z<8; z++)
            try{ if (position[z][spalte].besitzer() == spieler) ret++;
                    else return ret; }
            catch(NullPointerException e) { return ret; }
         break;
      case 3: // Hauptdiagonale
         for(s=spalte+1, z=zeile+1; s<8 && z<8; s++, z++)
            try{ if (position[z][s].besitzer() == spieler) ret++;
                    else return ret; }
            catch(NullPointerException e) { return ret; }
         break;
      case 4: // Nebendiagonale
         for(s=spalte-1, z=zeile+1; s>=0 && z<8; s--, z++)
            try{ if (position[z][s].besitzer() == spieler) ret++;
                    else return ret; }
            catch(NullPointerException e) { return ret; }
         break;
      }
      return ret;
   }

   private void sinke()
   {
      for(int spalte=0; spalte<8; spalte++)
      {
         if (position[7][spalte] != null && position[7][spalte].markiert())
            position[7][spalte] = null;

         for(int zeile=6; zeile>=0; zeile--)
            if (position[zeile][spalte] != null && position[zeile][spalte].markiert())
               nachrücken(spalte, zeile);
      }
   }

   private void nachrücken(int spalte, int zeile)
   {
      for(int z=zeile; z<7; z++) position[z][spalte] = position[z+1][spalte];
      position[7][spalte] = null;
   }

   public void Paint(Graphics g)
   {
      g.setColor(Color.black);
      g.drawRect(ursprung.x, ursprung.y, breite-1, höhe-1);

      for(int zeile=0; zeile<8; zeile++)
         for(int spalte=0; spalte<8; spalte++)
            zeichne(g, zeile, spalte);
   }

   private void zeichne(Graphics g, int zeile, int spalte)
   {
      int xoffset = breite / 8;
      int yoffset = höhe / 8;

      g.setColor(Color.black);
      g.drawRect(spalte*xoffset+ursprung.x+2, (7-zeile)*yoffset+ursprung.y+2, 
                 xoffset-3, yoffset-3);

      if (position[zeile][spalte] != null)
      {
         Color farbe = (position[zeile][spalte].besitzer()==1 ? Color.red : Color.blue);
         if(position[zeile][spalte].markiert())
            farbe = (position[zeile][spalte].besitzer()==1 ?
                     new Color(1.0f, 0.6f, 0.6f) : new Color(0.6f, 0.6f, 1.0f));

         g.setColor(farbe);
         g.fillRect(spalte*xoffset+ursprung.x+4, (7-zeile)*yoffset+ursprung.y+4, 
                    xoffset-6, yoffset-6);
      }
   }
}


/**
     feld ist ein besetztes Feld am Spielfeld
*/

class feld
{
   int Spieler;
   boolean Markierung;

   public feld(int s)
   {
      Spieler = s;
      Markierung = false;
   }

   public void markiere() {Markierung = true;}
   public boolean markiert() {return Markierung;}
   public int besitzer() {return Spieler;} 
}


/**
     spielflaeche ist die Fläche des gesamten Spiels
*/

class spielflaeche extends shape
{
   spielfeld brett;
   intanzeige anz1, anz2, ebene;
   int brettseite;
   punkt bursprung;
   coloranzeige nächster;

   public spielflaeche(punkt p, int b, int h)
   {
      super(p, b, h);
      
      brettseite = Math.min(breite, höhe-30);
      bursprung = new punkt((breite-brettseite)/2,10);
      brett = new spielfeld(bursprung, brettseite, brettseite);
      anz1 = new intanzeige(new punkt(20, höhe-25), 35, 20, "Sp 1");        // Punkte Spieler1
      anz2 = new intanzeige(new punkt(breite-50, höhe-25), 35, 20, "Sp 2"); // Punkte Spieler2
      nächster = new coloranzeige(new punkt(20,höhe/2), 30, 20, "next");    // Wer ist dran?
      nächster.set(Color.red);
      ebene = new intanzeige(new punkt(breite-50, höhe/2), 30, 20, "step"); // Welche Rekusionsebene?

      brett.anz1 = anz1; brett.anz2 = anz2; brett.nächster = nächster; brett.ebene = ebene;
   }

   public boolean MausKlick(int globX, int globY)
   {
      if (brett.in(globX, globY)) return brett.MausKlick(globX, globY); else return false;
   }

   public void Paint(Graphics g)
   {
      g.setColor(Color.white);
      g.fillRect(ursprung.x, ursprung.y, breite, höhe);

      brett.Paint(g);
      anz1.Paint(g); anz2.Paint(g); nächster.Paint(g); ebene.Paint(g);
   }
}


/**
     Anzeige von diversen Informationen im Applet
*/

abstract class anzeige extends shape
{
   String label;

   public anzeige(punkt p, int b, int h, String l)
   {
      super(p, b, h);
      label = l;
   }

   public boolean MausKlick(int globX, int globY) { return false; }

   public void Paint(Graphics g)
   {
      g.setColor(Color.black);
      g.drawRect(ursprung.x, ursprung.y, breite, höhe);
      g.drawString(label, ursprung.x+1, ursprung.y-3);
   }
}

class intanzeige extends anzeige
{
   int wert;

   public intanzeige(punkt p, int b, int h, String l)
   {
      super(p, b, h, l);
      wert = 0;
   }

   public void add(int i) { wert += i; }
   public void set(int i) { wert = i; }

   public void Paint(Graphics g)
   {
      String w = Integer.toString(wert);

      super.Paint(g);
      g.drawString(w, ursprung.x+10, ursprung.y+15);
   }
}

class coloranzeige extends anzeige
{
   Color wert;

   public coloranzeige(punkt p, int b, int h, String l)
   {
      super(p, b, h, l);
      wert = Color.white;
   }

   public void set(Color c) { wert = c; }

   public void Paint(Graphics g)
   {
      super.Paint(g);
      g.setColor(wert);
      g.fillRect(ursprung.x+2, ursprung.y+2, breite-3, höhe-3);
   }
}

/**
     Applet
*/

public class Viertris extends Applet
{
   spielflaeche Spiel;
   //String debuginfo;
   
   public Viertris() { super(); }

   public void init()
   {
      Dimension d = size();
      Spiel = new spielflaeche(new punkt(0,0), d.width, d.height);
      Spiel.brett.viertris = this;
   }

   public boolean mouseUp(Event e, int x, int y)
   {
      if (Spiel.MausKlick(x, y)) repaint();
      return false;
   }

   public void Update() { update(getGraphics()); }

   public void paint(Graphics g) { Spiel.Paint(g); }
}
