# Hilfe beim Platzieren der Schiffe



## towelie8 (18. Jun 2020)

Guten Tag,
ich möchte ein simples Schiffe Versenken programmieren. Ein Feld habe ich bereits generiert, das war es dann aber auch schon.
In dem Spielfeld sollen Schiffe platziert werden, mit festen Positionen und nur mit einer Größe von einem Feld.
Beim anklicken des Feldes soll sich dann die Farbe von weiß zu blau ändern, versteckt sich hinter dem Feld ein Schiff dann soll sich die Farbe des Buttons zu rot ändern.

Grüße.

```
package com.interes;

public class Board {
    
    int xCoord = 8;
    int yCoord = 8;
    int counter = 0;
    
    public Board(int x, int y) {
        init(x, y);
    }
    public void shoot( String coordString ) {
        
        //String [] split = coordString.split(":");
        //int x = Integer.valueOf(split[0]);
        //int y = Integer.valueOf(split[1]);
        counter++;

    }
    
    public void placeShip(int x, int y) {
        
    }
    
    public void hit() {
        counter++;
    }
    
    public void init (int x, int y) {
        counter = 0;
        xCoord = x;
        yCoord = y;
    }
    
    public int getxCoord() {
        return xCoord;
    }
    
    public int getyCoord() {
        return yCoord;
    }
    
    public int getHits() {
        return counter;
    }
    
}
```






```
<!DOCTYPE html>
<%@page import="com.interes.Board"%>
<%@page import="com.interes.Ship"%>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Battleship</title>
</head>
<body bgcolor="#424242">
    <form method="POST">
        <script type="text/javascript">

            function onClick( value ) {

                document.getElementById("shoot").innerHTML = value;
            };
            
            
        </script>


        <%
            Board board = (Board)session.getAttribute( "board" );
        
            if( board == null  || request.getParameter("shoot") == null )
            {
                board = new Board(8,8);
                session.setAttribute("board", board);
            }
            
            else
            {
                board.shoot(request.getParameter("shoot"));
            }
        
                
        
        %>
        
        Schuss = <input type="text" id="shoot" name="shoot" value="">
        Anzahl Versuche = <%=board.getHits()%>
        

        <table>
            <%String water = "#2E64FE";%>
            <%String noWater = "#D8D8D8"; %>
        
            <%
                for (int i = 0; i < board.getyCoord(); i++) {
            %>
            <tr>
                <%
                    for (int j = 0; j < board.getxCoord(); j++) {
                %>
                
                
                <td>
                
                    <input type="submit" value="<%=i%>:<%=j%>" id="shoot" onClick="onClick( this.value )"
                        style="height: 50px; width: 50px; background-color: <%=noWater%>">
                
            
                </td>

                <%
                    }
                    }
                %>
            
        </table>
    </form>
</body>
</html>
```


----------



## kneitzel (18. Jun 2020)

Du musst dann erst einmal dein Brett speicher. Die Frage ist, was Du pro Feld speichern willst.

Also nur so als Vorschlag:
Ein Feld kann sein: Leer, leer+Beschossen, Schiff, Schiff+Beschossen
Sowas könnte man in Java z.B. mit einer Enum abbilden.

Dann musst Du die Felder haben. Das wäre dann z.B. ein zweidimensionales Array aus dem enum.

Initialisierung erstellt so ein Array und setzt die Werte auf Leer.
Schiffe kannst Du erzeugen mit Code, der sowas macht:
Solange Schiffe zu setzen sind:
- zufalls-Koordinaten ermitteln.
- Ist Feld der Zufallskoordinaten leer? -> Schiff setzen und Anzahl zu setzende Schiffe um eins reduzieren

Das wäre ein möglicher Ansatz, den Du abbilden könntest.


----------



## towelie8 (18. Jun 2020)

Vielen Dank für die schnelle Antwort, ich habe aber absolut keine Ahnung wie ich das ganze angehen soll.

Grüße.


----------



## MoxxiManagarm (18. Jun 2020)

towelie8 hat gesagt.:


> ich habe aber absolut keine Ahnung wie ich das ganze angehen soll.



Einen Vorschlag hat JustNobody doch schon ziemlich gut beschrieben.

1. Mach dir ein Enum, das hat 4 Werte für die jeweiligen Zustände einen Feldes, z.B.: HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP
2. Erstelle dir ein 2D-Array dieses Enums, anfänglich mit HIDDEN_WATER auf allen Felder vorbelegt
3. Jetzt platzierst du Schiffe, indem du HIDDEN_WATER Felder durch HIDDEN_SHIP Felder ersetzt
4. Bei shoot auf ein Feld wird HIDDEN_WATER zu REVEALED_WATER und HIDDEN_SHIP zu REVEALED_SHIP


----------



## towelie8 (18. Jun 2020)

MoxxiManagarm hat gesagt.:


> Einen Vorschlag hat JustNobody doch schon ziemlich gut beschrieben.
> 
> 1. Mach dir ein Enum, das hat 4 Werte für die jeweiligen Zustände einen Feldes, z.B.: HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP
> 2. Erstelle dir ein 2D-Array dieses Enums, anfänglich mit HIDDEN_WATER auf allen Felder vorbelegt
> ...




Vielen Dank für die schnellen Antworten, ich bin totaler Anfänger und hoffe die fragen sind nicht unverschämt lächerlich.
Wieso kann ich das Array nicht mit der enum HIDDEN_WATER belegen?.

Grüße




```
enum status {HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP}
    
    String zweidimArray [][] = new String [7][7];
    
    
    public void fillArray() {
        
        for ( int i = 0; i < zweidimArray.length; i++) {
            
            for ( int j = 0; j < zweidimArray.length; i++) {
                
                
                zweidimArray[i][j] = HIDDEN_WATER;
                
            }
        }
        
    }
```


----------



## MoxxiManagarm (18. Jun 2020)

Weil du ein String Array hast, es muss aber ein status Array sein. Schreib status bitte auch groß (Namenskonvention)


```
enum Status { HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP }
    
    Status zweidimArray [][] = new Status [7][7];
```


----------



## towelie8 (18. Jun 2020)

Danke ich habe jetzt das 2D Array erzeugt, alle Felder mit HIDDEN_WATER belegt. In der JSP will ich jetzt auf den Koordinaten 4,4 ein Schiff setzen, jedoch klappt das nicht wie ich das gerne hätte.



```
<!DOCTYPE html>
<%@page import="com.interes.Board"%>

<html>
<head>
<link href="styles/style.css" rel="stylesheet" type="text/css">
<meta charset="ISO-8859-1">
<title>Battleship</title>
</head>
<body bgcolor="#424242">
    <form method="POST">
        <h1>BATTLESHIP</h1>
        <script type="text/javascript">
            function onClick(value) {

                document.getElementById("shoot").innerHTML = value;
            };
        </script>


        <%
            Board board = (Board) session.getAttribute("board");

            board.fillArray();
          
            board.deployShip(4,4);

            if (board == null || request.getParameter("shoot") == null) {
                board = new Board(8, 8);
                session.setAttribute("board", board);
            }

            else {
                board.shoot(request.getParameter("shoot"));
            }
        %>

        Schuss = <input type="text" id="shoot" name="shoot" value="">
        Counter =
        <%=board.getCounter()%>
        Hits =
        <%=board.getHits() %>
        Misses =
        <%=board.getMisses() %>


        <table>
            <%
                String water = "#2E64FE";
            %>
            <%
                String noWater = "#D8D8D8";
            %>

            <%
                for (int i = 0; i < board.getyCoord(); i++) {
            %>
            <tr>
                <%
                    for (int j = 0; j < board.getxCoord(); j++) {
                %>
                <%
                    // if(field[i][j] == hit)
                %>
                <%
                    //if(field[i][j] == button)
                %>
                <td><input type="submit" value="<%=i%>:<%=j%>" id="shoot"
                    onClick="onClick( this.value )"
                    style="height: 50px; width: 50px; background-color: <%=noWater%>">


                </td>
                <%
                    // if(field[i][j] == miss)
                %>


                <%
                    }
                    }
                %>
          
        </table>
    </form>
</body>
</html>
```





```
package com.interes;

public class Board {

    int xCoord = 8;
    int yCoord = 8;
    int counter = 0;
    int hits = 0;
    int misses = 0;

    /*
     * 1. Mach dir ein Enum, das hat 4 Werte für die jeweiligen Zustände einen
     * Feldes, z.B.: HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP 2.
     * Erstelle dir ein 2D-Array dieses Enums, anfänglich mit HIDDEN_WATER auf allen
     * Felder vorbelegt 3. Jetzt platzierst du Schiffe, indem du HIDDEN_WATER Felder
     * durch HIDDEN_SHIP Felder ersetzt 4. Bei shoot auf ein Feld wird HIDDEN_WATER
     * zu REVEALED_WATER und HIDDEN_SHIP zu REVEALED_SHIP
     *
     */

    public enum Status {
        HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP
    }

    public Status zweidimArray[][] = new Status[7][7];

    public void fillArray() {

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

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

                zweidimArray[i][j] = Status.HIDDEN_WATER;

            }
        }

    }

    public void deployShip(int x, int y) {
        zweidimArray[x][y] = Status.HIDDEN_SHIP;
    }
   
    public Board(int x, int y) {
        init(x, y);
    }

    public void shoot(String coordString) {

         String [] split = coordString.split(":");
         int x = Integer.valueOf(split[0]);
         int y = Integer.valueOf(split[1]);
       
       
        if (zweidimArray[x][y] == Status.HIDDEN_WATER) {
            misses++;
        }
        if (zweidimArray[x][y] == Status.HIDDEN_SHIP) {
            hits++;
        }
        counter++;

    }


    public void placeShip(int x, int y) {

    }

    public void counter() {
        counter++;
    }

    public void init(int x, int y) {
        counter = 0;
        xCoord = x;
        yCoord = y;
    }

    public int getxCoord() {
        return xCoord;
    }

    public int getyCoord() {
        return yCoord;
    }

    public int getCounter() {
        return counter;
    }
    public int getHits() {
        return hits;
    }
    public int getMisses() {
        return misses;
    }

}
```


----------



## MoxxiManagarm (18. Jun 2020)

towelie8 hat gesagt.:


> jedoch klappt das nicht wie ich das gerne hätte.


Das musst du genauer erläutern.



```
public void shoot(String coordString) {

         String [] split = coordString.split(":");
         int x = Integer.valueOf(split[0]);
         int y = Integer.valueOf(split[1]);
       
       
        if (zweidimArray[x][y] == Status.HIDDEN_WATER) {
            misses++;
        }
        if (zweidimArray[x][y] == Status.HIDDEN_SHIP) {
            hits++;
        }
        counter++;

    }
```
 Hier fehlt noch die Umwandlung von den Hidden Stati zu den Revealed Stati. Wenn du ein verdecktes Feld beschießt wird es natürlich aufgedeckt.


----------



## towelie8 (29. Jun 2020)

MoxxiManagarm hat gesagt.:


> Das musst du genauer erläutern.
> 
> 
> 
> ...




Habe das geändert:


```
// X + Y Koordinate wird ausgelesen + Status des beschossenen Feldes wird überprüft.
    public void shoot(String coordString) {

        String[] split = coordString.split(":");
        int x = Integer.valueOf(split[0]);
        int y = Integer.valueOf(split[1]);
        
        
        if (zweidimArray[x][y] == Status.HIDDEN_WATER) {
            zweidimArray[x][y] = Status.REVEALED_WATER;
            misses++;
        }
        if (zweidimArray[x][y] == Status.HIDDEN_SHIP) {
            zweidimArray[x][y] = Status.REVEALED_SHIP;
            hits++;
        }
        counter++;

    }
```


Wenn ich aber die JSP ausführe, bekomme ich einen Fehler.
Siehe Screenshot.

Grüße.


----------



## kneitzel (29. Jun 2020)

Die Fehlermeldung besagt einfach, dass board null war, d.h. das Attribut board konnte nicht aus der Session gelesen werden. Bist Du sicher, dass Du es hinterlegt hast?


----------



## towelie8 (29. Jun 2020)

JustNobody hat gesagt.:


> Die Fehlermeldung besagt einfach, dass board null war, d.h. das Attribut board konnte nicht aus der Session gelesen werden. Bist Du sicher, dass Du es hinterlegt hast?



Das hier ist die JSP.


```
<!DOCTYPE html>
<%@page import="com.interes.Board"%>

<html>
<head>
<link href="styles/style.css" rel="stylesheet" type="text/css">
<meta charset="ISO-8859-1">
<title>Battleship</title>
</head>
<body bgcolor="#424242">
    <form method="POST">
        <h1>BATTLESHIP</h1>
        <script type="text/javascript">
            function onClick(value) {

                document.getElementById("shoot").innerHTML = value;
            };
        </script>


        <%
            Board board = (Board) session.getAttribute("board");

            board.fillArray();
            //board.zweidimArray[4][4] = Status.HIDDEN_WATER;
            board.deployShip(4,4);

            if (board == null || request.getParameter("shoot") == null) {
                board = new Board(8, 8);
                session.setAttribute("board", board);
            }

            else {
                board.shoot(request.getParameter("shoot"));
            }
        %>

        Schuss = <input type="text" id="shoot" name="shoot" value="">
        Counter =
        <%=board.getCounter()%>
        Hits =
        <%=board.getHits() %>
        Misses =
        <%=board.getMisses() %>


        <table>
            <%
                String water = "#2E64FE";
            %>
            <%
                String noWater = "#D8D8D8";
            %>

            <%
                for (int i = 0; i < board.getyCoord(); i++) {
            %>
            <tr>
                <%
                    for (int j = 0; j < board.getxCoord(); j++) {
                    
                %>
                <td><input type="submit" value="<%=i%>:<%=j%>" id="shoot"
                    onClick="onClick( this.value )"
                    style="height: 50px; width: 50px; background-color: <%=noWater%>">


                </td>
                <%
                    
                %>


                <%
                    }
                    }
                %>
            
        </table>
    </form>
</body>
</html>
```

Und hier noch meine JAVA-Klasse


```
package com.interes;

public class Board {

    int xCoord = 8;
    int yCoord = 8;
    int counter = 0;
    int hits = 0;
    int misses = 0;


    public enum Status {
        HIDDEN_WATER, REVEALED_WATER, HIDDEN_SHIP, REVEALED_SHIP;
    }

    public Status zweidimArray[][] = new Status[7][7];

    
    
    // Fülle alle Array-Felder mit HIDDEN_WATER
    public void fillArray() {

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

            for (int j = 0; j < zweidimArray[i].length; j++) {

                zweidimArray[i][j] = Status.HIDDEN_WATER;

            }
        }

    }
    // Setze schiff an x und y Koordinate - HIDDEN_WATER -> HIDDEN_SHIP
    public void deployShip(int x, int y) {
        zweidimArray[x][y] = Status.HIDDEN_SHIP;
    }

    public Board(int x, int y) {
        init(x, y);
    }

    // X + Y Koordinate wird ausgelesen + Status des beschossenen Feldes wird überprüft.
    public void shoot(String coordString) {

        String[] split = coordString.split(":");
        int x = Integer.valueOf(split[0]);
        int y = Integer.valueOf(split[1]);
        
        
        if (zweidimArray[x][y] == Status.HIDDEN_WATER) {
            zweidimArray[x][y] = Status.REVEALED_WATER;
            misses++;
        }
        if (zweidimArray[x][y] == Status.HIDDEN_SHIP) {
            zweidimArray[x][y] = Status.REVEALED_SHIP;
            hits++;
        }
        counter++;

    }


    public void counter() {
        counter++;
    }

    public void init(int x, int y) {
        counter = 0;
        xCoord = x;
        yCoord = y;
    }

    public int getxCoord() {
        return xCoord;
    }

    public int getyCoord() {
        return yCoord;
    }

    public int getCounter() {
        return counter;
    }

    public int getHits() {
        return hits;
    }

    public int getMisses() {
        return misses;
    }

}
```

Kannst du mir evtl aufzeigen wo der Fehler liegt?

Grüße.


----------



## kneitzel (29. Jun 2020)

Du hast derzeit folgenden Code:

```
Board board = (Board) session.getAttribute("board");

            board.fillArray();
            //board.zweidimArray[4][4] = Status.HIDDEN_WATER;
            board.deployShip(4,4);

            if (board == null || request.getParameter("shoot") == null) {
                board = new Board(8, 8);
                session.setAttribute("board", board);
            }
```

Die null Prüfung kommt zu spät.


```
Board board = (Board) session.getAttribute("board");

            if (board == null || request.getParameter("shoot") == null) {
                board = new Board(8, 8);
                session.setAttribute("board", board);
            }

            board.fillArray();
            //board.zweidimArray[4][4] = Status.HIDDEN_WATER;
            board.deployShip(4,4);
```

Sieht besser aus. Wenn board null ist, dann erzeuge es und setze das Attribut in der Session.

Dann kannst Du auch auf board zugreifen.


----------



## towelie8 (29. Jun 2020)

JustNobody hat gesagt.:


> Du hast derzeit folgenden Code:
> 
> ```
> Board board = (Board) session.getAttribute("board");
> ...



Ersteinmal, danke für die schnellen Antworten.
Ich habe es abgeändert wie oben beschrieben.


```
<%
            Board board = (Board) session.getAttribute("board");


            if (board == null || request.getParameter("shoot") == null) {
                board = new Board(8, 8);
                session.setAttribute("board", board);
            }

            else {
                board.shoot(request.getParameter("shoot"));
            }
            
            
            board.fillArray();
            //board.zweidimArray[4][4] = Status.HIDDEN_WATER;
            board.deployShip(4,4);
        %>
```


Doch beim klicken der Felder, geschieht folgendes.



Grüße.


----------



## kneitzel (29. Jun 2020)

Also die Fehlermeldung besagt, dass eine NumberFormatException aufgetreten ist und zwar in Board.shoot, Zeile 46 in Board.java.
Das Problem ist ein Integer.valueOf Aufruf, der eine Eingabe von "" (einem leeren String) bekommen hat.

Wenn man sich Deinen Code anschaut, dann findet man folgenden Code in der shoot Methode:

```
String[] split = coordString.split(":");
        int x = Integer.valueOf(split[0]);
        int y = Integer.valueOf(split[1]);
```

Dies ist problematisch, denn:
a) Wenn coordString kein : enthält, dann hast Du ein String Array mit nur einem Element, das dem coordString selbst entspricht. Daher führt ein split[1] zu einer OutOfBounds Exception.
b) Integer.valueOf kann - wie Du gut erkannt hast, eine NumberFormatException werfen.

Bei Eingaben ist immer zu prüfen, ob die Eingabe gültig ist. Also hier würde ich:
a) nach dem split Aufruf prüfen, ob die Länge des split Arrays 2 ist. Ist die Länge nicht genau 2, dann ist die Eingabe ungültig.
b) Die Eingabe selbst kann man prüfen. Ich mochte in .Net immer das tryParse, aber das gibt es in Java so nicht, da Java call by Reference nicht kennt. Eine Lösung für diese Problematik könnte also sein, dass Du mittels try/catch die NumberFormatException abfängst:


```
String[] split = coordString.split(":");
        if (split.length != 2) {
                  //Mach was sinnvolles wie Nachricht an Anwender setzen. Dann aus Methode raus gehen!
        }

        int x;
        int y;
        try {
           x = Integer.valueOf(split[0]);
           y = Integer.valueOf(split[1]);
        } catch (NumberFormatException nfe) {
                  //Mach was sinnvolles wie Nachricht an Anwender setzen. Dann aus Methode raus gehen!
        }
```

Das ist aber dann erst einmal eine Lösung, um es einfach zu halten. Der Weg, den ich gehen würde, wäre eine Validierung der Eingabe über einen regulären Ausdruck. Dann sind die weiteren Prüfungen unnötig, denn der Code kann dann nur durchlaufen. Hintergrund ist u.a.: Exceptions haben "exceptional" zu sein, also wirklich ungeahnte Ausnahmen. Ein User der sich vertippt ist aber nichts außergewöhnliches. Das sollte man aktiv prüfen. 

Das vertiefe ich jetzt aber nicht weiter, denn ich hoffe, dass ich eine gut verständliche Lösung bieten konnte, so dass Du erst einmal weiter kommst. Aber bitte schreibe Dir für später den Punkt einmal auf: Reguläre Ausdrücke. Das ist in meinen Augen ein wichtiges und sehr mächtiges Thema.


----------



## towelie8 (30. Jun 2020)

JustNobody hat gesagt.:


> Also die Fehlermeldung besagt, dass eine NumberFormatException aufgetreten ist und zwar in Board.shoot, Zeile 46 in Board.java.
> Das Problem ist ein Integer.valueOf Aufruf, der eine Eingabe von "" (einem leeren String) bekommen hat.
> 
> Wenn man sich Deinen Code anschaut, dann findet man folgenden Code in der shoot Methode:
> ...



Vielen Dank für deine bzw. eure Hilfe. 

Grüße.


----------

