SchiffeVersenken

Hallo erstmal:)
Ich lerne jetzt seit ca. einem Jahr Java und wir (also meine Klasse) sind grade dabei ein Schiffe Versenken zu programmieren. Ich komme bei dem automatischen Schiffe setzen nicht weiter, bzw bei dem Prüfen ob der Hof des Schiffes frei ist.

Hier mal mein Code:

 public boolean pruefeHof(int startX, int startY, int laenge, boolean lage) {
        int breite = 3;

        if (lage) { //waagerecht  ,
            for (int y = startY - 1; breite > 0; breite--, y++) {
                int xLaenge = laenge + 2;
                for (int x = startX - 1; xLaenge > 0; xLaenge--, x++) {
                    if (spielDaten[x][y] != 0) {
                        return false;
                    }
                }
            }
        } else { //senkrecht
            for (int x = startX - 1; breite > 0; breite--, x++) {
                int xLaenge = laenge + 2;
                for (int y = startY - 1; xLaenge > 0; xLaenge--, y++) {
                    if (spielDaten[x][y] != 0) {
                        return false;
                    }
                }
            }
        }

        return true;

    }

Und jetzt noch das Alle Schiffe setzen programm:

public void setzeAlleSchiffe() {
        int laenge = 3;
        for (int anz = 5; anz >= 0; anz--) {
            boolean lage = wuerfel.nextBoolean();
            if (lage) { //waagerecht
                do {
                    int startX = wuerfel.nextInt((12 - (laenge + 1)) - 2) + 2;
                    int startY = wuerfel.nextInt((12 - 2) - 2) + 2;

                } while (pruefeHof(startX, startY, laenge, true));
            } else { //senkrecht
                do {
                    int startX = wuerfel.nextInt((12 - 2) - 2) + 2;
                    int startY = wuerfel.nextInt((12 - (laenge + 1)) - 2) + 2;

                } while (pruefeHof(startX, startY, laenge, false));

            }
        }
    }

Entschuldigung falls ich nerve, aber ich weiß echt nicht was ich falsch mach… Vielleicht liegt das auch daran, dass ich jetzt seit 2Tagen nur noch diesen Code anstarre. Ich sollte wirklich mal ne Pause machen
Und danke im Vorraus

was ist ein ‚Hof eines Schiffes‘?
was genau machen deine Methoden, was genau geht nicht?
alles beschreiben

wenn Zufall dabei ist (würfel), dann ist das für Untersuchungen immer ungünstig,
Thema könnte enden wie dieses hier zuletzt :wink:

verwende wenigstens new Random(42) oder so für konstante Resultate

verwende System.out.println() um dir alles auszugeben, was ist der Stand des spielDaten-Arrays?
welche x/y-Felder werden alles in einem Durchgang abgefragt, inwiefern gefällt dir das Ergebnis nicht?

Soo hab nochmal drübergescheut und Sachen überarbeitet das Pruefe Hof sieht jetzt so aus

public boolean pruefeHof(int startX, int startY, int laenge, boolean lage) {
        int breite = 3;

        if (lage) { //waagerecht  ,
            for (int y = startY - 1; breite > 0; breite--, y++) {
                int xLaenge = laenge + 2;
                for (int x = startX - 1; xLaenge > 0; xLaenge--, x++) {
                    if (spielDaten[x][y] != 0) {
                        return false;
                    }
                }
            }
        } else { //senkrecht
            for (int x = startX - 1; breite > 0; breite--, x++) {
                int xLaenge = laenge + 2;
                for (int y = startY - 1; xLaenge > 0; xLaenge--, y++) {
                    if (spielDaten[x][y] != 0) {
                        return false;
                    }
                }
            }
        }

        return true;

    }

Ich werde das auch im Main Part nochmal überarbeiten, damit es jeder als erstes list, das hier ist nur für den Fall, dass es schon welche gelesen haben.

*** Edit ***

Also, dann muss ich das wohl erklären xD
Der pruefeHof part prüft, ob die Umliegenden Felder des Arrays bereits mit einem Schiff (!=1 bei der if-Abfrage) schon mit einem Schiff belegt sind, damit das UP die Schiffe mit mindestens einem Feld abstand setzt.
Also sprich so:
000 0=zu prüfendes Feld
0x0 x= geplantes Schiff
0x0
0x0
000

Ich bekomme beim compilieren immer den “Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: -1”
und zwar bei dein Zeilen

for (int y = startY - 1; xLaenge > 0; xLaenge--, y++) {
                    if (spielDaten[x][y] != 0) {
                        return false;
                    }

sowie bei

do {
                    int startX = wuerfel.nextInt((12 - 2) - 2) + 2;
                    int startY = wuerfel.nextInt((12 - (laenge + 1)) - 2) + 2;

                } while (pruefeHof(startX, startY, laenge, false));

Das ganze auch noch umgekehrt, wenn das Schiff waagerecht liegen soll.

for (int x = startX - 1; xLaenge > 0; xLaenge--, x++) {
                    if (spielDaten[x][y] != 0) {
                        return false;
                    }
                }

sowie bei

do {
                    int startX = wuerfel.nextInt((12 - (laenge + 1)) - 2) + 2;
                    int startY = wuerfel.nextInt((12 - 2) - 2) + 2;

                } while (pruefeHof(startX, startY, laenge, true));

das spielDaten Array, ist ein int Array

private int[][] spielDaten = new int[12][12];

Ich würde gerne nicht Zufahlszahlen benutzen, jedoch ist das ein bisschen seltsam, da er die Zahlen ja würfeln soll.

@SlaterB
Hier hat mal wieder der Spam-Filter zugeschlagen - der top-post ist noch nicht für alle verfügbar - bitte mal freigeben =P

Wenn ich das Problem richtig verstehe geht es um die Initialisierung des Spielfeldes und dabei um die Regel, dass die Schiffe in jeder Richtung ein Feld abstand haben müssen.

Mein Ansatz wäre ja mal wieder ein ganz anderer:
[ol]
[li] Es gibt neben dem Spielfeld-Array noch eine Liste aller verfügbaren Zellen, die für ein Schiff verwendet werden können. Das sind am anfang alle.
[/li]

[li] Zellen des Spielfeldes Sind Objekte, die sich selbst aus dieser Liste Austragen, wenn sie einem Schiff zugeordnet werden.interface CellResevedListener { [/li] void unavailable(Cell cell); } class Cell{ private final CellResevedListener cellResevedListener; public Cell(CellResevedListener cellResevedListener){ this.cellResevedListener=cellResevedListener; } public void addToShip(){ cellResevedListener.unavailable(this); }
[li] Das Spiel erzeug für jede Zelle so einen CellResevedListener :Collection<cell> availableCells = new ArrayList<>(); [/li]for(int i=0;i<width;i++) for(int j=0;j<heigth;j++){ Cell cell = new Cell (me) ->availableCells.remove(me)); gameBoard**[j]=cell; }
[li]Eine Zelle kennt ihre Nachbarn
[/li]Die Zuordnung der Nachbarn mus in einer weiteren iteration über das Spielfeld-Array erfolgen, weil man ja zu dem Zeitpunkt, wo man eine Zelle erstell, die zukünftigen Zellen noch nicht hat…class Cell{ // dies hier ist zusätzlich in der Cell-Classe private final Collection<Cell> neighbours = new ArrayList<>(); public void addNeighbours(Collection<Cell> neighbours){ this.neighbours .clear(); this.neighbours.addAll(neighbours); } }
[li] Die Zelle weiß. ob sie zu einem Schiff gehört:```class Cell{
[/li]// alles hier zuzätzlich!!!
private boolean isShip =false;
public void addToShip(){
this.isShip = true;
}
}

[li] Eine Zelle sagt Ihren Nachbar, wenn sie zu einem Schiff zugeordnet wurde:```class Cell{
[/li]   public void addToShip(){
     cellResevedListener.unavailable(this);
     // neu in der Methode
      for(Cell neighbour: neighbours  )
          neighbour.youAreShipNeigbour();
   }
   
// neue Methode
   private void youAreShipNeigbour(){
      
   }```
[li] Auch eine Nachbarzelle trägt sich auch aus der Verfügbarenliste aus```class Cell{
[/li]   private void youAreShipNeigbour(){
     // neu in der Methode
     cellResevedListener.unavailable(this);
   }```
[/ol]
Ab jetzt kann man ohne weitere Checks davon ausgehen, dass eine Zelle, die man aus  `availableCells`  holt mindestens ein Feld von seinen Nachbarn entfernt ist.

bye
TT

Mal ganz konkret: Exceptions sind schon was feines. Man sieht, in welcher Zeile der Fehler aufgetreten ist. Und wenn der, der die Exception wirft, kein A… gewissenhaft gearbeitet hat, dann sieht man sogar, WAS falsch war.

In diesem Fall: Wenn da eine “ArrayIndexOutOfBoundsException: -1” fliegt, dann sieht man, dass in diesem Fall…

for (int y = startY - 1; xLaenge > 0; xLaenge--, y++) {
    if (spielDaten[x][y] != 0) {
        return false;
}

wohl entweder “x” oder “y” -1 sein muss. Und y könnte -1 sein, wenn “startY==0” ist.

Was auch immer da genau geprüft wird, habe ich nicht nachvollzogen, aber wie man das Problem umgeht, kann man zumindest leicht andeuten:

int minY = startY - 1;
if (minY < 0) minY = 0;
for (int y = minY; .... ) {
    ....
}

(es gibt vermutlich elegantere Lösungen, auf verschiedenen Ebenen, aber … zumindest sollte obiges nachvollziehbar sein)

Danke an allle habs selbst nochmal neu geschrieben und jetzt gehts:)
Falls ihr das auch und den code wollt schreibt mich an

Nebenbei wird das Problem, beim Überprüfen der Nachbarfelder “über den Rand” zu kommen, in vielen Brettspiel-Implementierungen so gelöst, dass man rings um das eigentliche Feld noch eine (oder bei Schach wegen der Springer zwei) Reihen “toter” Felder legt - sozusagen auch ein Art “Hof”. Natürlich muss man die Indizes entsprechend anpassen, die dann 1- statt 0-basiert sind.

Das macht man speziell bei Schach nicht zuletzt für die Performance (da gibt’s eine Menge Infos dazu unter https://chessprogramming.wikispaces.com/Board+Representation ). Nach den hier offenbar zu vermittelnden Infos “Was ist ein Array?” und “Was ist eine if-schleife?” ( :o) ) würde ich persönlich eher Empfehlungen in der Richtung geben, dass es irgendwo eine boolean isValid(int x, int y) oder sowas wie List<Point> getNeighbors(int x, int y) geben könnte…