Finde den fehler nicht

Status
Nicht offen für weitere Antworten.

Unkownsyntax

Bekanntes Mitglied
Code:
  public class Main {

	static final int MINE = 99;

	public static void main(String[] args) {

		boolean[][] field;

		// solange man spielen will
		do {
			// S1) Einlesen der Feldgroesse
			int w = readFieldWidth();
			int h = readFieldHeight();

			// S2) Einlesen der Bombenwahrscheinlichkeit
			double prob = readBombProb();

			// S3) Erstellen eines entsprechenden Feldes
			field = createField(w, h, prob);

			// Testausgabe
			printFieldForTesting(field);

			// S4) Spielen des Spieles
			boolean won = play(field);

			if (won) {
				IO.writeLn("Gratuliere ! Gewonnen");
			} else {
				IO.writeLn("Beng!!! Leider im Kampf gefallen!");
			}

			// S5) Fragen ob noch einmal gespielt werden soll.
		} while (playAgain());
	}

	static void printFieldForTesting(boolean[][] f) {

		IO.writeLn();
		for (int i = 0; i < f.length; i++) {
			for (int j = 0; j < f[i].length; j++) {
				if (f[i][j]) {
					IO.write(" * ");
				} else {
					IO.write(" - ");
				}
			}
			IO.writeLn();
		}
		IO.writeLn();
	}

	static int readFieldWidth() {
		IO.write("Feldbreite: ");
		return IO.readInt();
	}

	static int readFieldHeight() {
		IO.write("Feldhoehe: ");
		return IO.readInt();
	}

	static double readBombProb() {
		IO.write("Wahrscheinlichkeit fuer Mine: ");
		return IO.readDouble();
	}

	static boolean[][] createField(int w, int h, double prob) {
		boolean[][] f = new  boolean[h][w];
		for (int i = 0; i < f.length; i++) {
			for (int j = 0; j < f[i].length; j++) {
				f[i][j] = Math.random() < prob;
			}
		}
		return f;
	}

	static boolean playAgain() {
		IO.writeLn();
		IO.writeLn("Wollen Sie es nochmals versuchen (j|n)?");
                
		return IO.read() == 'j';
	}

	static boolean play(boolean[][] field) {
		int[][] uncovered;
		uncovered = createUncovered(field.length, field[0].length);
		int row, col;
		boolean dead = false;
		// Ausgeben der aufgedeckten Felder
		print(uncovered);
		do {

			// Einlesen des nächsten Feldes das aufgedeckt werden soll
			IO.write("Zeile: ");
			row = IO.readInt();
			IO.write("Spalte: ");
			col = IO.readInt();

			// Aufdecken: entweder Mine erwischt oder Anzahl der nachbarminen anzeigen
			dead = uncover(row, col, field, uncovered);
			// Ausgeben der aufgedeckten Felder
			print(uncovered);

		//solange bis alle nicht-Minen aufgedeckt oder !field[row][col])
		} while (! allUncovered(uncovered, field) && ! dead);

		// return won
		return ! dead;

	}

	static boolean uncover(int r, int c, boolean[][] f, int[][] uc) {

		if (! inField(r, c, f)) {
			IO.writeLn("Zeile " + r + ", Spalte " + c + " nicht in Feld");
			return false;
		}

		if (f[r][c]) {
			uc[r][c] = MINE;
			return true;
		}
		uc[r][c] = countMines(f, r, c); // Nachbarnminen
		return false;
	}

	static int countMines(boolean[][] f, int r, int c) {

		int n = 0;

		for (int i = r-1; i <= r+1; i++) {
			for (int j= c-1; j <= c+1; j++) {
				if (inField(i, j, f) && f[i][j]) {
					n++;
				}
			}
		}
		return n;

	}

	static boolean inField(int r, int c, boolean[][] f) {
		return r >= 0 && c >= 0 && r < f.length && c < f[0].length;
	}

	static boolean allUncovered(int[][] uc, boolean[][] f) {
		for (int i = 0; i < f.length; i++) {
			for (int j = 0; j < f[i].length; j++) {
				// wenn keine Mine auf i, j soll es aufgedeckt sein
				if (! f[i][j] && uc[i][j] == -1) {
					return false;
				}
			}
		}
		return true;
	}

	static void print(int[][] uc) {
		IO.writeLn();
		for (int i = 0; i < uc.length; i++) {
			for (int j = 0; j < uc[i].length; j++) {
				if (uc[i][j] == -1) {
					IO.write(" - ");
				} else if (uc[i][j] == MINE) {
					IO.write(" * ");
				} else {
					IO.write(" " + uc[i][j] + " ");
				}
			}
			IO.writeLn();
		}
	}

	static int[][] createUncovered(int h, int w) {
		int [][] uc = new int[h][w];
		for (int i = 0; i < uc.length; i++) {
			for (int j = 0; j < uc[i].length; j++) {
				uc[i][j] = -1;
			}
		}
		return uc;
	}

}

Hi hab hier den code meines programmes nur irgendwie funktioniert es nicht irgendwie wenn ich das programm starte hängt sich irgendwie auf in der eingabeforderung und es wird irgendwie immer ausgegeben dass ich eine bombe erwische hat wer ne ahnung was da fehler sein kann?

Hier die anforderungen meiner übung:
Wir wollen uns nun selbst ein Minesweeper-Spiel programmieren. Das Spiel soll folgend laufen:
Zuerst wird eine gewünschte Größe des Spielfeldes eingelesen.
Dann werden im Spielfeld zufällig Minen gelegt. Wir wollen durchschnittlich auf 20% der Felder Minen
setzen, d.h. jedes Feld erhält mit der Wahrscheinlichkeit 0,2 eine Mine (verwenden Sie Math.random()).
Der Spieler hat nun solange die Möglichkeit Felder aufzudecken, bis er entweder alle freien Felder
aufgedeckt hat (dann hat er gewonnen) oder er auf eine Mine „tritt“ (dann hat er verloren). Ein Feld wird
aufgedeckt, indem die Zeile und Spalte des Feldes eingelesen wird.
Es wird nach jedem Zug der Spielstand angezeigt, indem für nicht-aufgedeckte Felder das Zeichen '-', für
aufgedeckte freie Plätze die Anzahl der Minen in den Nachbarfeldern und für Minenfelder der Stern '*'
ausgegeben wird.
Man soll eine beliebige Anzahl von Spielen spielen können.
Beispiel:
Breite des Feldes: 4
Hoehe des Feldes: 4

0 1 2 3
0 - - - -
1 - - - -
2 - - - -
3 - - - -

Feld aufdecken (x y): 2 2

0 1 2 3
0 - - - -
1 - - - -
2 - - 1 -
3 - - - -

Feld aufdecken (x y): 1 2

0 1 2 3
0 - - - -
1 - - 1 -
2 - - 1 -
3 - - - -
Feld aufdecken (x y): 0 1

0 1 2 3
0 – 1 - -
1 - - 1 -
2 - - 1 -
3 - - - -

...

Feld aufdecken (x y): 3 0

0 1 2 3
0 1 1 - -
1 - - 1 1
2 - - 1 -
3 * - - -

Beng!!!! Mine erwischt und verloren.

Wollen Sie es nochmals versuchen (j|n)? j
 
Kann nur an dieser blöden IO-Klasse liegen, mit Java-Bordmitteln läuft es wie geschmiert (zum Stil will ich mich mal nicht äußern)
Code:
import java.util.Scanner;

public class Mine {

   static final int MINE = 99;
   static Scanner scanner = new Scanner(System.in);

   public static void main(String[] args) {

      boolean[][] field;

      // solange man spielen will
      do {
         // S1) Einlesen der Feldgroesse
         int w = readFieldWidth();
         int h = readFieldHeight();

         // S2) Einlesen der Bombenwahrscheinlichkeit
         double prob = readBombProb();

         // S3) Erstellen eines entsprechenden Feldes
         field = createField(w, h, prob);

         // Testausgabe
         printFieldForTesting(field);

         // S4) Spielen des Spieles
         boolean won = play(field);

         if (won) {
            System.out.println("Gratuliere ! Gewonnen");
         } else {
            System.out.println("Beng!!! Leider im Kampf gefallen!");
         }

         // S5) Fragen ob noch einmal gespielt werden soll.
      } while (playAgain());
   }

   static void printFieldForTesting(boolean[][] f) {

      System.out.println();
      for (int i = 0; i < f.length; i++) {
         for (int j = 0; j < f[i].length; j++) {
            if (f[i][j]) {
               System.out.print(" * ");
            } else {
               System.out.print(" - ");
            }
         }
         System.out.println();
      }
      System.out.println();
   }

   static int readFieldWidth() {
      System.out.print("Feldbreite: ");
      return scanner.nextInt();
   }

   static int readFieldHeight() {
      System.out.print("Feldhoehe: ");
      return scanner.nextInt();
   }

   static double readBombProb() {
      System.out.print("Wahrscheinlichkeit fuer Mine: ");
      return scanner.nextDouble();
   }

   static boolean[][] createField(int w, int h, double prob) {
      boolean[][] f = new  boolean[h][w];
      for (int i = 0; i < f.length; i++) {
         for (int j = 0; j < f[i].length; j++) {
            f[i][j] = Math.random() < prob;
         }
      }
      return f;
   }

   static boolean playAgain() {
      System.out.println();
            System.out.println("Wollen Sie es nochmals versuchen (j|n)?");
      return scanner.next().toLowerCase().equals("j");
   }

   static boolean play(boolean[][] field) {
      int[][] uncovered;
      uncovered = createUncovered(field.length, field[0].length);
      int row, col;
      boolean dead = false;
      // Ausgeben der aufgedeckten Felder
      print(uncovered);
      do {

         // Einlesen des nächsten Feldes das aufgedeckt werden soll
         System.out.print("Zeile: ");
         row = scanner.nextInt();
         System.out.print("Spalte: ");
         col = scanner.nextInt();

         // Aufdecken: entweder Mine erwischt oder Anzahl der nachbarminen anzeigen
         dead = uncover(row, col, field, uncovered);
         // Ausgeben der aufgedeckten Felder
         print(uncovered);

      //solange bis alle nicht-Minen aufgedeckt oder !field[row][col])
      } while (! allUncovered(uncovered, field) && ! dead);

      // return won
      return ! dead;

   }

   static boolean uncover(int r, int c, boolean[][] f, int[][] uc) {

      if (! inField(r, c, f)) {
         System.out.println("Zeile " + r + ", Spalte " + c + " nicht in Feld");
         return false;
      }

      if (f[r][c]) {
         uc[r][c] = MINE;
         return true;
      }
      uc[r][c] = countMines(f, r, c); // Nachbarnminen
      return false;
   }

   static int countMines(boolean[][] f, int r, int c) {

      int n = 0;

      for (int i = r-1; i <= r+1; i++) {
         for (int j= c-1; j <= c+1; j++) {
            if (inField(i, j, f) && f[i][j]) {
               n++;
            }
         }
      }
      return n;

   }

   static boolean inField(int r, int c, boolean[][] f) {
      return r >= 0 && c >= 0 && r < f.length && c < f[0].length;
   }

   static boolean allUncovered(int[][] uc, boolean[][] f) {
      for (int i = 0; i < f.length; i++) {
         for (int j = 0; j < f[i].length; j++) {
            // wenn keine Mine auf i, j soll es aufgedeckt sein
            if (! f[i][j] && uc[i][j] == -1) {
               return false;
            }
         }
      }
      return true;
   }

   static void print(int[][] uc) {
      System.out.println();
      for (int i = 0; i < uc.length; i++) {
         for (int j = 0; j < uc[i].length; j++) {
            if (uc[i][j] == -1) {
                     System.out.print(" - ");
            } else if (uc[i][j] == MINE) {
                     System.out.print(" * ");
            } else {
                     System.out.print(" " + uc[i][j] + " ");
            }
         }
         System.out.println();
      }
   }

   static int[][] createUncovered(int h, int w) {
      int [][] uc = new int[h][w];
      for (int i = 0; i < uc.length; i++) {
         for (int j = 0; j < uc[i].length; j++) {
            uc[i][j] = -1;
         }
      }
      return uc;
   }

}
 
Na gut, weil heut Weihnachten ist...

Hier eine etwas objekt-orientiertere Version:

Code:
import java.util.Scanner;
import static java.lang.System.*;
import static java.lang.Math.*;

public class MineSweeper {
  private static final Scanner scanner = new Scanner(in);

  
  private boolean won = false;
  private final int width;
  private final int height;
  private final Field[][] field;
  private StringBuilder sb = new StringBuilder();
  
  public MineSweeper(int width, int height, double prob) {
    this.width = width; 
    this.height = height; 
    this.field = new Field[width][height];
    //initialize array
    for(int x = 0; x < width; x++) {
      for(int y = 0; y < height; y++) {
        field[x][y] = new Field();
      }
    }
    //place mines
    for(int x = 0; x < width; x++) {
      for(int y = 0; y < height; y++) {
        if(random() < prob) {
          setMine(x,y);
        }
      }
    }
  }
  
  private void setMine(int x, int y) {
    field[x][y].setMine();
    //increase the mine counts of the neighbors
    for (int i = x-1; i <= x+1; i++) {
      for (int j = y-1; j <= y+1; j++) {
        if(inside(i,j)) {
          field[i][j].increaseMines();
        }
      }
    }
  }
  
  //test if coords are inside the field
  private boolean inside(int x, int y) {
    return 0 <= x && x < width && 0 <= y && y < height;
  }
  
  @Override
  public String toString() {
    sb.setLength(0);
    for(int y = 0; y < height; y++) {
      sb.append(String.format("%02d",y)).append(": ");
      for(int x = 0; x < width; x++) {
        sb.append(field[x][y]).append(" ");
      }
      sb.append("\n");
    }
    return sb.toString();
  }
  
  public void start() {
    boolean exploded = false;
    while(! won && ! exploded) {
      //show the field
      out.println(this);
      for(int x = -1, y = -1; ! inside(x,y);) {
        out.print("Zeile: ");
        y = scanner.nextInt();
        out.print("Spalte: ");
        x = scanner.nextInt();
        if (inside(x,y)) {
          //make the player move
          exploded = !field[x][y].tryToUncover();
        } else {
          out.println("Ungültige Eingabe");
        }
      }
      //test if won
      won = true;
      for(int x = 0; x < width; x++) {
        for(int y = 0; y < height; y++) {
          if(! field[x][y].isUncovered() && ! field[x][y].isMine()) {
            won = false;
            break;
          }
        }
      }
    }
    //show uncovered version of field
    for(int x = 0; x < width; x++) {
      for(int y = 0; y < height; y++) {
        field[x][y].tryToUncover();
      }           
    }
    out.println(this);
  }
  

  public boolean hasWon() {
    return won;
  }
  
  public static void main(String... args) {
    for(boolean wannaPlay = true; wannaPlay; ) {
      out.print("Feldbreite (min. 3): ");
      int width = max(scanner.nextInt(), 3);
      out.print("Feldhöhe (min. 3): ");
      int height = max(scanner.nextInt(), 3);
      out.print("Wahrscheinlichkeit für Mine (0 .. 0.9): ");
      double prob = Math.min(Math.max(scanner.nextDouble(), 0),0.9);
      MineSweeper ms = new MineSweeper(width, height, prob);
      ms.start();
      if(ms.hasWon()) {
         out.println("Gratuliere ! Gewonnen");
      } else {
         out.println("Beng!!! Leider im Kampf gefallen!");
      }
      out.println("Wollen Sie es nochmals versuchen (j|n)?");
      wannaPlay = "j".equals(scanner.next().toLowerCase());
    }
  }
  
  private static class Field {
    private boolean uncovered = false;
    private boolean mine = false;
    private int mineCount = 0;
    public void setMine() {
      mine = true;
    }
    public boolean isMine() {
      return mine;
    }
    public void increaseMines() {
      mineCount++;
    }
    public int getMineCount() {
      return mineCount;
    }
    public boolean tryToUncover() {
      uncovered = true;
      return ! mine;
    }
    public boolean isUncovered() {
      return uncovered;
    }
    @Override
    public String toString() {
      if (! uncovered) {
        return "-";
      } else if(mine){
        return "*";
      } else {
        return "" + mineCount;
      }
    }
  }
  
}
 
würde der code auch mit IO Klasse funktionieren muss nämlich die IO klasse verwenden .... 🙁

Glaub auch nicht dass wir die imports verwenden dürfen ... also das scanner und so.... was macht das genau ? kann man das anders schreiben? danke bis jetzt mal 🙂
 
Ich kenne diese ominöse IO Klasse nicht, aber es sollte eigentlich gehen. Schon komisch, wie jemand darauf kommen kann, dass mit so einer Krüppel-Klasse das Programmieren leichter würde. Das ist etwa so, als würde jemand versuchen Russisch zu lehren, ohne kyrillische Buchstaben zu benutzen...

Falls du den Quellcode von IO hast, kannst du ja nachschauen, wie es dort umgesetzt ist (wahrscheinlich fast genauso, wie ich es hier gemacht habe).

Mein Programm ist übrigens auch nicht der Weisheit letzter Schluss. Aber zumindest die Idee mit der Klasse "Field" (daraus kann man auch eine eigenständige Klasse machen) und das Hochzählen beim "Bombenlegen" finde ich ganz OK. main() und vor allem start() sehen aber noch etwas wurstelig aus...

Ich weiß nicht, ob es eine gute Idee ist, deinem Prof/Lehrer meine Version zu servieren. Ich würde stutzig werden, wenn ein Student mit Sachen wie inneren statischen Kassen aufkreuzt ;-)
Vielleicht solltest du nochmal deine Variante unter die Lupe nehmen. Wie gesagt, es muss irgendwie an der IO liegen. Vielleicht mal ein paar print-Anweisungen einstreuen, um zu sehen, wo es genau schiefläuft...
 
Was ich nicht ganz versteh was heißt das @override genau was machst das?

würd es eigentlich mit rekursionen noch platzsparrender zu programmieren gehn?
 
@Override ist eine Markierung für den Compiler. Schönes Anwendungsbeispiel: Eine Klasse überschreibt eine Methode x(). Nun stellt man später fest, dass x() komplett raus muss. Ohne @Override passiert es leicht, dass man x() nur aus der Superklasse löscht, aber in den Subklassen, die x() überschreiben, vergisst. Mit dieser Markierung meckert in solchen Fällen der Compiler und kann einem so langes Fehlersuchen ersparen.

Ark
 
@Override hilft auch, Tippfehler zu erkennen, an denen man sich sonst den Wolf sucht. Etwa wenn du Object.toString() überschreiben willst, aber toSring() schreibst. Das ist ja an sich kein Fehler, nur wird halt in println() nicht deine Methode aufgerufen, sondern die der Oberklasse. Schreibst du aber @Override toSring, meckert der Compiler. Solche Tippfehler kommen häufiger vor, als man denkt (Heißt es z.B. hashcode oder hashCode? Kann ich mir nie merken...)
 
würd es eigentlich mit rekursionen noch platzsparrender zu programmieren gehn?
Beim Programmieren geht es um Lesbarkeit. Kürzer ist oft lesbarer, aber nicht immer.

Schleifen kann man immer durch Rekursion ersetzen. Zu beachten ist aber, dass Rekursion u.U. zu einer StackOverflowException führen kann, wenn sich eine Funktion zu oft selbst aufruft.

Als Beispiel mal die start()-Funktion rekursiv. Ob das lesbarer ist, musst du selbst entscheiden
Code:
public void start() {
    boolean exploded = false;
    //show the field
    out.println(this);
    for(int x = -1, y = -1; ! inside(x,y);) {
      out.print("Zeile: ");
      y = scanner.nextInt();
      out.print("Spalte: ");
      x = scanner.nextInt();
      if (inside(x,y)) {
        //make the player move
        exploded = !field[x][y].tryToUncover();
      } else {
        out.println("Ungültige Eingabe");
      }
    }
    //test if won
    won = true;
    for(int x = 0; x < width; x++) {
      for(int y = 0; y < height; y++) {
        if(! field[x][y].isUncovered() && ! field[x][y].isMine()) {
          won = false;
          break;
        }
      }
    }
    if(won || exploded) {
      //show uncovered version of field
      for(int x = 0; x < width; x++) {
        for(int y = 0; y < height; y++) {
          field[x][y].tryToUncover();
        }           
      }
      out.println(this);
      return; //<--- Abbruch der Rekursion
    } 
    start(); //<-----rekursiver Aufruf
}
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben