# Problem bei Schiffeversenken-Spiel



## Masipulami (18. Jan 2006)

Hallo zusammen,

ich habe mich die letzten Tage mal daran gesetzt ein Schiffe versenken Spiel zu programmieren.
Das Spiel ansich läuft so weit prima.

Jetzt habe ich das Ganze auch noch so programmiert, dass der aktuelle Score immer zwischengespeichert wird und dann am Ende ausgegeben wird. Der Score wird auch korrekt gespeichert.
Bei der Ausgabe klappt allerdings etwas noch nicht.

Ich wollte das folgendermaßen machen:
Nachdem das letzte Schiffsfeld aufgedeckt wurde, wird der Benutzer aufgefordert seinen Name einzugeben.
Dieser Name wird dann mit dem Score im aktuellen Fenster ausgegeben (also dort wo vorher noch das Spielfeld war (hat gestern auch schon mal funktioniert; das Spielfeld wird dann einfach nur "überzeichnet") und in der Datei highscore.txt gespeichert.
Dabei soll nach jedem Spiel der Name und Score in einer neuen Zeile in der Datei gespeichert werden.
Beim nächsten Klick soll dann diese Datei wieder ausgelesen werden und deren Inhalt (also alle gespeicherten Highscores) wieder im aktuellen Fenster (wieder mittels "Überzeichnen") ausgegeben werden.

Von der Funktionalität her sollte das ja kein Problem sein. Nur leider habe ich noch einen Fehler im Code und der Inhalt der Datei bleibt leer. Ganz egal, was ich eingebe.

Die IF-Anweisungen in der Paint-Methode müssten so ja eigentlich laufen.
Dass der Score im Fenster angezeigt wurde hat heute Abend schon auf diese Weise geklappt.

Es würde mich sehr freuen, wenn ihr euch mal den Code ansehen würdet.
Ich finde den/die Fehler einfach nicht.

Viele Grüße,
Masipulami



```
import java.io.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

class SchiffeVersenken extends Frame 
{
   public int zaehler = 0;
   final int MAXSPALTE = 16, MAXZEILE = 16; // Geometrie des Spielfelds
   
   Image bild0, bild1, bild2, bild3, bild4, bild5, bildT; // Referenzen auf die zu ladenden Bildchens
   
   int maxX = 0; // maximaler x-Wert, dient zur Errechnung der notweindigen Fenstergröße
   
   Point aktMausPunkt = new Point(0,0); // Koordinaten des letzten Mausklicks
   
   // Sichtbarkeitsmatrix - zeigt an ob an dieser Stelle das Spielbrett sichtbar ist (true) oder nicht (fals)
   boolean sm[][] = new boolean[MAXSPALTE][MAXZEILE]; 
   
   // Wertematrix des Spielfelds. Wird mit Hilfe von Zufallszahlen im Kostruktor erzeugt.
   int spielFeld[][] = null;
	
   int feld1 = 0; int feld2 = 0;
   int scoreZähler = 0; // Variable, die den aktuellen Score speichert
	
   final int ABSTAND=4; // Abstand des Bildes von oben, unten, links rechts 
   
   int schiffsfeldzaehler = 0;  // zählt alle Felder aller Schiffe zusammen
   int wert;  // Wert, der an jeweiligen Stelle des mit Random() erzeugten Arrays steht
   Font f;  // für Highsoreausgabe
   public int x=50;  // Position der Textausgabe
   public int y=50;  // Position der Textausgabe
   String ausgabe; // Hier wird Aufgabestring von Punktestand des Scorzählers gespeichert
   BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
   String name; // für eingegebenen Name (für Highscore)
   String highsc; // wird später so verwendet: highsc = name + " " + ausgabe;
   int c;
   
   public static void main (String[] args)
   {  
	SchiffeVersenken re = new SchiffeVersenken();
   }

   public SchiffeVersenken() 
   {
	  super("Bild Anzeigen");
	  
	  f = new Font("Verdana", Font.PLAIN, 24);
   	  
	  addWindowListener(new WindowClosingAdapter(false));
   	 
      // Schliesst den MouseListerner mit eigener Klasse (in der gleichen Datei unten!) an 
	  addMouseListener(new myMausListener()); 
   	  
	  setBackground(new Color(0,22,0));	// Hintergrundfarbe setzen
     
	  setSize(200,200);	// die Größe ist nur vorläufig, wird in paint() auf den endgültigen Wert geändert
	  	  
	  Random zufallsGenerator = new Random();
	  int[][] spielFeld = new int[16][16]; 
	  int zufallsZahl = 0;    // Variable speichert die Zufallszahl 
	  int hilfsVariable = 0;  // Hilfsvariablen sollen einen reibungslosen Ablauf der
	  int hilfsVariable2 = 0; // Arrayaufnahme der unterschiedlichen Schiffe sichern. 
	  int zähler = 0;         // Zähler, der die Anzahl der Schiffe zählt.
	  
	  
	  // Hier werden im Array mittels Zufallsgenerator die Schiffe platziert.
	  // Somit sind die Schiffe bei jedem Start an einer anderen Position.
	  for(int i = 0; i <16; i++)
	  {
		for(int j = 0; j < 16; j++)
		{
            // Hier werden die 2er, 3er, 4er und 5er Felder im Array aufgenommen.
			if(hilfsVariable == 2 | hilfsVariable == 3 | hilfsVariable == 4 | hilfsVariable == 5)
			{
				spielFeld[i][j] = zufallsZahl;
				hilfsVariable2--;
	  			
				if(hilfsVariable2 == 1)
				{
				hilfsVariable = 0;
				zähler++; // Zähler der die Anzahl der Schiffe hochzählt,
				}		  // wenn ein 2er, 3er, 4er oder 5er Schiff platziert wird.
			}
	  		
			else
			{
				// Eine Zufallszahl wird generiert. Die Zufallszahö ist deshalb so hoch damit nicht 
				// zu viele Schiffe auf dem Spielfelsd sind.
				zufallsZahl = zufallsGenerator.nextInt(30); 											
				
                // Wenn die Zufallszahl größer 5 ist dann wird sie genullt, also leeres Feld.
				if(zufallsZahl > 5) 
				zufallsZahl = 0;
	  			
                // Sorgt dafür, dass kein zu großes Schiff vor Ende der Spalte gezeichnet wird.
				if(zufallsZahl + j > 15) 
				zufallsZahl = 0;
	  			
				if(zufallsZahl == 1)
                // Zähler der die Anzahl der Schiffe hochzählt, wenn ein 1er Schiff platziert wird.
				zähler++; 
				spielFeld[i][j] = zufallsZahl; // Hier werden die leeren Felder und die 1er Felder ins Array aufgenommen.
				hilfsVariable = zufallsZahl; //Hilfsvariablen die einen reibungslosen Ablauf,
				hilfsVariable2 = zufallsZahl;// der 2er, 3er, 4er und 5er Felder bei der Arrayaufnahme sicherstellen.
			}
		}
	  }
	 
	  // Nachdem der Spielfeldarray nun mit Zufallswerten gefüllt wurde, werden die
	  // Schiffsfelder ausgezählt, also alle Felder, auf denen ein Teil eines Schiffes ist.
	  for(int k = 0; k <16; k++)
	  {
		for(int l = 0; l <16; l++)
		{
			int wert = spielFeld[k][l];
			
			if(wert == 1 | wert == 2 | wert == 3 | wert == 4 | wert == 5)
			{
				schiffsfeldzaehler++;
			}
		}
	  }
	 
	 System.out.println("============================");
	 System.out.println("==    Schiffeversenken    ==");
	 System.out.println("============================"); 
	 //	 Bei der Erstellung des Frames wird die Anzahl der erzeugten Schiffe ausgegeben  
	 System.out.println("Anzahl der Schiffe: " +zähler); 
	 // GIbt die Anzahl der Schiffsfelder aus
	 System.out.println("Anzahl der Schiffsfelder: " + schiffsfeldzaehler);
	 System.out.println("============================\n");
	 //System.out.println();
	 
	 // Weist das Konstruktorarray dem Klassenarray zu
	 this.spielFeld = (int[][]) spielFeld.clone(); 
   	 	
	 // Bilder werden geladen
	 bild0=getToolkit().getImage("feld0.gif");
	 bild1=getToolkit().getImage("feld1.gif");   	  
	 bild2=getToolkit().getImage("feld2.gif");
	 bild3=getToolkit().getImage("feld3.gif");
	 bild4=getToolkit().getImage("feld4.gif");
	 bild5=getToolkit().getImage("feld5.gif");
	 bildT=getToolkit().getImage("feldT.gif");

	 setVisible(true);   
  }
  
  // wird von myMausListener  aufgerufen, und setzt die Referenz der Variablen aktMausPunkt
  // auf das Point-Objekt mit den aktuellen Daten des letzten Mausklicks
  public void addPunkt(Point p)
  {
	  this.aktMausPunkt = p; 
  }

  private void feldBerechnen()
  {
	  int insOben = getInsets().top; 
	  int insLinks = getInsets().left; 
	  int bildBreite = bild0.getWidth(this); 
	  int bildHoehe = bild0.getHeight(this);         
	  int x=-1,y=-1;
	  
	/*
			Nachdem die Insets des Fensters und Höhe und Breite der Button-Bilder ermittelt wurden, werden nun aus den Mauskoordinaten
			die Koordinaten des angeklickten Feldes errechnet.
        
			Algorithmus:
			der x-Wert (d.h. die linke Kante) des beispielsweise 5. Bildes errechnet sich aus
			insetLinks + (5*Abstand-zwischen-Bildern) + 4*Bildbreite (5 Abstände und 4 Bilder liegen rechts des 5. Bildes)
			Dieser Wert ist die Linke Kante und muss kleiner sein als der x-Wert des Mausklicks, damit das 5. Bild angeklickt sein kann
        
			Die rechte Kante des beispielsweise 5. Bildes errechnet sich aus
			insetLinks + (5*Abstand-zwischen-Bildern) + 5*Bildbreite       ( d.h. Linke Kante + Bildbreite)   
			Dieser Wert muss größer sein als der x-Wert des Mausklicks, damit dieses Bild angeklickt sein kann
        
			.. analoges gilt für die y-Werte
        
			Wurde zwischen die Felder geklickt wird für beide Koordinaten -1 ausgegeben
      
		  */
	  
	  
	  for ( int i =0; i < MAXSPALTE; i++)
	   for ( int j =0; j < MAXZEILE+1; j++)
		if ( aktMausPunkt.x > insLinks +  (i+1)* ABSTAND + i*bildBreite &&  aktMausPunkt.x < insLinks + (i+1)*ABSTAND + (i+1)* bildBreite && 
			 aktMausPunkt.y > insOben + (j+1)* ABSTAND + j*bildHoehe &&  aktMausPunkt.y < insOben + (j+1)*ABSTAND + (j+1)*bildHoehe )
	  {
		 x = i; 
		 y = j;
		 this.feld1 = x; // Speichert den angklickten Punkt in der Klassenvariablen
		 this.feld2 = y; //	Speichert den angklickten Punkt in der Klassenvariablen
	  }    
	      
	 // wenn kein Feld getroffen wurde (d.h. es wurde ins Wasser neben den Schiffen geklickt) wird auch nix eingetragen
	 // anderfalls wird das jeweilige Feld in der Sichtbarkeitsmatrix auf true gesetzt, d.h. an dieser Stelle kann der
	 // Eintrag im Spielfeld (sp-Matrix) ausgegeben werden
	 if ( x != -1) // Feld getroffen 
        // der angelickte Punkt wird als true in der Sichtbarkeitsmatrix wird auf true gesetzt
	 	sm[x][y] = true; 
	
	 System.out.println("getroffen: "+ (x+1) + " - " + (y+1));
	 
  }

    // Gibt die Klassenvariable zurück. Hab das müssen so programmieren da der Compiler es bei 
    // mir anders nicht gemacht hat
  	private int xKoordinate()
	{
		return this.feld1; 
	}
	
    // Gibt die Klassenvariable zurück.
	private int yKoordinate()
	{
		return this.feld2;
	}
	
	private void scoreBerechnen()
	{
        // Gibt den Wert des Arrays zurück auf den geklickt wurde
		int bildKoordinate = spielFeld[xKoordinate()][yKoordinate()]; 
		
        // Jetzt wird noch je nach Klick der Score ausgerechnet und der Schiffsfeldzähler
		// um 1 herabgesetzt, damit später (wenn der Schiffsfeldzähler bei 0 angekommen ist
		// die Eingabeaufforderung, das Ausgaben des Scores und das Speichern des Scores
		// in einer Datei ausgeführt werden kann -> siehe Paint()
		if(bildKoordinate == 0)
		{
			scoreZähler = scoreZähler -2;
		}
		
		if(bildKoordinate == 1)
		{
			scoreZähler = scoreZähler +1;
			schiffsfeldzaehler--;
		}
		
		if(bildKoordinate == 2)
		{
			scoreZähler = scoreZähler +2;
			schiffsfeldzaehler--;
		}
		
		if(bildKoordinate == 3)
		{
			scoreZähler = scoreZähler +3;
			schiffsfeldzaehler--;
		}
		
		if(bildKoordinate == 4)
		{
			scoreZähler = scoreZähler +4;
			schiffsfeldzaehler--;
		}
		
		if(bildKoordinate == 5)
		{
			scoreZähler = scoreZähler +5;
			schiffsfeldzaehler--;
		}
		
		System.out.println("Aktueller Score: " + scoreZähler);	
		System.out.println("Verbleibende Schiffsfelder: " + schiffsfeldzaehler);
		System.out.println();
		
		ausgabe = "Punktestand: " + scoreZähler;
	}
	

  public void paint(Graphics gra) 
  {			
  	if(schiffsfeldzaehler > 0)
	{
         //	die x-Koordinate des lo-Ecks des Bildes wird errechnet: Inset-Wert plus (selbstdefinierter) ABSTAND
		 int aktX=ABSTAND + getInsets().left;  
	     // die y-Koordinate des lo-Ecks des Bildes wird errechnet: Inset-Wert plus (selbstdefinierter) ABSTAND																		
		 int aktY = ABSTAND + getInsets().top;	
	     
		 // nun werden für alle möglichekn Koordinatenwertepaare das jeweilige bild angezeigt
		 // für alle Zeilen und für alle Spalten einer Zeile wird mit bildSuchen das für
		 // den Koordinateneintrag passende Bild gesucht und an der errechneten Stelle ausgegeben
		 for ( int j = 0; j < MAXZEILE; j++)
		 {  
		  	for (int i = 0; i < MAXSPALTE; i++)
		  	{ 
		  		//	bildSuchen gibt das passende Bild für die Koordinaten zurück 
		  		// aktX und aktY sind die errechneten Pixel-Koordinaten des Bildecks links oben 	
		  		gra.drawImage( bildSuchen(i,j),aktX, aktY,this);
           
		  		aktX += bild0.getWidth(this) + ABSTAND; // x weiterschalten  
		  		maxX = aktX; 
		  	}
		 aktY += bild0.getHeight(this) + ABSTAND;// y weiterschalten
		 aktX=ABSTAND + getInsets().left;           
		 }     
      
		aktX = maxX + getInsets().right;
		aktY = aktY + getInsets().bottom;
 		
		this.setSize(aktX, aktY); // und das Fester wird auf die neue Größe eingestellt 
	}
	
	if(schiffsfeldzaehler == 0)
	{
		gra.setColor(new Color(188,0,0));
	    gra.setFont(f);
	    
	    //ausgabe = "Punktestand: " + scoreZähler;
	    
	    gra.drawString(ausgabe, x, y);
	    this.setSize(200, 200);
	    
	    try
		{
	    	PrintWriter f = new PrintWriter(new BufferedWriter(new FileWriter("highscore.txt")));
	    	
	    	System.out.print("Bitte geben Sie Ihren Name ein: ");
	    	name = stdin.readLine();
	    	highsc = name + " " + ausgabe;
	    	f.println(highsc);
	    	
	    	f.close();
	    
		}
	    catch (IOException ex) {};
	}
	
	if(schiffsfeldzaehler < 0)
	{
		gra.setColor(new Color(188,0,0));
	    gra.setFont(f);
	    this.setSize(200, 200);
	    	        
	    try
		{
	    	FileReader f = new FileReader("highscore.txt");
	    	
	    	while ((c = f.read()) != -1) 
	         {
	    		int z = 0;
	    		char highscArr[];
	    		highscArr[z]=(char)c;
	    		z++;
	         }
	         f.close();
	         
	         
	         gra.drawString("HIGHSCORELISTE", x, y);
	         gra.drawString(ausgabe, x, y);
	    
		}
	    catch (IOException ex) {};
	}
  
  
  }
  
	/*
			aus paint() ausgegliederte Methode - um paint() nicht riesig werden zu lassen
			errechnet aus den x, und y Koordinaten in der Spiele-Matrix - nicht den Mauskoordinaten(!!)
        
	*/
	Image bildSuchen(int x, int y)
	{
	   int matrixWert = spielFeld[x][y];  

	   if( sm[x][y]) // Eintrag in Sichtbar-Matrix ist true - Feld soll sichtbar sein
		  switch(matrixWert)
		  {
			 case 0: return bildT;
			 case 1: return bild1;
			 case 2: return bild2; 
			 case 3: return bild3;
			 case 4: return bild4;
			 case 5: return bild5;      
		 }
	   else 
		 return bild0;
         
         
	   return bild0; 
   
	}

 class myMausListener  extends MouseAdapter
 {
	   
	   
	   public void mousePressed(MouseEvent event)
	   {
	   	
	   	  SchiffeVersenken fenster = (SchiffeVersenken) event.getSource();

		  Point aktPoint = new Point(event.getX(),  event.getY());
      
		  fenster.addPunkt(aktPoint);
		  fenster.feldBerechnen(); 
		  fenster.scoreBerechnen();
		  fenster.repaint();
		  
		  zaehler++;
	   }
 }
}
```


----------



## sliwalker (18. Jan 2006)

Hoi,

schreib mal ab zeile 315 das hier:

```
try 
      { 
          BufferedWriter f = new BufferedWriter(new FileWriter("highscore.txt")); 
           
          System.out.print("Bitte geben Sie Ihren Name ein: "); 
          name = stdin.readLine(); 
          highsc = name + " " + ausgabe; 
          f.write(highsc); 
          f.newLine(9;
          f.flush();
           
          f.close(); 
       
      } 
       catch (IOException ex) {}; 
   }
```

nicht getestet 

greetz
SLi

EDIT: war write(String s)...nicht writeln()


----------



## Masipulami (18. Jan 2006)

Danke dir. Werd ich gleich mal testen.
Was macht flush noch mal? *blödfrag*


----------



## Masipulami (18. Jan 2006)

Hier in dem Teil wird mir auch ein Fehler angezeigt:


```
try
		{
	    	FileReader f = new FileReader("highscore.txt");
	    	
	    	while ((c = f.read()) != -1) 
	         {
	    		int z = 0;
	    		char highscArr[];
	    		highscArr[z]=(char)c;
	    		z++;
	         }
	         f.close();
	         
	         
	         gra.drawString("HIGHSCORELISTE", x, y);
	         gra.drawString(ausgabe, x, y);
	    
		}
	    catch (IOException ex) {};
```


Und zwar in dieser Zeile:


```
highscArr[z]=(char)c;
```

Der Teil ist auch noch nicht ganz fertig.
Ich stell mir das so vor, dass mit der while-Schleife oben wieder alles, was in der Datei steht, in den Array gespeichert wird. Dieser danach in nen String umgewandelt wird und dann als gesamte Highscoreliste ausgegeben wird.

Oder gibt es eine Möglichkeit einfach Zeilenweise aus der Datei zu lesen, diese Zeilen dann jeweils in nem StringBuffer zu speichern und halt mit append immer an den StringBuffer anzuhängen, diesen StringBuffer dann in nen String umwandeln und den dann im Fenster mittels drawString auszugeben.

Nur wie muss dazu mein Code aussehen?


----------



## Masipulami (18. Jan 2006)

Komisch ist auch, dass 

a) Die Datei leer bleibt und
b) Die Aufforderung den Name einzugeben immer wieder kommt. Also wie in einer Endlosschleife, obwohl die Anweisung den Name einzugeben nicht in einer Schleife steht.

Muss das Programm halt unbedingt in den nächsten Tagen zum Laufen bringen. Ist für die Uni und wird bewertet.


----------

