Java Schiffe versenken: Endlosschleife

Marcellus

Newbie
Registriert
Nov. 2009
Beiträge
7
Hallo!

Bin grade dabei mir java beizubringen und bin mittlerweile bei Objekten angelangt, Theorie geht halbwegs aber in der Praxis häng ich noch..., jedenfalls will ich "Schiffe versenken" in einer abgespeckten Variante schreiben. Ich habe jetzt das Problem, dass das Programm beim Anlegen (also dem Verteilen auf dem Spielfeld) der Schiffe in einer Endlosschleife läuft.

Ich füg hier mal den Code ein von dem ich denke dass der fehler irgendwo dort liegt, vermutlich fehlt wo ein return oder sonst was, aber ich komm einfach nicht drauf. Wenn wer sieht woran es liegt würde ich mich über einen Hinweis freuen ;).

Code:
public class Battleships {
	// decare global cnst
	public static final int MAX_SHIPS = 10;
	public static final int MAX_HITS = 4 * 2 + 3 * 3 + 2 * 4 + 1 * 5; // 30 hits
	public static final int MIN_SHIP_LENGTH = 2;
	public static final int MAX_SHIP_LENGTH = 5;
	public static final int FIELDSIZE = 20;

	private static Ship[] ships = new Ship[MAX_SHIPS];
	private static Field[][] water = new Field[20][20];

	// private static private static Random rand;

	public static void main(String[] args) {
		boolean ok = false;
		for (int i = 0; i < FIELDSIZE; i++) {
			for (int j = 0; j < FIELDSIZE; j++) {
				water[i][j] = new Field(i, j);
			}
		}
		for (int k = 0; k < 4; k++) {
			while (!ok) {
				if (placeShip(2)) {
					ok = true;
				}

			}
			ok = false;
		}

		for (int z = 0; z < 3; z++) {
			while (!ok) {
				if (placeShip(3)) {
					ok = true;
				}

			}
			ok = false;
		}

		for (int w = 0; w < 2; w++) {
			while (!ok) {
				if (placeShip(4)) {
					ok = true;
				}

			}
			ok = false;
		}

		while (!ok) {
			if (placeShip(5)) {
				ok = true;
			}
		}
		//game();
	}

	public static boolean placeShip(int len) {
		int x, y;
		boolean horiz;
		IO.write("again");
		if (random('h') == 0) {
			horiz = true;
		} else {
			horiz = false;
		}
		x = random();
		y = random();

		int i = 0;
		while (ships[i] != null) {
			i++;
		}

		if (isPlaceable(x, y, len, horiz)) {
			Field[] arr = new Field[len];
			IO.writeLn("ok");
			for (int j = 0; j < len; j++) {
				if (horiz)
					arr[j] = water[x][y + j];
				else
					arr[j] = water[x + j][y];
			}
			ships[i] = new Ship(arr);
			water[x][y].ship = ships[i];
			for (int k = 0; k < (len - 1); k++) {
				if (horiz) {
					x++;
				} else {
					y++;
				}
				water[x][y].ship = ships[i];
			}

		} else {
			// placeShip(len);
			return false;
		}
		return true;

	}

	public static boolean isPlaceable(int x, int y, int len, boolean horiz) {
		if (water[x][y].getShip()) {
			return false;
		} else {
			IO.writeLn(x + " " + y);
			for (int i = 0; i < (len - 1); i++) {
				if (horiz) {
					x++;
				} else {
					y++;
				}
				if ((x > 19) || (y > 19)) {
					return false;
				}
				if (water[x][y].ship != null) {
					return false;
				}
			}
		}
		return true;
	}

	public static int random() {
		int rndm = (int) (Math.random() * 20);
		return rndm;
	}

	public static int random(char h) {
		int rndm = (int) (Math.random() * 2);
		return rndm;

	}

Code:
public class Field {
	private int x, y;
	private static boolean hit = false;
	public static Ship ship = null;

	public Field(int x, int y) {
		this.x=x;
		this.y=y;
	}
	
	public static boolean getShip() {
		if (ship != null) {
			return true;
		} else {
			return false;
		}
	}
	public static boolean getHit() {
		if(hit==true){
			return true;
		}else {
			return false;
		}
	}

Code:
public class Ship {
	private Field[] deck;

	public Ship(Field[] deck) {
		deck = deck;
	}

ist nur ein Auszug, also nicht drüber wundern, dass die Klassen nicht abgeschlossen sind und noch andere Dinge drinstehen etc., aber hier sollte der Fehler liegen...
Einige Ausgaben sind nur zu Kontrollzwecken.
Die IO class ist ok und ersetzt nur System.out etc.

Exceptions kommen keine, er läuft einfach ins Nichts...

Tja, das war's, wenn wer bis hier gelesen hat: meinen Glückwunsch ;)
lG
 
Hast du schonmal versucht das ganze zu Debuggen, und immer wieder Haltemarken etc. zu setzen und dich dann schrittweise durch das Programm zu "hangeln"?

Gruß,

badday
 
Hi,

ja, da ich ohnehin in Eclipse arbeite hab ich natürlich schon versucht zu debuggen, bin Schritt für Schritt durchgegangen, sobald ich jedoch zu dem Punkt komme, an dem PlaceShip() aufgerufen wird, rechnet er nurnoch ohne Ausgabe...

lG

Edith sagt: ich sollte vielleicht erwähnen, dass ich vom Debuggen auch nicht viel Ahnung habe, habe halt Breakpoints gesetzt und mich sonst durchgeklickt und geschaut was die Variablen für Werte haben, also nicht sehr profi-like...
Habs gestern zum ersten Mal probiert eben wegen dieses Fehlers
 
Zuletzt bearbeitet:
Also du hast oben von einer Endlosschleife gesprochen. Das würde doch dann heißen, dass du die Schleife durch das Debuggen lokalisieren kannst, oder verstehe ich das falsch?

Gruß,

badday
 
Also, ich hab das Debuggen nochmal probiert, hatte bisher tatsächlich immer etwas falsch gemacht... jedenfalls scheint es so, als würde getShip() immer true ergeben, wodurch die isPlaceable() false zurückgibt und somit kommt man nicht voran, ist diese getShip() jetzt falsch? (ist eben mein erstes "wirkliches" Objekt, bin da noch sehr unsicher wie was genau geht...)
 
Probiere vielleicht mal beim erstellen des Arrays alle Objekte mit null zu initialisieren.

Hab leider gerade wenig Zeit, sonst hätte ich mir das genauer angeschaut.
Viel Glück.

Gruß,

badday
 
ok, trotzdem danke!

soweit ich es verstanden habe, müsste es ja schon bei Initialisierung des Objekts auf null gesetzt werden, da die Variable in der class ja mit null steht...

vielleicht hat ja sonst noch jemand eine Idee...

lG
 
jedenfalls scheint es so, als würde getShip() immer true ergeben, wodurch die isPlaceable() false zurückgibt und somit kommt man nicht voran

Genau, hab mir mal die Mühe gemacht das durchzuschauen. Der Fehler liegt in der Wahl der Variablen der Klasse Field. Du willst scheinbar für jedes Feld speichern ob dort ein Schiff liegt (public static Ship ship = null), verwendest aber eine Klassen-Variable (static), die nach einmaligem setzen ihren im gesamten Programm einheitlichen Wert behält. Ändere das mal in private.
 
ok, ich hoffe ich hab das jetzt richtig verstanden, hab in der Field class die ship variable auf private geändert und als Ersatz eine setShip() geschrieben
Code:
public class Field {
	private int x, y;
	private static boolean hit = false;
	private static Ship ship = null;

	public Field(int x, int y) {
		this.x=x;
		this.y=y;
	}
	
	public static boolean getShip() {
		if (ship != null) {
			return true;
		} else {
			return false;
		}
	}
	public static void setShip(Ship s) {
		ship=s;
	}

habs dann wieder Schritt-für-Schritt debugged, aber gleiches Ergebnis bekommen, getShip() wird immer true...

wenn was anderes gemeint war bitte noch einmal erklären
 
Also was ich beim Debugger sehen konnte ist:

Das Programm hängt in dieser Schleife fest:

Code:
			while (!ok) {
				if (placeShip(2)) {
					ok = true;
				}

			}

Dabei gibt placeShip(2) immer false zurück, und "ok" bleibt false, was durch die Negation in der Schleifen-Bedingung eine Endlosschleife ergibt.

placeShip() liefert false, weil diese Bedingung Fehlschlägt:

Code:
		if (isPlaceable(x, y, len, horiz)) {

Und die wiederrum bekommt ihr False aus:

Code:
		if (water[x][y].getShip()) {
			return false;

Das ganze passiert wenn ich es richtig sehe ab dem zweiten Durchlauf. Kann es sein das beim platzieren des Schiffes was schief geht? Werden nach dem ersten Durchlauf überall Schiffe platziert und desshalb können keine weiteren Schiffe mehr gesetzt werden?

Das wär zumindest so meine Vermutung. Lass dir am besten an ausgewählten Stellen (zB wenn ein Schiff platziert wurde) die Karte ausgeben.

/edit

P.s: Meine Antwort bezieht sich auf den Code vor deiner Antwort um 17:50, das danach habe ich nicht angeguckt.
P.p.s: Etwas mehr Kommentierung und sprechender Code könnte übrigends nicht schaden. ;) Wenn man ausführlich kommentiert und sich nochmal klar darüber wird was welcher Code-Block tun soll findet man manchmal auch Fehler. Und eine Variable "ok" ist nicht sehr sprechend.
 
Zuletzt bearbeitet:
ja, das ist es, es werden bei sämtlichen Felder ship's gesetzt, ok, Fehler gefunden, jetzt bleiben die Fragen:
1) warum? und
2) wie bieg ichs hin?

soweit jedenfalls schonmal danke!

lG
 
Mache mal folgendes, implementier dir diese Funktion: (oder kopier sie..)

Code:
	/**
	 * Gibt die Karte aus. Koordinaten an denen sich ein Schiff befindet werden
	 * mit einem + markiert, freie Flaechen mit 0.
	 */
	private static void printMap() {
		
		for(int i = 0; i < water.length-1; i++) {
			
			String line = "";
			
			for(int j = 0; j < water[0].length-1; j++) {
				
				if(water[i][j].getShip()) {
					line = line + '+';
				} else {
					line = line + '0';
				}
				
			}
			System.out.println(line);
		}
	}

Bau den Funktionsaufruf ein:

Code:
		for (int k = 0; k < 4; k++) {
			while (!ok) {
				if (placeShip(2)) {
					ok = true;
				}
				printMap();  // Karte ausgeben, an diese Stelle BREAKPOINT setzen!

			}
			ok = false;
		}

Und setze dir den Breakpoint an den Punkt wo die Karte ausgegeben wird. Dann führe das ganze mal im Debuggen aus. Du wirst sehen das die ganze Karte "voller Schiffe" ist. Also läuft etwas beim setzen des ersten Schiffes schief. Was musst du nun aber selber finden, da habe ich nicht nach geguckt. :p
 
so, jetzt ist es klar, ich war blind und hatte übersehen dass ship auf static gesetzt war, jetzt geht alles wunderbar ;)

danke für die Hilfe!
 
Zurück
Oben