Boulder Dash nachbauen

babuschka

Top Contributor
Keine Ahnung, ob jemand Lust hat, das anzuschauen, aber wenn ich

Java:
//Die Klasse BoulderDash
import java.util.ArrayList;
import java.util.List;
 
 
public class BoulderDash{
	
	
public static void main( String[] args){
    
	MapParser mapparser=new MapParser();
	List<List<String>> maps = MapProvider.loadMaps();
    GUI gui=new GUI();
    
    for (List<String> level : maps){
        mapparser.parseMap(level);
        
        
    }
    
    
    
    
//weiter bin ich noch nicht
}
 
}


kompilieren lasse, kommt kein Fehler, aber wenn ichs ausführen lasse, kommt dies:

Exception in thread "main" java.lang.Nullpointerexception
at MapParser.<init> 8
at BoulderDash main. 11



Woran es liegt, bin ich nicht in der Lage zu erkennen.



Ich poste aber mal den Code zu MapParser noch, damit vllt. irgendjemand damit was anfangen kann:

Java:
import java.util.ArrayList;
import java.util.List;
 
//Die Klasse MapParser
 
public class MapParser{
	List<String> map;
	Element[][]spielfeld=new Element[map.size()-1][map.get(1).length()];
	
	
	
	
	//Implementiere das Spielfeld nur, wenn das übergebene Level valide ist.
	//Das wird vorher mit Hilfe der untenstehenden Methoden getestet.
    Element[][] parseMap(List<String> map){
        
    	   
                           char certainchar;
                           Element newElement;
                           int counter=0;
                           int counter2=0;
                           boolean sourrounded=false;
                           boolean equalLength;
                           
                           
                           for(int j=0; j<map.size(); j++){
                        	   
                               counter=countPlayer(map.get(j), 'P');
                               sourrounded=sourroundedByWalls(map.get(j));
                               counter2=countExists(map.get(j), 'G');
                               
                      }    
                           equalLength=equalLength(map);
                           
                   if(counter==1 && counter2>=1 && sourrounded==true && equalLength==true){       
                           
                           
                           
                           
 
        for(int i=0; i<map.size(); i++){
            
            for(int j=0; j<=map.get(i).length(); j++){
            certainchar=map.get(i).charAt(i);
            switch(certainchar){
            
            case'P': newElement=new Player(i,j,this); spielfeld[i][j]=newElement; break;
            case'E': newElement=new Erde(i,j,this); spielfeld[i][j]=newElement;break; 
            case'S': newElement=new Stein(i,j,this); spielfeld[i][j]=newElement;break;
            case'M': newElement=new Monster(i,j,this); spielfeld[i][j]=newElement;break;
            case'D': newElement=new Diamant(i,j,this); spielfeld[i][j]=newElement;break;
            case'G': newElement=new Ausgang(i,j,this); spielfeld[i][j]=newElement;break;
            case' ': newElement=new LeeresFeld(i,j,this); spielfeld[i][j]=newElement;break;
            }
            
            
            }
        }
    
                    }
                   
                   else {System.out.println("Level ist nicht rechteckig; Spielfeld wurde nicht initialisiert.");
                   spielfeld=null;
                   }         
                   return spielfeld;
    }       


public char getSpielfeld(int i, int j){
	return spielfeld[i][j].getChar();
}

public void setSpielfeld(int i, int j, char k){
	
	Element newElement2;
	switch(k){
    
    case'P': newElement2=new Player(i,j,this); spielfeld[i][j]=newElement2; break;
    case'E': newElement2=new Erde(i,j,this); spielfeld[i][j]=newElement2;break; 
    case'S': newElement2=new Stein(i,j,this); spielfeld[i][j]=newElement2;break;
    case'M': newElement2=new Monster(i,j,this); spielfeld[i][j]=newElement2;break;
    case'D': newElement2=new Diamant(i,j,this); spielfeld[i][j]=newElement2;break;
    case'G': newElement2=new Ausgang(i,j,this); spielfeld[i][j]=newElement2;break;
    case' ': newElement2=new LeeresFeld(i,j,this); spielfeld[i][j]=newElement2;break;
    }
	
}

//Es folgen Methoden, die für den Test der Validität eines Levels benutzt werden.

//Zähle die Anzahl der Spieler.

public int countPlayer(String string, char aChar){

  int counter=0;

    for(int i=0; i<string.length(); i++){
            
               if(string.charAt(i)==aChar){
                      counter++;
                  }
        
     }

return counter;
}


//Teste, ob am Anfang und Ende eines Strings ein bestimmes Char steht.

public boolean sourroundedByWalls(String string){

   boolean sourrounded=true;

         if(string.charAt(0)!='W' || string.charAt(string.length()-1)!='W'){
                  sourrounded=false;
          }

     return sourrounded;
}


//Zähle die Anzahl der Ausgänge.

public int countExists(String string, char aChar){

  int counter2=0;

    for(int i=0; i<string.length(); i++){
            
               if(string.charAt(i)==aChar){
                      counter2++;
                  }
        
     }
        return counter2;

}

//Teste, ob alle Zeilen die gleiche Länge haben (Rechtecksform des Spielfelds)

public boolean equalLength(List<String> irg){
boolean equalLength=true;

int LengthOfLine=irg.get(0).length();
int LengthOfNextLine;

if(equalLength==true){

  for(int i=1; i<irg.size();i++){
      
      LengthOfNextLine=irg.get(i).length();
  
      if(LengthOfLine!=LengthOfNextLine){
             equalLength=false;
         }
      LengthOfLine=LengthOfNextLine;

}
 
}


return equalLength;

}
}
 
R

read-only

Gast
Exception in thread "main" java.lang.Nullpointerexception
at MapParser.<init> 8
at BoulderDash main. 11

Nullpointerexception: Du greifst per .Notation auf Attribute eines Objektes zu das null ist.
der Fehler ist in BoudlerDash main Zeile 11 aufgetreten:
Java:
MapParser mapparser=new MapParser();

und zwar genauer in der Klasse Mapparser bei der init-Funktion zeile 8:
Java:
Element[][]spielfeld=new Element[map.size()-1][map.get(1).length()];

Du greifst dort auf map.size() und map.get(1).length() zu, einer von diesen Aufrufen hat also den Fehler verursacht und bewegst du jetzt deine Augen eine Zeile nach oben steht dort
Java:
List<String> map;
welche nicht initialisiert wurde also explizit null ist.
 

Sonecc

Gesperrter Benutzer
Das wird ihm nicht helfen, weil die Klasse konzeptionell schon falsch ist.
Die Liste wird in der ganzen Klasse nie verwendet außer zur Initialisierung von spielfeld. (als kleiner Tipp...)
 

babuschka

Top Contributor
Das wird ihm nicht helfen, weil die Klasse konzeptionell schon falsch ist.
Die Liste wird in der ganzen Klasse nie verwendet außer zur Initialisierung von spielfeld. (als kleiner Tipp...)


Meinst Du die Klasse BoulderDash oder die Klasse MapParser?


Okay, Du wirst die Klasse MapParser meinen.



Könntest Du mir vllt. näher erklären, inwiefern sie konzeptionell falsch ist?
Aber nur, wenn das nicht wieder Deinen Missmut hinaufbeschwört.
 
Zuletzt bearbeitet von einem Moderator:

Sonecc

Gesperrter Benutzer
Du hast 2 Felder:
map
spielfeld

map wird nur genutzt, damit du spielfeld initialisieren kannst. Du kannst zum Zeitpunkt der initialisierung aber gar nicht wissen, wie groß dein Feld ist, bzw. mit was für einer Liste du arbeiten wirst.
Wenn dein Spielfeld wirklich abhängig von der Liste (also map) ist, dann wirst du einen Konstruktor verwenden müssen oder das spielfeld innerhalb einer Methode initialisieren müssen, welche die Map als Parameter hat.


Edit: Rage Flames entfernt...
 

babuschka

Top Contributor
Die Initialisierung des Spielfeld passiert doch aber in einer Methode, die die Liste als Parameter hat, ist diese Methode denn nicht

Element[][] parseMap(List<String> map){...

?


Ich glaube, ich hab's schon verstanden:

Java:
import java.util.ArrayList;
import java.util.List;
 
//Die Klasse MapParser
 
public class MapParser{
	
	Element[][]spielfeld;
	
	
	
	
	//Implementiere das Spielfeld nur, wenn das übergebene Level valide ist.
	//Das wird vorher mit Hilfe der untenstehenden Methoden getestet.
    Element[][] parseMap(List<String> map){
        
    	spielfeld=new Element[map.size()][map.get(1).length()];   
                           char certainchar;
                           Element newElement;
                           int counter=0;
                           int counter2=0;
                           boolean sourrounded=false;
                           boolean equalLength;
                           
                           
                           for(int j=0; j<map.size(); j++){
                        	   
                               counter=countPlayer(map.get(j), 'P');
                               sourrounded=sourroundedByWalls(map.get(j));
                               counter2=countExists(map.get(j), 'G');
                               
                      }    
                           equalLength=equalLength(map);
                           
                   if(counter==1 && counter2>=1 && sourrounded==true && equalLength==true){       
                           
                           
                           
                           
 
        for(int i=0; i<map.size(); i++){
            
            for(int j=0; j<map.get(i).length(); j++){
            certainchar=map.get(i).charAt(i);
            switch(certainchar){
            
            case'P': newElement=new Player(i,j,this); spielfeld[i][j]=newElement; break;
            case'E': newElement=new Erde(i,j,this); spielfeld[i][j]=newElement;break; 
            case'S': newElement=new Stein(i,j,this); spielfeld[i][j]=newElement;break;
            case'M': newElement=new Monster(i,j,this); spielfeld[i][j]=newElement;break;
            case'D': newElement=new Diamant(i,j,this); spielfeld[i][j]=newElement;break;
            case'G': newElement=new Ausgang(i,j,this); spielfeld[i][j]=newElement;break;
            case' ': newElement=new LeeresFeld(i,j,this); spielfeld[i][j]=newElement;break;
            }
            
            
            }
        }
    
                    }
                   
                   else {System.out.println("Level ist nicht rechteckig; Spielfeld wurde nicht initialisiert.");
                   spielfeld=null;
                   }         
                   return spielfeld;
    }       


public char getSpielfeld(int i, int j){
	return spielfeld[i][j].getChar();
}

public void setSpielfeld(int i, int j, char k){
	
	Element newElement2;
	switch(k){
    
    case'P': newElement2=new Player(i,j,this); spielfeld[i][j]=newElement2; break;
    case'E': newElement2=new Erde(i,j,this); spielfeld[i][j]=newElement2;break; 
    case'S': newElement2=new Stein(i,j,this); spielfeld[i][j]=newElement2;break;
    case'M': newElement2=new Monster(i,j,this); spielfeld[i][j]=newElement2;break;
    case'D': newElement2=new Diamant(i,j,this); spielfeld[i][j]=newElement2;break;
    case'G': newElement2=new Ausgang(i,j,this); spielfeld[i][j]=newElement2;break;
    case' ': newElement2=new LeeresFeld(i,j,this); spielfeld[i][j]=newElement2;break;
    }
	
}

//Es folgen Methoden, die für den Test der Validität eines Levels benutzt werden.

//Zähle die Anzahl der Spieler.

public int countPlayer(String string, char aChar){

  int counter=0;

    for(int i=0; i<string.length(); i++){
            
               if(string.charAt(i)==aChar){
                      counter++;
                  }
        
     }

return counter;
}


//Teste, ob am Anfang und Ende eines Strings ein bestimmes Char steht.

public boolean sourroundedByWalls(String string){

   boolean sourrounded=true;

         if(string.charAt(0)!='W' || string.charAt(string.length()-1)!='W'){
                  sourrounded=false;
          }

     return sourrounded;
}


//Zähle die Anzahl der Ausgänge.

public int countExists(String string, char aChar){

  int counter2=0;

    for(int i=0; i<string.length(); i++){
            
               if(string.charAt(i)==aChar){
                      counter2++;
                  }
        
     }
        return counter2;

}

//Teste, ob alle Zeilen die gleiche Länge haben (Rechtecksform des Spielfelds)

public boolean equalLength(List<String> irg){
boolean equalLength=true;

int LengthOfLine=irg.get(0).length();
int LengthOfNextLine;

if(equalLength==true){

  for(int i=1; i<irg.size();i++){
      
      LengthOfNextLine=irg.get(i).length();
  
      if(LengthOfLine!=LengthOfNextLine){
             equalLength=false;
         }
      LengthOfLine=LengthOfNextLine;

}
 
}


return equalLength;

}
}
 
Zuletzt bearbeitet von einem Moderator:

babuschka

Top Contributor
Jetzt wird beim Ausführen von BoulderDash auch schon das Fenster geöffnet, wo ich die Spielwelten laden kann.

Allerdings scheint bei der Überprüfung der Validität was schiefzulaufen, denn wenn ich beispielsweise dieses Spielfeld lade:


WWWWWWWWWW
W EEPESW SW
W EEEE SS W
W S W
WMSSS EE W
W W
W D W
WE E E E W
WDSSSSGEE W
WWWWWWWWWW


Kommt die Ausgabe, daß dieses Feld nicht rechtreckig sei.
 

babuschka

Top Contributor
SORRY, die W sollen auch rechts untereinander stehen und es ist rechteckig, irgendwie bekomme ichs hier nicht dargestellt.




Ich nehme an, daß ich in der for-Schleife vergessen habe, die Werte jeweils zu addieren.

Also z.B.

Java:
counter=counter+countPlayer(map.get(j), 'P');
und daß die if-Bedingung deswegen nie erfüllt ist.
 
Zuletzt bearbeitet von einem Moderator:
G

Gast2

Gast
Könntest du deine Sourcen bitte mal anständig formatieren? Das kann doch so keiner lesen. Ich habs sogar gerade versucht... Aber das is so en durcheinander. Man sieht gar nit was wo in welchem Block drinne steht ...
 

babuschka

Top Contributor
Hat einer eine Idee warum

Java:
WWWWWWWWWW
WEEPESW SW
W EEEE SSW
W      S W
WMSSS  EEW
W        W
W   D    W
WE E E E W
WDSSSSGEEW
WWWWWWWWWW

und auch

Java:
WWWWWWWWWWWWWWWWWWWW
WEEEEEEEEESSSSEEESSW
WEEEEEEESS SSS SS  W
W  M               W
W EEEEEEEEEEESSSS  W
W P                W
WSSSSSSSSSSSS      W
WEEEEEEEEEEEEEEEEEEW
WEEEEEEEEEEEEEEEEEEW
W     D            W
WSSSSSSSSSSSSESESESW
WSESESESESESEEESESEW
WEEEESSSSEEEESSSSESW
W    D      S    S W
WSSSEE E E E E S E W
WEDSDSDSDSDSEEEEEEEW
W          D       W
W    G             W
WSSSSSSSSSSEDEEEEEEW
WWWWWWWWWWWWWWWWWWWW

eingelesen werden, aber bei

Java:
WWWWWWWWWWWW
WPSSSSSSSSSW
WEEEEEEEEEDW
WEEESSEEESSW
W          W
W  MSSSSSSSW
WEEEESSSEEEW
WSSSEEESS  W
W G        W
WDSSSSEESSSW
WWWWWWWWWWWW

die if-Bedingung offenbar nicht erfüllt ist, weil angezeigt wird:

"Level ist nicht valide..."?


Ich erkenne da keinen Unterschied bzw. Fehler.






PS. Sorry, ich werde den Code noch besser strukturieren, ich sehe ein, daß er sehr (!) chaotisch ist.
 
Zuletzt bearbeitet von einem Moderator:
F

Firephoenix

Gast
Wenn ich eh schon drüberlese... was solls:

Java:
import java.util.ArrayList;
import java.util.List;

public class MapParser {

	Element[][] spielfeld;

	Element[][] parseMap(List<String> map) {

		// Spielfeld hätte hier lokal angelegt werden können, wird global in der
		// Klasse nicht benötigt
		spielfeld = new Element[map.size()][map.get(1).length()];
		// Was ist ein certainchar? Sinnvolle Variablennamen wählen außerdem
		// nutzt du die Variable erst viel später
		// sie muss hier noch nicht angelegt werden
		char certainchar;
		// Selbiges, die Variable wird erst unten Benötigt
		Element newElement;
		// Namen passend wählen! Der erste counter
		// zählt die 'P' der 2. die 'G'
		// benenne sie entsprechend
		int counter = 0;
		int counter2 = 0;
		boolean sourrounded = false;
		// equallength kannst du komplett rauswerfen, du setzt den wert einmal
		// und prüfst ihn direkt dannach
		boolean equalLength;

		for (int j = 0; j < map.size(); j++) {

			/*
			 * Überleg dir einmal was die Funktion macht wenn deine Map 2 Zeilen
			 * hat: die 1. Zeile ist nicht surrounded und enthält ein P und ein
			 * G die 2. Zeile ist surrounded und enthält ebenfalls ein P und ein
			 * G Beim ersten durchlauf ist counter 1, surrounded false und
			 * counter 2 1 beim nächsten durchlauf überschreibst du alle
			 * variablen, counter ist wieder 1 sourrounded wäre true und counter
			 * 2 wäre 1. gültig ist die map trotzdem nicht
			 */
			counter = countPlayer(map.get(j), 'P');
			sourrounded = sourroundedByWalls(map.get(j));
			counter2 = countExists(map.get(j), 'G');

		}
		equalLength = equalLength(map);

		if (counter == 1 && counter2 >= 1 && sourrounded == true
				&& equalLength == true /*
										 * anstatt hier dein equalLength zu
										 * prüfen könntest du direkt den
										 * gleichnamigen Funktionsaufruf
										 * einsetzen
										 */) {

			for (int i = 0; i < map.size(); i++) {

				for (int j = 0; j < map.get(i).length(); j++) {
					// anstatt hier erst den char zwischenzuspeichern kannst du
					// auch direkt
					// den aufruf in das switch-statement einsetzen
					certainchar = map.get(i).charAt(i);
					switch (certainchar) {

					case 'P':
						// Auch hier kannst du direkt das new ... Zuweisen, das
						// Zwischenspeichern in newElement ist überflüssig
						newElement = new Player(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					case 'E':
						newElement = new Erde(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					case 'S':
						newElement = new Stein(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					case 'M':
						newElement = new Monster(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					case 'D':
						newElement = new Diamant(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					case 'G':
						newElement = new Ausgang(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					case ' ':
						newElement = new LeeresFeld(i, j, this);
						spielfeld[i][j] = newElement;
						break;
					}
					// Default-Block einfügen mit wenigstens einer Fehlermeldung
					// falls unbekannte Zeichen kommen

				}
			}

		}

		else {
			System.out
					.println("Level ist nicht rechteckig; Spielfeld wurde nicht initialisiert.");
			spielfeld = null;
		}
		return spielfeld;
	}

	// wird die methode hier überhaupt verwendet?
	// falls ja spielfeld in der klasse lassen, andernfalls raus damit
	public char getSpielfeld(int i, int j) {
		return spielfeld[i][j].getChar();
	}

	// Den Code habe ich oben schonmal gesehen, raus damit, entweder hier oder
	// oben
	public void setSpielfeld(int i, int j, char k) {

		Element newElement2;
		switch (k) {

		case 'P':
			newElement2 = new Player(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		case 'E':
			newElement2 = new Erde(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		case 'S':
			newElement2 = new Stein(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		case 'M':
			newElement2 = new Monster(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		case 'D':
			newElement2 = new Diamant(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		case 'G':
			newElement2 = new Ausgang(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		case ' ':
			newElement2 = new LeeresFeld(i, j, this);
			spielfeld[i][j] = newElement2;
			break;
		}

	}

	// Es folgen Methoden, die für den Test der Validität eines Levels benutzt
	// werden.

	// Zähle die Anzahl der Spieler.

	// Vergleich die Methode mal mit der countExists... mit passender benennung
	// countChars
	// wäre das nicht passiert, mit playern hat die Methode hier nämlich
	// garnichts zu tun.
	public int countPlayer(String string, char aChar) {

		int counter = 0;

		for (int i = 0; i < string.length(); i++) {

			if (string.charAt(i) == aChar) {
				counter++;
			}

		}

		return counter;
	}

	// Teste, ob am Anfang und Ende eines Strings ein bestimmes Char steht.

	// Der name kann irreführend sein, die Funktion prüft nur eine Zeile, also
	// besser lineSurroundedByWalls
	public boolean sourroundedByWalls(String string) {

		boolean sourrounded = true;

		if (string.charAt(0) != 'W'
				|| string.charAt(string.length() - 1) != 'W') {
			sourrounded = false;
		}

		return sourrounded;
	}

	// Zähle die Anzahl der Ausgänge.
	// Siehe oben, gibts schonmal - raus damit
	public int countExists(String string, char aChar) {

		int counter2 = 0;

		for (int i = 0; i < string.length(); i++) {

			if (string.charAt(i) == aChar) {
				counter2++;
			}

		}
		return counter2;

	}

	// Teste, ob alle Zeilen die gleiche Länge haben (Rechtecksform des
	// Spielfelds)

	// Wenn du der Methode eine leere Liste übergibst fliegt direkt eine
	// Nullpointerexception weil du direkt den Wert des 1. Elements abgreifst.
	// Lieber vorher abfangen, außerdem gibt es auch die möglichkeit
	// mehrere return zu verwenden und die Methode früher abzubrechen, ich hab
	// dir dazu unten einen Vorschlag angefügt
	public boolean equalLength(List<String> irg) {
		boolean equalLength = true;

		int LengthOfLine = irg.get(0).length();
		int LengthOfNextLine;

		if (equalLength == true) {

			for (int i = 1; i < irg.size(); i++) {

				LengthOfNextLine = irg.get(i).length();

				if (LengthOfLine != LengthOfNextLine) {
					equalLength = false;
				}
				LengthOfLine = LengthOfNextLine;

			}

		}

		return equalLength;

	}

	public boolean allElementsEqualLength(List<String> strings) {
		if (strings.isEmpty()) {
			return true;
		}
		int lastLineLength = strings.get(0).length();
		
		for (int i = 1; i < strings.size(); i++) {
			int actualLineLength = strings.get(i).length();
			if(actualLineLength != lastLineLength){
				return false;
			}
			lastLineLength = actualLineLength;
		}
	}
}
 

babuschka

Top Contributor
Oh, vielen lieben Dank für diese Mühe.

Ich frage zuerst etwas nach zu Zeile 32-39.

Also bei counter und counter2 muss ich dann wohl dies hier machen:


Java:
counter=counter+countPlayer(map.get(j), 'P');
counter2=counter2+countExists(map.get(j), 'G');

So gehen die Ergebnisse jeweils nicht verloren, sondern werden aktualisiert.

Etwas Ähnliches versuche ich mir gerade für das sourrounded zu überlegen.


Meine Idee hierfür ist:

Java:
sourrounded=sourroundedByWalls(map.get(j)) && sourroundedByWalls(map.get(j-1));

Wobei ich gerade nicht sicher bin, ob man das machen kann, weil man ja dann zum Beispiel für j=0 einen nicht zulässigen Wert hätte (-1).


Vielleicht die Schleife bei 1 anfangen lassen und entsprechend anpassen:

Java:
for(int j=1; j<=map.size(); j++){
                        	   
                               counter=counter+countPlayer(map.get(j-1), 'P');
                   sourrounded=sourroundedByWalls(map.get(j)) && sourroundedByWalls(map.get(j-1));
                               counter2=counter2+countExists(map.get(j-1), 'G');
                               
                      }




Eine andere Idee von mir, die mir irgendwie sympathischer ist, ist:

Java:
for(int j=0; j<map.size(); j++){
                               
                               counter=counter+countPlayer(map.get(j), 'P');
                               if(counter>1){break;}
                               sourrounded=sourroundedByWalls(map.get(j));
                               if(sourrounded==false){break;}
                               counter2=counter2+countExists(map.get(j), 'G');
                               
                      }

daß man die Schleife also einfach verlässt, wenn die Anzahl der Spieler größer als 1 ist oder sourrounded in irgendeiner Zeile false ist.






Habe aber dennoch keine Ahnung, warum bei meiner dritten Map die if-Bedingung nicht gilt und ausgegeben wird: "nicht valide..."
 
Zuletzt bearbeitet von einem Moderator:
G

Gast2

Gast
Da macht sich schon jemand die Mühe und reformatiert deinen Source, schreibt dir überall Kommentare rein und im nächsten Post sind deine Sourcen wieder wie Kraut und Rüben...

Merkst du was?
 

Sonecc

Gesperrter Benutzer
Ich mach dir ausnahmsweise mal deine Methode wie du prüfen kannst, ob das Level von Wänden umgeben wurde oder nicht. Sei dir Gewiss, dass das eine absolute Seltenheit bei mir ist, dass ich praktisch eine Lösung einer Aufgabe präsentiere
Beachte, dass sie gleichzeitig auch prüft, ob die Reihen des Levels gleichlang sind
Ich habe mit Absicht jede Zeile des Codes kommentiert, in der Hoffnung du kopierst es nicht einfach
sondern denkst darüber nach und überlegst dir genau, warum ich was an welcher Stelle gemacht habe.
Auf diese Weise kannst du vielleicht auch deine Konzeptionellen Probleme erkennen und verbessern.

Java:
/**
 * Checks the map if it is surrounded by walls and 
 * if its rows have an equal size
 * @param map the list of rows of the map to test
 * @return true if the level is surrounded by walls 
 * and if the rowsizes are ok
 */
public static boolean checkWallsAndForm(List<String> map) {
	//All other rows have to have this value
	int lastCol = map.get(0).length()-1; 
	//Run through all rows of the map
	for (int i = 0; i < map.size(); i++) {
		//Get the current row
		String row = map.get(i);
		//Last Column index of this row
		int rowsLastCol = row.length() - 1;
		//If it is not equal to lastCol, the row has
		//different size then the first row had
		if (rowsLastCol != lastCol) {
			//Not valid row, return false
			return false;
		}
		//First and last row must not contain any other char than 'w'
		if (i == 0 || i == map.size() - 1) {
			//Check every entry of the row
			for (int j = 0; j < row.length(); j++) {
				//Only W is allowed
				if (row.charAt(j) != 'W') {
					//Row invalid, return false
					return false;
				}
			}
		} else {
			//All other rows must have a 'W' at the beginning and the end
			if (row.charAt(0) != 'W' || row.charAt(lastCol) != 'W') {
				//Row does not start or end with an 'W', return false
				return false;
			}
		}
	}
	//Everything ok, return true
	return true;
}
 

babuschka

Top Contributor
Ich habe schon einige der Tipps, die mir Firephoenix gegeben hat, versucht umzusetzen. Zum Beispiel habe ich die Methoden, die die Anzahl der Spieler und der Ausgänge zählen, zu einer zusammengefasst.

Auch habe ich meine Methoden, die die Rechtecksform und das Umgebensein von Wänden testen, durch die von Sonecc ersetzt (ich habe sie zwar übernommen, sie aber nicht nur einfach gedankenlos kopiert). Dann sieht es zumindest schonmal so aus:

Java:
import java.util.ArrayList;
import java.util.List;
 
public class MapParser{
    
	Element[][] spielfeld;
    
        Element[][] parseMap(List<String> map){
        
        spielfeld=new Element[map.size()][map.get(1).length()];   
        char certainchar;
        Element newElement;
                           
                           
         if(countChars(map,'P')==1 && countChars(map,'G')>=1 && checkWallsAndForm(map)==true){       
                           
                           
                           
                           
 
        for(int i=0; i<map.size(); i++){
            
            for(int j=0; j<map.get(i).length(); j++){
            certainchar=map.get(i).charAt(i);
            switch(certainchar){
            
            case'P': newElement=new Player(i,j,this); spielfeld[i][j]=newElement; break;
            case'E': newElement=new Erde(i,j,this); spielfeld[i][j]=newElement;break; 
            case'S': newElement=new Stein(i,j,this); spielfeld[i][j]=newElement;break;
            case'M': newElement=new Monster(i,j,this); spielfeld[i][j]=newElement;break;
            case'D': newElement=new Diamant(i,j,this); spielfeld[i][j]=newElement;break;
            case'G': newElement=new Ausgang(i,j,this); spielfeld[i][j]=newElement;break;
            case' ': newElement=new LeeresFeld(i,j,this); spielfeld[i][j]=newElement;break;
            default: System.out.println("No valid letter.");
            }
            
            
            }
        }
    
                    }
                   
                   else {System.out.println("Level is not valid.");
                   spielfeld=null;
                   }    
                           
                           
                           
                   return spielfeld;
    }       
 
 
public char getSpielfeld(int i, int j){
    return spielfeld[i][j].getChar();
}
 
public void setSpielfeld(int i, int j, char k){
    
    Element newElement2;
    switch(k){
    
    case'P': newElement2=new Player(i,j,this); spielfeld[i][j]=newElement2; break;
    case'E': newElement2=new Erde(i,j,this); spielfeld[i][j]=newElement2;break; 
    case'S': newElement2=new Stein(i,j,this); spielfeld[i][j]=newElement2;break;
    case'M': newElement2=new Monster(i,j,this); spielfeld[i][j]=newElement2;break;
    case'D': newElement2=new Diamant(i,j,this); spielfeld[i][j]=newElement2;break;
    case'G': newElement2=new Ausgang(i,j,this); spielfeld[i][j]=newElement2;break;
    case' ': newElement2=new LeeresFeld(i,j,this); spielfeld[i][j]=newElement2;break;
    }
    
}
 
//The following methods are used to check if the level is valid.
 
//Count the number of a certain char in each row.
 
public int countChars(List<String> map, char aChar){
 
  int counter=0;
 
    for(int i=0; i<map.size();i++){
    	
    	for(int j=0; j<map.get(i).length();j++){
    	
               if(map.get(i).charAt(j)==aChar){
                      counter++;
                  }
        }
    	
    }	
 
return counter;
}
 

//Check if the level is sourrounded by walls and if it is rectangular.

public static boolean checkWallsAndForm(List<String> map) {
    
    int lastCol = map.get(0).length()-1; 
    
    for (int i = 0; i < map.size(); i++) {
        
        String row = map.get(i);
        
        int rowsLastCol = row.length() - 1;
        
        if (rowsLastCol != lastCol) {
            
            return false;
        }
        
        if (i == 0 || i == map.size() - 1) {
            
            for (int j = 0; j < row.length(); j++) {
                
                if (row.charAt(j) != 'W') {
                    
                    return false;
                }
            }
        } else {
            
            if (row.charAt(0) != 'W' || row.charAt(lastCol) != 'W') {
                
                return false;
            }
        }
    }
    
    return true;
}  
   
 
         

  


}



Die restlichen Tipps zur Verbesserung von Firephoenix konnte ich leider noch nicht umsetzen.

Zum Beispiel bereiten mir die Methoden setSpielfeld und getSpielfeld Probleme; ich benutze diese ja u.a. in der Klasse Player und weiß daher nicht, ob ich sie jetzt einfach aus MapParser rausnehmen sollte.





Achso: Mein Level 3 wird immer noch als "nicht valide" zurückgewiesen.
 
Zuletzt bearbeitet von einem Moderator:

Sonecc

Gesperrter Benutzer
erstmal, die Formatierung ist noch immer grottig... bitte achte doch darauf, bevor du code postest, da so niemand wirklich was lesen kann

Achso: Mein Level 3 wird immer noch als "nicht valide" zurückgewiesen.



Wenn ich deinen Code kopiere und es auf die Maps anwende, wird bei mir angegeben, dass diese valide sind.

Dementsprechend ist dein Problem nicht nachvollziehbar

[edit]
Lustig, dass du den JavaDoc entfernst und durch einen eigenen kommentar ersetzt, der fehler enthält^^

surrounded wird nicht sourounded geschrieben...
[/edit]
 
Zuletzt bearbeitet:

babuschka

Top Contributor
Wenn ich deinen Code kopiere und es auf die Maps anwende, wird bei mir angegeben, dass diese valide sind.

Dementsprechend ist dein Problem nicht nachvollziehbar


Also ich mache es so (vllt. ist die Vorgehensweise ja verkehrt):

Ich lasse MapParser und BoulderDash kompilieren.

Dann führe ich Boulderdash aus: java Boulderdash


Dann öffnet sich ein Fenster, wo ich die Maps auswählen kann.

Wähle ich Spielwelt1.txt oder Spielwelt2.txt dauert es eine Weile. Ansonsten passiert nichts.



Wähle ich aber Spielwelt3.txt kommt eben "Level is not valid."
 

Sonecc

Gesperrter Benutzer
dann gib mal deine Spielwelt3.txt
Nehme ich nämlich das Spielfeld, dass du in einem deiner vorherigen Posts stehen hast, wird dieses als richtig erkannt. (was ja auch richtig ist)
 

babuschka

Top Contributor
Ich meine die Spielwelt ist sogar schon unter denen, die ich oben gepostet hatte.

Also sie sieht so aus:

Java:
WWWWWWWWWWWW
WPSSSSSSSSSW
WEEEEEEEEEDW
WEEESSEEESSW
W          W
W  MSSSSSSSW
WEEEESSSEEEW
WSSSEEESS  W
W G        W
WDSSSSEESSSW
WWWWWWWWWWWW
 

Sonecc

Gesperrter Benutzer
...
Ok, etwas deutlicher...
Lade bitte mal deine Spielwelt3.txt Datei als Dateianhang hier hoch.

Dass du das hier schonmal gepostet hast, habe ich hiermit ausgedrückt:

Nehme ich nämlich das Spielfeld, dass du in einem deiner vorherigen Posts stehen hast, wird dieses als richtig erkannt. (was ja auch richtig ist)


Also bitte ... Lade deine DATEI hoch. Nicht hier reintippen, sondern hochladen...
 

Sonecc

Gesperrter Benutzer
Die Datei wird deswegen nicht als valide erkannt, weil die letzte Zeile in der Datei Leerzeichen am Ende enthält.

Statt

Code:
WWWWWWWWWWWW

steht dort (_ sind leerzeichen)

Code:
WWWWWWWWWWWW__________


Edit:

Hier mal eine verbesserte Version die mit solchen fehlerhaften Dateien umgehen kann

Java:
/**
 * Checks the map if it is surrounded by walls and 
 * if its rows have an equal size
 * @param map the list of rows of the map to test
 * @return true if the level is surrounded by walls 
 * and if the rowsizes are ok
 */
public static boolean checkWallsAndForm(List<String> map) {
	//All other rows have to have this value
	int lastCol = map.get(0).length()-1; 
	//Run through all rows of the map
	for (int i = 0; i < map.size(); i++) {
		//Get the current row
		String row = map.get(i);
		//Remove beginning and trailing whitespaces  <----- new line
		row = row.trim();                                     //<----- new line
		//Last Column index of this row
		int rowsLastCol = row.length() - 1;
		//If it is not equal to lastCol, the row has
		//different size then the first row had
		if (rowsLastCol != lastCol) {
			//Not valid row, return false
			return false;
		}
		//First and last row must not contain any other char than 'w'
		if (i == 0 || i == map.size() - 1) {
			//Check every entry of the row
			for (int j = 0; j < row.length(); j++) {
				//Only W is allowed
				if (row.charAt(j) != 'W') {
					//Row invalid, return false
					return false;
				}
			}
		} else {
			//All other rows must have a 'W' at the beginning and the end
			if (row.charAt(0) != 'W' || row.charAt(lastCol) != 'W') {
				//Row does not start or end with an 'W', return false
				return false;
			}
		}
	}
	//Everything ok, return true
	return true;
}
 
Zuletzt bearbeitet:

Sonecc

Gesperrter Benutzer
Und wieder hab ich das gefühl du leistest keine bis kaum eigenarbeit...

Wenn du meine veränderte Methode übernimmst, musst du die Veränderung auch in deine anderen Methoden übernehmen...
Entweder du lässt es zu, dass die Datei leerzeichen am Ende enthält, dann musst du aber auch überall darauf achten, dass das passieren kann, oder du lässt es nicht zu.
Überleg dir selbst was du willst. Was du nun machen musst, sage ich dir jedenfalls nicht, darauf kann und solltest du selbst kommen, wenn du die Methode wirklich nicht einfach nur stur kopiert hast, sondern auch darüber nachgedacht hast. (was ich übrigens nicht glaube)
 

babuschka

Top Contributor
Okay, ich versuche es zu verstehen!

Deine neue Methode zeichnet sich doch jetzt dadurch aus, daß die Zeilen vorher und hinterher keine Leerstellen mehr haben.


Und Du meinst, daß ich jetzt daß auch bei der Methode, die Player und Exist zählt, so machen muss, wenn ich diese neue Methode verwenden will?



Oder bei welchen Methoden muss ich das dementsprechend auch anpassen?
 

babuschka

Top Contributor
Ja, das mache ich.

Aber auch da muss ich leider noch eine Frage stellen.

Wie entferne ich die?


Also Du meinst doch die Leerzeilen, die Du als ______ gekennzeichnet hast.

Innerhalb des Spielfelds dürfen ja Leerzeichen sein, nur am Ende der Zeilen nicht. Aber wie entferne ich die?
 

babuschka

Top Contributor
Okay, das war ein Missverständnis.


Jetzt habe ich die Leerzeilen am Ende gelöscht und auch bei 3 kommt jetzt nicht mehr die Meldung, es sei nicht valide.



Aber ich habe schon wieder eine andere Frage.


Wenn ich bei der Erzeugung des Spielfeld einen default-Zweig dazu nehme, scheint IMMER der angesprungen zu werden, wenn ich zum Beispiel Spielwelt1 dann lade, wird entsprechend der Anzahl der Zeilen dieser default-Zweig angesprungen.


Was ist denn da wieder verkehrt?
 

Sonecc

Gesperrter Benutzer
Schau dir dein switch statement doch mal genau an. Da fehlt etwas
Der Buchstabe W wird dort nie abgefragt, damit springt er in den default
 
Zuletzt bearbeitet:

R3van

Mitglied
Ich möchte nochmals darauf hinweisen, dass wenn du (Java_) Lösungen dieses Forums mit in deine Abgabe nimmst, und ja das sind eindeutig Lösungen zu den Aufgaben, dann musst du dies kenntlich machen. Ein Verstoß kann zum Ausschluss der Veranstaltung und einem Eintrag in die Prüfungsakte führen. Du kannst zudem sehr sicher sein, dass wir diese Abgabe sehr genau prüfen werden.
 

babuschka

Top Contributor
In Ordnung, wie kennzeichne ich das richtig, sodaß keine Schwierigkeiten entstehen?

Und: Was muss ich alles kennzeichnen? Es ist ja nicht so, daß nichts von mir stammen würde.

Würde es reichen, wenn ich ganz am Anfang schreibe, daß ich hier Hilfe bekommen habe (und den Link gebe) und dann an den Stellen jeweils schreibe: s. Link?

Oder wäre das zu unpräzise?



PS. Es ist absolut nicht meine Absicht, irgendwas zu verwenden und das ungekennzeichnet zu lassen.
 
Zuletzt bearbeitet von einem Moderator:

babuschka

Top Contributor
Die eine Methode wurde mir verraten, ja, das stimmt.

Das muss ich also kennzeichnen, das sehe ich ein und ist nur fair.

Aber alles Vorherige habe ich mir ja selbst erarbeitet, muss ich das auch alles kennzeichnen???




Der Austausch über Foren ist okay, wurde mir gesagt und alles (bis auf die verratene Methode) hier war Austausch - meines Ermessens.
 

babuschka

Top Contributor
Bitte keine Unterstellungen!

Ich wollte weder mogeln noch war es meine Hoffnung, "dass es keiner merkt".

Im Gegenteil weise ich in meiner Ausarbeitung explizit darauf hin, daß mir hier geholfen wurde!!!
 

timbeau

Gesperrter Benutzer
Ich finde nicht, dass es soo erschlichen war. Er hat auf jeden Fall auch viel Energie reingesteckt & mir gings am Anfang meines Studiums ähnlich. Neben Softwareentwicklern die noch nen Bachelor machen sieht man als Abiturient oft alt aus, zumindest am Anfang und ohne jetzt die große Affinität zum programmieren.

Aber die Tutoren sollte man schon anders erreichen.
 

babuschka

Top Contributor
Ich glaube, das hier ein Missverständnis vorliegt.

Es ist keineswegs so, daß dies mein Weg ist, um mit meinem Tutor zu kommunizieren.



Was kann ich dafür, wenn sich ein Tutor hier anmeldet und mich kontaktiert?

(Was ich übrigens sehr nett fand!)




Und ich möchte auch nochmal darauf hinweisen, daß mir hier nichts geschenkt wurde und alles von mir stammt (bis auf EINE Methode, die mir in der Tat vorgelegt wurde!). Ansonsten wäre die Diskussion wohl auch nicht so lang ausgefallen: Hätte man mir Musterlösungen vorgegeben, sähen die wohl auch viel besser und professioneller aus!!

Also bitte bringt mich nicht unnötig in Schwierigkeiten, indem Sachen behauptet werden, die nicht stimmen.



PS. Im Gegenteil: Die Tutoren sind sehr gut zu erreichen, da ist überhaupt nichts auszusetzen, bisher wurde mir immer kompetent geholfen.
 
Zuletzt bearbeitet von einem Moderator:

Sonecc

Gesperrter Benutzer
Erschlichen hat er sich wirklich nichts. Als ich ihm die Methode geschrieben hatte, war meine Hoffnung, dass er an dem Stück Code das formatieren und das konzeptionelle Arbeiten etwas lernt. Er muss nunmal die Vorgehensweise und die Denkweise erlernen, die man als Entwickler benötigt und der sehr ausführlich dokumentierte Code sollte ihm das näher bringen.
Ich hatte die Hoffnung, dass er sich richtig damit beschäftigt und versucht nachzuvollziehen, wieso ich wann und was gemacht habe und dadurch eben etwas lernt.

Erschlichen hat er sich da nichts, nur etwas geschenkt bekommen. Dass er den Code nicht 1 : 1 kopieren soll, hatte ich ja angemerkt um eben genau das Problem zu verhindern, dass solche Vorwürfe aufkommen. Ob und wie er sich daran gehalten hat, kann ich nicht sagen, dass er darauf aber, wie er sagt, hinweist ist schon eine nette Geste, die ihm wohl nicht viel bringen wird.

Aber interessant zu sehen, dass Jango sich wieder einmischt. Man kann ja meckern, da lohnt es sich immer. Nur nie helfen oder ähnliches. Das wäre langweilig. Schade nur, dass sie diesmal keine Ahnung hatte, worum es überhaupt geht, aber das ist ja auch nicht soooo selten...
 

Neue Themen


Oben