Benutzer-Werkzeuge

Webseiten-Werkzeuge


api:projects:minesweeper:spielfeld:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.


api:projects:minesweeper:spielfeld:start [2024/08/31 10:03] (aktuell) – angelegt - Externe Bearbeitung 127.0.0.1
Zeile 1: Zeile 1:
 +====== Projekt Minesweeper: Die Klasse Spielfeld ======
 +[[../start|Zurück zur Hauptseite des Projekts Minesweeper]] \\ \\ 
  
 +Ein Objekt der Klasse Spielfeld enthält viele Objekte der Klasse Zelle und stellt damit das gesamte Spielfeld im Grafikbereich dar. Starte das Programm unten, decke mit der Maus verschiedene Zellen auf und entdecke - ausgehend von der Methode ''Zelle.onMouseUp'', welche Programmanweisungen nach dem Loslassen der Maustaste über einer Zelle ausgeführt werden.
 +
 +<HTML>
 +<div class="java-online" style="height: 620px; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Zelle'}">
 +<script type="text/plain" title="Spielfeld.java">
 +Spielfeld sp = new Spielfeld(10, 15, 20);
 +sp.init();
 +
 +while(true);  // Endlos-Wiederholung, damit weiter Mausereignisse entgegengenommen werden
 +
 +/**
 + * Ein Objekt der Klasse Spielfeld enthält und verwaltet alle Zellen.
 + */
 +class Spielfeld {
 +   
 +   private Zelle[][] zellen;    // Erste Koordinate: Spalte (x), zweite Koordinate: Zeilen (y)
 +   private int spalten;         // Anzahl der Spalten des Spielfelds
 +   private int zeilen;          // Anzahl der Zeilen des Spielfelds
 +   private int minenAnzahl;     // Anzahl der vesteckten Minen
 +
 +   Spielfeld(int spalten, int zeilen, int minenAnzahl) {
 +      this.spalten = spalten;
 +      this.zeilen = zeilen;
 +      this.minenAnzahl = minenAnzahl;
 +      zellen = new Zelle[spalten][zeilen];
 +   }
 +
 +   /**
 +    * Instanziere alle Zellen und "verstecke" dabei die Minen
 +    */
 +   public void init() {
 +      // Erzeuge zunächst Zellen ohne Minen.
 +      for(int spalte = 0; spalte < spalten; spalte++) {
 +         for(int zeile = 0; zeile < zeilen; zeile++) {
 +            
 +            zellen[spalte][zeile] = new Zelle(this, ZellBild.hintergrund_leer, spalte, zeile);
 +
 +         }
 +      }
 +
 +      // "Verstecke" die Minen
 +      for(int i = 0; i < minenAnzahl; i++) {
 +         boolean fertig = false;
 +         while(!fertig) {
 +            int spalte = Math.floor(Math.random() * spalten);
 +            int zeile = Math.floor(Math.random() * zeilen);
 +            Zelle zelle = zellen[spalte][zeile];
 +            if(zelle.getInhalt() != ZellBild.mine) {
 +               zelle.setZustand(ZellBild.mine, true, false);
 +               fertig = true;
 +            }
 +         
 +      }
 +
 +
 +      // Zähle für jede nicht-Minen-Zelle die Nachbarminen und stelle die 
 +      // Anzahl als Zahlengrafik dar.
 +      for(int spalte = 0; spalte < spalten; spalte++) {
 +         for(int zeile = 0; zeile < zeilen; zeile++) {
 +            
 +            Zelle zelle = zellen[spalte][zeile];
 +            if(zelle.getInhalt() == ZellBild.hintergrund_leer) {
 +               int nachbarbomben = zähleNachbarMinen(zelle);
 +               if(nachbarbomben > 0) {
 +                  zelle.setZustand(ZellBild.zahl_0 + nachbarbomben, true, false);
 +               }
 +            }
 +
 +         }
 +      }
 +   }
 +
 +   public int getMinenAnzahl() {
 +      return minenAnzahl;
 +   }
 +
 +   private int zähleNachbarMinen(Zelle zelle) {
 +      int nachbarMinen = 0;
 +      for(int dx = -1; dx <= 1; dx++) {
 +         for(int dy = -1; dy <= 1; dy++) {
 +            if(dx != 0 || dy != 0) {
 +               int spalte = zelle.getSpalte() + dx;
 +               int zeile = zelle.getZeile() + dy;
 +               if(spalte >= 0 && spalte < spalten && zeile >= 0 && zeile < zeilen) {
 +                  if(zellen[spalte][zeile].getInhalt() == ZellBild.mine) {
 +                     nachbarMinen++;
 +                  };
 +               }
 +            }
 +         }
 +      }
 +      return nachbarMinen;
 +   }
 +
 +   /**
 +    * Zerstört alle Zellen des Spielfelds
 +    */
 +   public void löschen() {
 +      for(int spalte = 0; spalte < spalten; spalte++) {
 +         for(int zeile = 0; zeile < zeilen; zeile++) {
 +
 +            zellen[spalte][zeile].destroy();
 +            zellen[spalte][zeile] = null;
 +
 +         }
 +      }
 +   }
 +
 +   /**
 +    * Berechnet die x-Koordinate des Pixels am linken Rand der übergebenen Spalte.
 +    */
 +   public double spalteToX(int spalte) {
 +      return 21 + 32 * spalte;
 +   }
 +
 +   /**
 +    * Berechnet die y-Koordinate des Pixels am oberen Rand der übergebenen Zeile.
 +    */
 +   public double zeileToY(int zeile) {
 +      return 116 + 32 * zeile;
 +   }
 +
 +   /**
 +    * Wird von Zelle.onMouseUp aufgerufen und deckt die Zelle auf. 
 +    * Enthält sie keine Mine und enthalten auch die Nachbarzellen keine Minen, so werden
 +    * rekursiv alle benachbarten Zellen aufgedeckt, die ebenfalls keine Minen enthalten 
 +    * und deren Nachbarzellen ebenfalls keine Minen enthalten. 
 +    */
 +   public void klickAufZelle(Zelle zelle) {
 +      zelle.aufdecken();
 +      if(zelle.getInhalt() == ZellBild.hintergrund_leer) {
 +         // Falls weder die Zelle noch die Nachbarzellen Minen enthalten,
 +         // dann untersuche die acht benachbarten Zellen:
 +         for(int dx = -1; dx <= 1; dx++) {
 +            for(int dy = -1; dy <= 1; dy++) {
 +               if(dx != 0 || dy != 0) {
 +                  int spalte = zelle.getSpalte() + dx;
 +                  int zeile = zelle.getZeile() + dy;
 +                  if(spalte >= 0 && spalte < spalten && zeile >= 0 && zeile < zeilen) {
 +                     // Hole das benachbarte Zellen-Objekt
 +                     Zelle zelle = zellen[spalte][zeile];
 +                     if(zelle.istZugedeckt()) { 
 +                        klickAufZelle(zelle);
 +                     }
 +                  }
 +               }
 +            }
 +         }
 +      }
 +   }
 +
 +   /**
 +    * Fürs Intro: Zufällige Zelle öffnen
 +    */
 +   public void zufälligeZelleKlicken() {
 +      int spalte = Math.floor(Math.random() * spalten);
 +      int zeile = Math.floor(Math.random() * zeilen);
 +      klickAufZelle(zellen[spalte][zeile]);
 +   }
 +
 +   /**
 +    * Markiere die Zelle mit einer Fahne
 +    */
 +   public void setFahne(Zelle zelle) {
 +         zelle.setZustand(zelle.getInhalt(), true, true);
 +   }
 +
 +   /**
 +    * Entferne die Fahnen-Markierung der Zelle
 +    */
 +   public void löscheFahne(Zelle zelle) {
 +      zelle.setZustand(zelle.getInhalt(), true, false);
 +   }
 +
 +   /**
 +    * Nachdem das Spiel verloren ist, werden alle Zellen aufgedeckt.
 +    */
 +   public void allesAufdecken() {
 +      for(int spalte = 0; spalte < spalten; spalte++) {
 +         for(int zeile = 0; zeile < zeilen; zeile++) {
 +            
 +            Zelle zelle = zellen[spalte][zeile];
 +            if(zelle.istZugedeckt()) {
 +               if(zelle.hatFahne()) {
 +                  if(zelle.getInhalt() == ZellBild.mine) {
 +                     zelle.setZustand(ZellBild.mine_entschärft, false, false);
 +                  } else {
 +                     zelle.setZustand(ZellBild.hintergrund_leer, false, false);
 +                  }
 +               } else {
 +                  zelle.aufdecken();
 +               }
 +            }
 +
 +         }
 +      }
 +
 +   }
 +
 +   /**
 +    * Gibt genau dann true zurück, wenn alle Minen markiert und alle anderen
 +    * Zellen aufgedeckt sind.
 +    */
 +   public boolean alleAufgedeckt() {
 +      for(int spalte = 0; spalte < spalten; spalte++) {
 +         for(int zeile = 0; zeile < zeilen; zeile++) { 
 +            Zelle zelle = zellen[spalte][zeile];
 +            if(zelle.istZugedeckt() && !zelle.hatFahne()) return false;
 +         }
 +      } 
 +      return true;
 +   }
 +
 +}</script>
 +
 +<script type="text/plain" title="Zelle.java">
 +// Indizes der Sprites für die verschiedenen Zellbilder
 +class ZellBild {
 +   static int mine = 0;
 +   static int mine_entschärft = 1;
 +   static int mine_explodiert = 2; 
 +   static int fahne = 3;
 +   static int zahl_0 = 5;
 +   static int zahl_8 = 13;
 +   static int hintergrund_leer = 15;
 +   static int zugedeckt = 16;
 +}
 +
 +/**
 + * Die Klasse Zelle repräsentiert eine quadratische Zelle des Spielfeldes. Sie wird mithilfe von 
 + * zwei Sprites gezeichnet: dem Hintergrund (Zell-Objekt ist selbst ein Sprite) und dem Vordergrund 
 + * (gleichnamiges Attribut).
 + */
 +class Zelle extends Sprite {
 +   
 +   private int inhalt;          // Sprite-Index des Zell-Bildes, siehe Klasse ZellBild
 +
 +   private boolean zugedeckt;   // == true, solange die Zelle noch nicht aufgedeckt ist
 +   private boolean fahne;       // == true, falls die Zelle mit einer Fahne markiert ist
 +
 +   private Sprite vordergrund;
 +
 +   // Jede Zelle "kennt" das Spielfeld, auf dem sie platziert ist, und kann damit dessen
 +   // öffentliche Methoden aufrufen.
 +   private Spielfeld spielfeld;
 +
 +   private int spalte;          // Position der Zelle auf dem Spielfeld
 +   private int zeile;
 +
 +   Zelle(Spielfeld spielfeld, int zustand, int spalte, int zeile) {
 +      super(spielfeld.spalteToX(spalte), spielfeld.zeileToY(zeile), SpriteLibrary.Minesweeper, ZellBild.hintergrund_leer, ScaleMode.nearest_neighbour);
 +      vordergrund = new Sprite(spielfeld.spalteToX(spalte), spielfeld.zeileToY(zeile), SpriteLibrary.Minesweeper, ZellBild.zugedeckt, ScaleMode.nearest_neighbour);
 +      this.spielfeld = spielfeld;
 +      this.spalte = spalte;
 +      this.zeile = zeile;
 +      setZustand(zustand, true, false);
 +   }
 +
 +   public int getInhalt() {
 +      return inhalt;
 +   }
 +
 +   public int getZeile() {
 +      return zeile;
 +   }
 +
 +   public int getSpalte() {
 +      return spalte;
 +   }
 +
 +   public boolean istZugedeckt() {
 +      return zugedeckt;
 +   }
 +
 +   public boolean hatFahne() {
 +      return fahne;
 +   }
 +
 +   /**
 +    * Ändert sich der Zustand der Zelle, so sorgt die Methode setZustand dafür,
 +    * dass die Bilder der Sprites entsprechend gesetzt werden.
 +    */
 +   public void setZustand(int inhalt, boolean zugedeckt, boolean fahne) {
 +      if(zugedeckt) {
 +         if(fahne) {
 +            vordergrund.setImageIndex(ZellBild.fahne);
 +         } else {
 +            vordergrund.setImageIndex(ZellBild.zugedeckt);
 +         }
 +      } else {
 +         vordergrund.setImageIndex(inhalt);
 +      }
 +      this.zugedeckt = zugedeckt;
 +      this.fahne = fahne;
 +      this.inhalt = inhalt;
 +   }
 +
 +   public void destroy() {
 +      super.destroy();
 +      vordergrund.destroy();
 +   }
 +
 +   /**
 +    * Wird vom Browser aufgerufen, wenn der Mauszeiger sich von außen in die Zelle hineinbewegt
 +    */
 +   public void onMouseEnter(double x, double y) {
 +      if(zugedeckt) {
 +         vordergrund.tint("#ff8080");
 +         getWorld().setCursor("pointer");
 +      }
 +   }
 +
 +   /**
 +    * Wird vom Browser aufgerufen, wenn der Mauszeiger sich aus der Zelle
 +    * hinausbewegt.
 +    */
 +   public void onMouseLeave(double x, double y) {
 +      vordergrund.tint("#ffffff"); 
 +      getWorld().setCursor("default");
 +   }
 +   
 +   /**
 +    * Wird vom Browser aufgerufen, wenn eine der Maustasten nach unten gedrückt wird.
 +    */
 +   public void onMouseDown(double x, double y, int key) {
 +      vordergrund.tint("#ff0000");
 +   }
 +
 +   /**
 +    * Wird vom Browser aufgerufen, wenn eine der Maustasten losgelassen wird.
 +    */
 +   public void onMouseUp(double x, double y, int key) {
 +
 +      if(key == 0) {  // linke Maustaste, also aufdecken
 +         if(fahne) return; 
 +         // Mine erwischt?
 +         if(inhalt == ZellBild.mine) {
 +            inhalt = ZellBild.mine_explodiert;
 +            setZustand(inhalt, false, false);
 +            return;
 +         }
 +         spielfeld.klickAufZelle(this); 
 +      } else {
 +         // Rechte Maustaste => Fahne setzen oder löschen
 +         if(zugedeckt) {
 +            if(!fahne) {
 +               spielfeld.setFahne(this);
 +            } else {
 +               spielfeld.löscheFahne(this);
 +            }
 +         }
 +      }
 +         
 +   }
 +
 +   public void aufdecken() {
 +      setZustand(inhalt, false, false);
 +   }
 +
 +}
 +</script>
 +</div>
 +</HTML>
api/projects/minesweeper/spielfeld/start.txt · Zuletzt geändert: 2024/08/31 10:03 von 127.0.0.1