├── .gitignore
├── src
└── main
│ └── java
│ ├── module-info.java
│ └── org
│ └── peut
│ ├── Main.java
│ ├── App.java
│ ├── Hokje.java
│ ├── Ship.java
│ └── Board.java
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /target
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | module org.peut {
2 | requires javafx.controls;
3 | exports org.peut;
4 | }
--------------------------------------------------------------------------------
/src/main/java/org/peut/Main.java:
--------------------------------------------------------------------------------
1 | package org.peut;
2 |
3 | // Glue function for the fat jar file
4 | public class Main {
5 | public static void main(String[] args) {
6 | App.main(args);
7 | }
8 | }
--------------------------------------------------------------------------------
/src/main/java/org/peut/App.java:
--------------------------------------------------------------------------------
1 | package org.peut;
2 |
3 | import javafx.application.Application;
4 | import javafx.stage.Stage;
5 |
6 |
7 | /**
8 | * JavaFX App
9 | */
10 | public class App extends Application {
11 |
12 | @Override
13 | public void start(Stage primaryStage){
14 |
15 | primaryStage.setTitle("Zee");
16 | primaryStage.setResizable(false);
17 |
18 | Board board = new Board(primaryStage);
19 |
20 | }
21 |
22 | public static void main(String[] args) {
23 | launch();
24 | }
25 |
26 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | org.peut
5 | zee
6 | 1.0-SNAPSHOT
7 |
8 | UTF-8
9 | 11
10 | 11
11 |
12 |
13 |
14 | org.openjfx
15 | javafx-controls
16 | 15.0.1
17 |
18 |
19 |
20 |
21 |
22 | org.apache.maven.plugins
23 | maven-compiler-plugin
24 | 3.8.0
25 |
26 | 11
27 |
28 |
29 |
30 | org.openjfx
31 | javafx-maven-plugin
32 | 0.0.4
33 |
34 | org.peut.App
35 |
36 |
37 |
38 |
39 | org.apache.maven.plugins
40 | maven-assembly-plugin
41 | 3.2.0
42 |
43 |
44 |
45 |
46 | true
47 | org.peut.Main
48 |
49 |
50 |
51 | jar-with-dependencies
52 |
53 |
54 |
55 |
56 |
57 | make-assembly
58 | package
59 |
60 | single
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/main/java/org/peut/Hokje.java:
--------------------------------------------------------------------------------
1 | package org.peut;
2 |
3 | import javafx.event.ActionEvent;
4 | import javafx.event.EventHandler;
5 | import javafx.scene.Group;
6 | import javafx.scene.control.Button;
7 |
8 |
9 | public class Hokje extends Button {
10 | //length and width of each square
11 | public static final int SIDE = 60;
12 | // class wide counts to determine position of a new square
13 | private static int xcount = 0;
14 | private static int ycount = 0;
15 |
16 | public static void resetXYcount() {
17 | xcount = 0;
18 | ycount = 0;
19 | }
20 |
21 | // is there a ship in this square?
22 |
23 | private boolean occupied = false;
24 | // reference to the ship if so
25 | private Ship ship;
26 | //back reference to the board
27 | private Board board;
28 | private int index;
29 |
30 |
31 | Hokje(Board board) {
32 | this.board = board;
33 |
34 | //lamba function as per the discussion on
35 | // https://stackoverflow.com/questions/25409044/javafx-multiple-buttons-to-same-handler
36 |
37 | this.setOnAction(e -> {
38 | Hokje h = (Hokje) e.getSource();
39 | h.checkSquare();
40 | });
41 |
42 |
43 | this.place();
44 | }
45 |
46 | private void place() {
47 |
48 | this.setLayoutX(xcount * SIDE);
49 | this.setLayoutY(ycount * SIDE);
50 |
51 | this.setMinSize(SIDE, SIDE);
52 | this.setMaxSize(SIDE, SIDE);
53 | this.setPrefSize(SIDE, SIDE);
54 |
55 | if (((xcount + (ycount + 1) & 1) == 1)) {
56 | this.setStyle("-fx-background-color: lightblue");
57 | } else {
58 | this.setStyle("-fx-background-color: skyblue");
59 | }
60 |
61 |
62 | this.index = xcount + (ycount * Board.BOARDSIDE);
63 |
64 | ++xcount;
65 | if (xcount >= Board.BOARDSIDE) {
66 | ++ycount;
67 | xcount = 0;
68 | }
69 |
70 | }
71 |
72 |
73 | public boolean isOccupied() {
74 | return occupied;
75 | }
76 |
77 | public void setOccupied(boolean occupied) {
78 | this.occupied = occupied;
79 | }
80 |
81 | public Ship getShip() {
82 | return ship;
83 | }
84 |
85 | public void setShip(Ship ship) {
86 | this.ship = ship;
87 | }
88 |
89 | public int getIndex() {
90 | return index;
91 | }
92 |
93 | public void setIndex(int index) {
94 | this.index = index;
95 | }
96 |
97 | public void show() {
98 | System.out.println("- Hokje " + index);
99 | }
100 |
101 | private void checkSquare() {
102 |
103 | board.setGrenades(board.getGrenades() - 1);
104 | if (board.getGrenades() <= 0) {
105 | int shipsLeft = board.getShipsLeft();
106 | board.setStageTitle("No more grenades. You lost.");
107 | board.gameOver();
108 | return;
109 | }
110 |
111 | if (isOccupied()) {
112 |
113 | if (ship.isDead()) {
114 | board.setStageTitle("Shooting wreckage is counter productive");
115 | } else {
116 | if (ship.isDamaged(this)) {
117 | board.setStageTitle("Ship #" + ship.getNumber() + " already damaged here");
118 | } else {
119 | board.setStageTitle("Hit!");
120 |
121 | this.setStyle("-fx-background-color: gray");
122 |
123 | if (ship.hit(this)) {
124 | for (Hokje d : ship.getDamagedParts()) {
125 | d.setStyle("-fx-background-color: darkblue");
126 | }
127 |
128 | board.setShipsLeft(board.getShipsLeft() - 1);
129 | if (board.getShipsLeft() <= 0) return;
130 |
131 | board.setGrenades(board.getGrenades() + (Board.BOARDSIDE) / 2);
132 | board.setStageTitle(ship.getName() + " destroyed. " + board.getShipsLeft() + " more ships remain.");
133 | return;
134 | } else {
135 | board.setStageTitle("Ship #" + ship.getNumber() + " is damaged");
136 | }
137 | }
138 | }
139 | } else {
140 | board.setStageTitle("Missed, nothing at " + index);
141 | }
142 | }
143 |
144 |
145 | }
146 |
147 |
148 |
--------------------------------------------------------------------------------
/src/main/java/org/peut/Ship.java:
--------------------------------------------------------------------------------
1 | package org.peut;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Random;
5 |
6 | public class Ship {
7 |
8 | private int length;
9 |
10 | private ArrayList healthyParts;
11 | private ArrayList damagedParts;
12 |
13 | private String name;
14 | private int number;
15 | private boolean dead;
16 |
17 |
18 | Ship(String name, Board board) {
19 | this.name = name;
20 | this.dead = false;
21 | healthyParts = new ArrayList<>();
22 | damagedParts = new ArrayList<>();
23 |
24 | placeShip(board);
25 | }
26 |
27 | private void placeShip(Board board) {
28 | boolean vertical = false;
29 | if ((Math.random() * 10) < 5) vertical = true;
30 |
31 |
32 | length = (int) Math.floor((Math.random() * 3.2) + 1);
33 | System.out.println("length of" + this.name + " is " + length);
34 |
35 | boolean ready = false;
36 | int maxcount = 100;
37 |
38 | while (!ready && maxcount >= 0) {
39 | int endrow = Board.BOARDSIDE;
40 | int endcol = Board.BOARDSIDE;
41 |
42 | if (vertical) {
43 | endrow -= (length - 1);
44 | } else {
45 | endcol -= (length - 1);
46 | }
47 |
48 | Random r = new Random();
49 | int startRow = r.nextInt(endrow);
50 | int startCol = r.nextInt(endcol);
51 |
52 | ready = true;
53 | if (vertical) {
54 | for (int i = 0; i < length; ++i) {
55 | if (board.getHokje(startRow + i, startCol).isOccupied()) {
56 | ready = false;
57 | break;
58 | }
59 | }
60 | } else {
61 | for (int i = 0; i < length; ++i) {
62 | if (board.getHokje(startRow, startCol + i).isOccupied()) {
63 | ready = false;
64 | break;
65 | }
66 | }
67 | }
68 |
69 | if (ready) {
70 | if (vertical) {
71 | for (int i = 0; i < length; ++i) {
72 |
73 | Hokje square = board.getHokje(startRow + i, startCol);
74 | square.setOccupied(true);
75 | square.setShip(this);
76 | healthyParts.add(square);
77 | }
78 | } else {
79 | for (int i = 0; i < length; ++i) {
80 |
81 | Hokje square = board.getHokje(startRow, startCol + i);
82 | square.setOccupied(true);
83 | square.setShip(this);
84 | healthyParts.add(square);
85 | }
86 | }
87 | } else {
88 | System.out.println("Ship replace " + name);
89 | maxcount--;
90 | }
91 |
92 | }
93 |
94 | if (maxcount >= 0) {
95 | board.setShipsLeft((board.getShipsLeft() + 1));
96 | this.number = board.getShipsLeft();
97 |
98 | this.show();
99 | } else {
100 | throw new IllegalArgumentException("No space found for " + name + ". Reduce number of ships.");
101 | }
102 |
103 | }
104 |
105 | public String getName() {
106 | return name;
107 | }
108 |
109 | public void setName(String name) {
110 | this.name = name;
111 | }
112 |
113 | public int getNumber() {
114 | return number;
115 | }
116 |
117 | public void setNumber(int number) {
118 | this.number = number;
119 | }
120 |
121 | public boolean isDead() {
122 | return dead;
123 | }
124 |
125 | public int getLength() {
126 | return length;
127 | }
128 |
129 | public void setLength(int length) {
130 | this.length = length;
131 | }
132 |
133 | public ArrayList getDamagedParts() {
134 | return damagedParts;
135 | }
136 |
137 | public void setDamagedParts(ArrayList damagedParts) {
138 | this.damagedParts = damagedParts;
139 | }
140 |
141 |
142 | public boolean isDamaged(Hokje square) {
143 | if (!healthyParts.contains(square)) {
144 | return (true);
145 | }
146 | return (false);
147 | }
148 |
149 | public boolean hit(Hokje square) {
150 | healthyParts.remove(square);
151 | damagedParts.add(square);
152 | if (healthyParts.isEmpty()) {
153 | dead = true;
154 | }
155 | return dead;
156 | }
157 |
158 | public void show() {
159 | System.out.println("Ship name: " + name);
160 | if (!dead) {
161 | System.out.println("Hokjes occupied by #" + number + " - " + name);
162 | for (Hokje a : healthyParts) {
163 | a.show();
164 | }
165 | }
166 | }
167 | }
--------------------------------------------------------------------------------
/src/main/java/org/peut/Board.java:
--------------------------------------------------------------------------------
1 | package org.peut;
2 |
3 | import javafx.geometry.Pos;
4 | import javafx.scene.Group;
5 | import javafx.scene.Scene;
6 | import javafx.scene.control.Button;
7 | import javafx.scene.control.Label;
8 | import javafx.scene.effect.DropShadow;
9 | import javafx.scene.layout.*;
10 | import javafx.scene.paint.Color;
11 | import javafx.scene.text.Font;
12 | import javafx.scene.text.TextAlignment;
13 | import javafx.stage.Stage;
14 |
15 |
16 | import java.util.Arrays;
17 |
18 | public class Board extends Group {
19 | public static final int BOARDSIDE = 10;
20 | public static final int SHIPCOUNT = 6;
21 | private Hokje[] board;
22 | private Stage stage;
23 | Ship[] ships;
24 | private int shipsLeft;
25 | private int grenades;
26 |
27 | Board(Stage stage) {
28 |
29 | // set the stage
30 | this.stage = stage;
31 |
32 | init();
33 | show();
34 | }
35 |
36 |
37 | private void init() {
38 |
39 | // removing all children of the board, avoid previously used objects staying around.
40 | while( ! this.getChildren().isEmpty() ){
41 | this.getChildren().remove(0);
42 | }
43 |
44 | // remove old board by assigning a new array
45 | board = new Hokje[(BOARDSIDE * BOARDSIDE)];
46 |
47 | // make sure the first allocated Hokje is at zero,zero
48 |
49 | Hokje.resetXYcount();
50 |
51 | // add BOARDSIDE x BOARDSIDE Hokjes to the Board
52 |
53 | for (int i = 0; i < (BOARDSIDE * BOARDSIDE); i++) {
54 | board[i] = new Hokje(this);
55 | this.getChildren().add(board[i]);
56 | //System.out.println( "Hokje "+ i + " style:" + h.getStyle() );
57 | }
58 | // make sure hokje 0,0 gets focus. Handy for keyboard operation
59 | board[0].requestFocus();
60 |
61 | // add SHIPCOUNT ships
62 | ships = new Ship[SHIPCOUNT];
63 | int shipSurface = 0;
64 | for (int i = 0; i < SHIPCOUNT; i++) {
65 | ships[i] = new Ship("BMS Baddy" + (i + 1), this);
66 | shipSurface += ships[i].getLength();
67 | }
68 |
69 | grenades = (BOARDSIDE * BOARDSIDE) / 2 + shipSurface;
70 | shipsLeft = SHIPCOUNT;
71 |
72 | setStageTitle(SHIPCOUNT + " ship" + (( SHIPCOUNT == 1)?"":"s") + " of unknown size must be destroyed");
73 |
74 | }
75 |
76 | public int getShipsLeft() {
77 | return shipsLeft;
78 | }
79 |
80 | public void gameOver() {
81 | Label label = new Label("GAME OVER");
82 |
83 | label.setFont(new Font("Arial", 32));
84 | label.setMinSize(200, 100);
85 | label.setMaxSize(200, 100);
86 | label.setPrefSize(200, 100);
87 | label.setStyle("-fx-text-fill: white");
88 | label.setTextAlignment(TextAlignment.CENTER);
89 |
90 | Button quitButton = new Button();
91 |
92 | quitButton.setMinSize(100, 100);
93 | quitButton.setMaxSize(100, 100);
94 | quitButton.setPrefSize(100, 100);
95 | quitButton.setFont(new Font("Arial", 24));
96 | quitButton.setStyle("-fx-text-fill: black");
97 | quitButton.setText("Quit");
98 | quitButton.setCancelButton(true);
99 |
100 | quitButton.setOnAction(e -> stage.close());
101 |
102 | Button againButton = new Button();
103 |
104 | againButton.setMinSize(100, 100);
105 | againButton.setMaxSize(100, 100);
106 | againButton.setPrefSize(100, 100);
107 | againButton.setFont(new Font("Arial", 24));
108 | againButton.setStyle("-fx-text-fill: black");
109 | againButton.setText("Again");
110 | againButton.setDefaultButton(true);
111 |
112 | againButton.setOnAction(e -> init());
113 |
114 | FlowPane box = new FlowPane();
115 | box.setStyle("-fx-background-color: skyblue");
116 | box.setPrefSize(210, 210);
117 | box.setAlignment(Pos.CENTER);
118 |
119 | box.getChildren().add(label);
120 | box.getChildren().add(quitButton);
121 | box.getChildren().add(againButton);
122 |
123 | box.setHgap(7);
124 | box.setVgap(7);
125 | box.setLayoutX(((BOARDSIDE * Hokje.SIDE) - 210) / 2);
126 | box.setLayoutY(((BOARDSIDE * Hokje.SIDE) - 210) / 2);
127 |
128 | DropShadow dropShadow1 = new DropShadow();
129 | dropShadow1.setRadius(7);
130 | dropShadow1.setOffsetX(3);
131 | dropShadow1.setOffsetY(3);
132 | dropShadow1.setColor(Color.DEEPSKYBLUE);
133 |
134 | box.setEffect(dropShadow1);
135 |
136 |
137 | this.getChildren().add(box);
138 |
139 | // to make sure enter will reach the againButton (which has been set as
140 | // as defaultButton. If not the last boardButton will be selected.
141 |
142 | box.requestFocus();
143 |
144 | }
145 |
146 | public void setShipsLeft(int shipsLeft) {
147 | this.shipsLeft = shipsLeft;
148 |
149 | if (this.shipsLeft == 0) {
150 | setStageTitle(" You WON! ");
151 | gameOver();
152 | }
153 | }
154 |
155 | public int getGrenades() {
156 | return grenades;
157 | }
158 |
159 | public void setGrenades(int grenades) {
160 | this.grenades = grenades;
161 | }
162 |
163 | public void setStageTitle(String title) {
164 | stage.setTitle("Grenades left: [" + grenades + "] Ships left: [" + shipsLeft + "] " + title);
165 | }
166 |
167 | public int rowcolToNumber(int row, int column) {
168 | return row + (column * BOARDSIDE);
169 | }
170 |
171 | public int[] numberToRowcol(int number) {
172 | int[] rowcol = new int[2];
173 | rowcol[0] = number / Board.BOARDSIDE;
174 | rowcol[1] = number % Board.BOARDSIDE;
175 |
176 | return (rowcol);
177 | }
178 |
179 | public Hokje getHokje(int row, int column) {
180 | return board[rowcolToNumber(row, column)];
181 | }
182 |
183 | public void show() {
184 | stage.setScene(new Scene(this, BOARDSIDE * Hokje.SIDE + 1, BOARDSIDE * Hokje.SIDE + 1));
185 | stage.show();
186 | }
187 |
188 |
189 | }
190 |
--------------------------------------------------------------------------------