Compare commits
No commits in common. "d681f20b90d22e764b0a498ca4c0139c28bd3804" and "2827d79556a00fb6c621103f3b8fb9680bf4cd00" have entirely different histories.
d681f20b90
...
2827d79556
26
README.md
26
README.md
@ -2,33 +2,35 @@
|
||||
|
||||
"named this way because i didn't realise there was another libremines!"
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Building
|
||||
|
||||
### Requirements:
|
||||
- Java 21
|
||||
- Maven 3.8.8 or lower
|
||||
- Java 21 or newer (openjdk-21-jdk)
|
||||
- Maven 3.8.8 (note: some versions cause gluon to freak out)
|
||||
- GraalVM 21
|
||||
|
||||
### Instructions:
|
||||
|
||||
Create the maven wrapper at version 3.8.8. GluonFX does not work with newer versions as of 2024-07-27.
|
||||
Create the maven wrapper. gluonfx does not like versions of maven that are not 3.8.8:
|
||||
|
||||
```shell
|
||||
mvn wrapper:wrapper -Dmaven=3.8.8
|
||||
```
|
||||
|
||||
Install dependencies, build and run:
|
||||
This is helpful for version management, in case you have an incompatible version of maven installed.
|
||||
Install dependencies:
|
||||
|
||||
```shell
|
||||
./mvnw dependency:resolve gluonfx:build
|
||||
./mvnw install
|
||||
```
|
||||
|
||||
Build and run:
|
||||
|
||||
```shell
|
||||
GRAALVM_HOME=/path/to/graalvm ./mvnw gluonfx:build
|
||||
```
|
||||
|
||||
A native binary should be placed at `target/gluonfx/<your architecture>/libremines`
|
||||
|
||||
Alternatively, to run using the JVM, use:
|
||||
|
||||
```shell
|
||||
./mvnw javafx:run
|
||||
```
|
||||
|
14
pom.xml
14
pom.xml
@ -6,23 +6,31 @@
|
||||
|
||||
<groupId>com.shr4pnel.minesweeper</groupId>
|
||||
<artifactId>libremines</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>web</id>
|
||||
<properties>
|
||||
<gluonfx.target>web</gluonfx.target>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>21.0.4</version>
|
||||
<version>21.0.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>21.0.4</version>
|
||||
<version>21.0.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
|
@ -1,167 +1,55 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.control.RadioMenuItem;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.MouseButton;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* The JavaFX controller for minesweeper.fxml.
|
||||
* Handles all operations performed within the GUI.
|
||||
* @author shrapnelnet admin@shr4pnel.com
|
||||
*/
|
||||
public class Controller {
|
||||
/**
|
||||
* The grid within the FXML holding all the tiles.
|
||||
*/
|
||||
@FXML
|
||||
private GridPane grid;
|
||||
|
||||
/**
|
||||
* Images within the FXML structure.
|
||||
*/
|
||||
@FXML
|
||||
private ImageView smiley, time_1, time_2, time_3, bomb_2, bomb_3;
|
||||
|
||||
/**
|
||||
* Menu items
|
||||
*/
|
||||
@FXML
|
||||
private RadioMenuItem color, marks;
|
||||
|
||||
/**
|
||||
* The menu item "about".
|
||||
*/
|
||||
@FXML
|
||||
private MenuItem about;
|
||||
|
||||
/**
|
||||
* The underlying 2D array representing where bombs are on the grid.
|
||||
*/
|
||||
private Grid gridHandler;
|
||||
|
||||
/**
|
||||
* A wrapper to make operations on the underlying grid easier.
|
||||
*/
|
||||
private GridWrapper wrapper;
|
||||
|
||||
/**
|
||||
* Handles the grid during a game over state preventing further clicking of the grid.
|
||||
*/
|
||||
private boolean gameOver = false;
|
||||
|
||||
/**
|
||||
* A variable specifying if the game has been loaded for the first time.
|
||||
*/
|
||||
private boolean isFirstLoad = true;
|
||||
|
||||
/**
|
||||
* The game timer.
|
||||
*/
|
||||
static Timer timer = new Timer();
|
||||
|
||||
/**
|
||||
* The time that has elapsed since the game started.
|
||||
*/
|
||||
private int time = 0;
|
||||
|
||||
/**
|
||||
* The time the game was started at.
|
||||
*/
|
||||
private long startTime;
|
||||
|
||||
/**
|
||||
* The number of bombs on the grid.
|
||||
*/
|
||||
private int bombCount = 99;
|
||||
|
||||
/**
|
||||
* A 2D array holding all tiles that have previously recursively been expanded.
|
||||
*/
|
||||
private boolean[][] expandedTiles;
|
||||
|
||||
/**
|
||||
* A boolean that shows if the user has performed their first click on the GridPane.
|
||||
*/
|
||||
private boolean isFirstClick = true;
|
||||
|
||||
/**
|
||||
* Sets important variables on Main class initialization
|
||||
*/
|
||||
@FXML
|
||||
private void initialize() {
|
||||
setNotYetImplemented(color);
|
||||
setNotYetImplemented(marks);
|
||||
about.setOnAction(this::openAbout);
|
||||
setupGrid();
|
||||
gridHandler = new Grid();
|
||||
wrapper = gridHandler.grid;
|
||||
expandedTiles = new boolean[30][16];
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the about window when the radiomenuitem is clicked
|
||||
*
|
||||
* @param actionEvent The node that the window opens on, on click
|
||||
*/
|
||||
private void openAbout(ActionEvent actionEvent) {
|
||||
try {
|
||||
Parent root = FXMLLoader.load(getClass().getResource("about.fxml"));
|
||||
Stage stage = new Stage();
|
||||
stage.setTitle("About");
|
||||
stage.setMinWidth(455);
|
||||
stage.setMinHeight(275);
|
||||
stage.setScene(new Scene(root));
|
||||
stage.show();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a window if an unimplemented menu item is clicked
|
||||
*
|
||||
* @param node The node that the window opens on, on click
|
||||
*/
|
||||
private void setNotYetImplemented(RadioMenuItem node) {
|
||||
node.setOnAction(new EventHandler<>() {
|
||||
@Override
|
||||
public void handle(ActionEvent actionEvent) {
|
||||
try {
|
||||
Parent root = FXMLLoader.load(getClass().getResource("unimplemented.fxml"));
|
||||
Stage stage = new Stage();
|
||||
stage.setTitle("Unimplemented!");
|
||||
stage.setMinHeight(420);
|
||||
stage.setMinWidth(525);
|
||||
stage.setScene(new Scene(root));
|
||||
stage.show();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
node.setOnAction((ActionEvent e) -> System.out.println("https://http.cat/images/501.jpg"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the GridPane with blank buttons
|
||||
*/
|
||||
private void setupGrid() {
|
||||
for (int column = 0; column < 30; ++column) {
|
||||
for (int row = 0; row < 16; ++row) {
|
||||
@ -171,13 +59,9 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used during initialization to fill the board
|
||||
*
|
||||
* @return A blank button
|
||||
*/
|
||||
private Button createBlankButton() {
|
||||
Image blank = new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, false);
|
||||
Image blank =
|
||||
new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, true);
|
||||
ImageView blankImage = new ImageView(blank);
|
||||
Button blankButton = new Button();
|
||||
blankButton.setGraphic(blankImage);
|
||||
@ -188,34 +72,18 @@ public class Controller {
|
||||
return blankButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes smiley face to concerned look when the mouse is held
|
||||
*
|
||||
* @param mouseEvent Stub, required by EventHandler interface
|
||||
*/
|
||||
private void mouseHeld(MouseEvent mouseEvent) {
|
||||
if (gameOver)
|
||||
return;
|
||||
setImage(smiley, "img/face_ooh.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes smiley face back to smiling after mouse release
|
||||
*
|
||||
* @param mouseEvent Stub, required by EventHandler interface
|
||||
*/
|
||||
private void mouseReleased(MouseEvent mouseEvent) {
|
||||
if (gameOver)
|
||||
return;
|
||||
setImage(smiley, "img/face_smile.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the main GridPane being clicked
|
||||
* Identifies the intention of the click (e.g. flag, open tile)
|
||||
*
|
||||
* @param e The event fired on click
|
||||
*/
|
||||
private void buttonClicked(MouseEvent e) {
|
||||
if (gameOver) {
|
||||
return;
|
||||
@ -236,33 +104,9 @@ public class Controller {
|
||||
if (buttonImage.getUrl().contains("flagged.png")) {
|
||||
return;
|
||||
}
|
||||
// if (buttonImage.getUrl().contains("num") && !buttonImage.getUrl().contains("num_0.png")) {
|
||||
// chord(clicked, buttonImage.getUrl());
|
||||
// return;
|
||||
// }
|
||||
handlePrimaryClick(clicked, column, row);
|
||||
}
|
||||
|
||||
// private void chord(Button clicked, String clickedURL) {
|
||||
// int column = GridPane.getColumnIndex(clicked);
|
||||
// int row = GridPane.getRowIndex(clicked);
|
||||
// int urlLength = clickedURL.length();
|
||||
// char expectedAdjacentChar = clickedURL.charAt(urlLength-5);
|
||||
// int expectedAdjacent = Integer.parseInt(Character.toString(expectedAdjacentChar));
|
||||
// int actualAdjacent = wrapper.atColumn(column).atRow(row).adjacentBombCount();
|
||||
// if (expectedAdjacent != actualAdjacent) {
|
||||
// return;
|
||||
// }
|
||||
// // chord logic
|
||||
// }
|
||||
|
||||
/**
|
||||
* If the first tile clicked was a bomb, move that bomb to the first available column on row 0 before opening it
|
||||
*
|
||||
* @param column The column of the clicked tile
|
||||
* @param row The row of the clicked tile
|
||||
* @return An array containing the column and row the bomb was moved to
|
||||
*/
|
||||
private int[] setBombIfFirstTileIsBomb(int column, int row) {
|
||||
for (int c = 0; c < 30; ++c) {
|
||||
for (int r = 0; r < 16; ++r) {
|
||||
@ -273,27 +117,15 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
}
|
||||
// this realistically should never happen... sorry!
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the URL of a given button
|
||||
*
|
||||
* @param button A javafx.scene.control.Button object
|
||||
* @return A string representation of the image URL
|
||||
*/
|
||||
private String getButtonURL(Button button) {
|
||||
ImageView graphic = (ImageView) button.getGraphic();
|
||||
Image image = graphic.getImage();
|
||||
return image.getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the grid to find all tiles that are either blank or flagged
|
||||
*
|
||||
* @return The number of tiles that were blank or flagged
|
||||
*/
|
||||
private int numberOfUnrevealedTiles() {
|
||||
int unrevealedTiles = 0;
|
||||
int column, row;
|
||||
@ -302,7 +134,7 @@ public class Controller {
|
||||
Button current = (Button) getNodeByRowColumnIndex(row, column);
|
||||
assert current != null;
|
||||
String currentURL = getButtonURL(current);
|
||||
if (currentURL.contains("blank.png") || currentURL.contains("flagged.png")) {
|
||||
if (currentURL.contains("blank.png") || currentURL.contains("flag.png")) {
|
||||
unrevealedTiles++;
|
||||
}
|
||||
}
|
||||
@ -310,24 +142,11 @@ public class Controller {
|
||||
return unrevealedTiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the number of unrevealed tiles is equal to 99 (the win condition)
|
||||
*
|
||||
* @return A boolean representing if the game has been won
|
||||
* @see #numberOfUnrevealedTiles()
|
||||
*/
|
||||
private boolean checkWinCondition() {
|
||||
int unrevealedTiles = numberOfUnrevealedTiles();
|
||||
return unrevealedTiles == 99;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a left mouse click on an unopened tile
|
||||
*
|
||||
* @param clicked The button that was clicked
|
||||
* @param column The column that it was clicked at
|
||||
* @param row The row that it was clicked at
|
||||
*/
|
||||
private void handlePrimaryClick(Button clicked, int column, int row) {
|
||||
if (wrapper.atColumn(column).atRow(row).isBomb() && !isFirstClick) {
|
||||
gameOver(clicked);
|
||||
@ -355,13 +174,6 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If a tile is surrounded by tiles with no adjacent bombs, open all the tiles recursively
|
||||
*
|
||||
* @param column The column that was clicked
|
||||
* @param row The row that was clicked
|
||||
* @see #expandTile(int, int)
|
||||
*/
|
||||
private void recursiveExpandTiles(int column, int row) {
|
||||
if (column < 0 || column >= 30 || row < 0 || row >= 16 ||
|
||||
expandedTiles[column][row] && !wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||
@ -380,12 +192,6 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a tile, and adds it to an array to prevent overflow
|
||||
*
|
||||
* @param column The column of the button to open
|
||||
* @param row The row of the button to open
|
||||
*/
|
||||
private void expandTile(int column, int row) {
|
||||
Node tile = getNodeByRowColumnIndex(row, column);
|
||||
if (tile != null) {
|
||||
@ -401,13 +207,6 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the grid and returns the node when it's at the correct child
|
||||
*
|
||||
* @param row The desired row to find
|
||||
* @param column The desired column to find
|
||||
* @return The node at the specified position
|
||||
*/
|
||||
private Node getNodeByRowColumnIndex(int row, int column) {
|
||||
for (Node node : grid.getChildren()) {
|
||||
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
|
||||
@ -417,9 +216,6 @@ public class Controller {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets important state variables on restart
|
||||
*/
|
||||
@FXML
|
||||
private void reinitialize() {
|
||||
gameOver = false;
|
||||
@ -433,11 +229,6 @@ public class Controller {
|
||||
isFirstClick = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the timer to 0
|
||||
*
|
||||
* @see #reinitialize()
|
||||
*/
|
||||
private void resetTimer() {
|
||||
URL zeroSecondURL = getClass().getResource("img/0_seconds.png");
|
||||
time_1.setImage(new Image(String.valueOf(zeroSecondURL)));
|
||||
@ -448,11 +239,6 @@ public class Controller {
|
||||
timer = new Timer();
|
||||
}
|
||||
|
||||
// todo figure out why createBlankButton errors here
|
||||
|
||||
/**
|
||||
* Refills the grid with new blank buttons
|
||||
*/
|
||||
private void resetGrid() {
|
||||
URL blank = getClass().getResource("img/blank.png");
|
||||
for (Node node : grid.getChildren()) {
|
||||
@ -461,11 +247,6 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a bomb is clicked, change the smiley, set gameOver to true.
|
||||
*
|
||||
* @param tileClicked The node that was clicked, to set the correct image
|
||||
*/
|
||||
private void gameOver(Node tileClicked) {
|
||||
gameOver = true;
|
||||
timer.cancel();
|
||||
@ -474,9 +255,6 @@ public class Controller {
|
||||
showAllBombs(GridPane.getColumnIndex(tileClicked), GridPane.getRowIndex(tileClicked));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a win state, change the smiley.
|
||||
*/
|
||||
private void win() {
|
||||
gameOver = true;
|
||||
timer.cancel();
|
||||
@ -484,9 +262,6 @@ public class Controller {
|
||||
flagAllRemaining();
|
||||
}
|
||||
|
||||
/**
|
||||
* After a win, set every bomb tile that is unflagged to flagged.
|
||||
*/
|
||||
private void flagAllRemaining() {
|
||||
int column, row;
|
||||
for (column = 0; column < 30; ++column) {
|
||||
@ -502,17 +277,12 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a flag on a tile, representing a tile that the user suspects has a bomb behind it.
|
||||
* This prevents the tile being clicked on.
|
||||
*
|
||||
* @param tileClicked The tile that the user clicks.
|
||||
*/
|
||||
private void flag(Node tileClicked) {
|
||||
Button tileAsButton = (Button) tileClicked;
|
||||
ImageView tileGraphic = (ImageView) tileAsButton.getGraphic();
|
||||
Image tileGraphicImage = tileGraphic.getImage();
|
||||
if (!tileGraphicImage.getUrl().contains("blank.png") && !tileGraphicImage.getUrl().contains("flagged.png")) {
|
||||
if (!tileGraphicImage.getUrl().contains("blank.png") &&
|
||||
!tileGraphicImage.getUrl().contains("flagged.png")) {
|
||||
return;
|
||||
}
|
||||
boolean flagged = tileGraphicImage.getUrl().contains("flagged.png");
|
||||
@ -529,30 +299,17 @@ public class Controller {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* On flag or reinitialization, update the bomb counter to represent the amount of currently flagged tiles
|
||||
*/
|
||||
private void updateBombCounter() {
|
||||
String bombCountString = String.format("%03d", bombCount);
|
||||
setBombCounterImage(bomb_2, bombCountString.charAt(1));
|
||||
setBombCounterImage(bomb_3, bombCountString.charAt(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to update the digits of the bomb counter.
|
||||
*
|
||||
* @param imageView The ImageView representing the counter digit to be changed.
|
||||
* @param digit The digit the counter should be changed to.
|
||||
* @see #updateBombCounter()
|
||||
*/
|
||||
private void setBombCounterImage(ImageView imageView, char digit) {
|
||||
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer when the user clicks or flags their first tile.
|
||||
*/
|
||||
private void scheduleTimer() {
|
||||
startTime = System.currentTimeMillis();
|
||||
TimerTask task = new TimerTask() {
|
||||
@ -568,11 +325,6 @@ public class Controller {
|
||||
timer.schedule(task, 0, 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the time since the game started, and passes it on.
|
||||
*
|
||||
* @see #setTimerImage(ImageView, char)
|
||||
*/
|
||||
private void updateTimer() {
|
||||
long elapsedTimeMillis = System.currentTimeMillis() - startTime;
|
||||
time = (int) (elapsedTimeMillis / 1000);
|
||||
@ -582,24 +334,11 @@ public class Controller {
|
||||
setTimerImage(time_3, timeString.charAt(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the timer digits individually based on updateTimer()
|
||||
*
|
||||
* @param imageView The ImageView to be updated
|
||||
* @param digit The digit to update the ImageView with
|
||||
* @see #updateTimer()
|
||||
*/
|
||||
private void setTimerImage(ImageView imageView, char digit) {
|
||||
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||
}
|
||||
|
||||
/**
|
||||
* On game over, show every bomb that was left on the grid, as well as every incorrectly flagged bomb.
|
||||
*
|
||||
* @param clickedColumn The column that caused the game over.
|
||||
* @param clickedRow The row that caused the game over.
|
||||
*/
|
||||
private void showAllBombs(int clickedColumn, int clickedRow) {
|
||||
for (Node node : grid.getChildren()) {
|
||||
Button b = (Button) node;
|
||||
@ -616,53 +355,27 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a button's graphic.
|
||||
*
|
||||
* @param button The button to change.
|
||||
* @param imagePath A path to an image to change the graphic to.
|
||||
*/
|
||||
private void setImage(Button button, String imagePath) {
|
||||
URL imageURL = getClass().getResource(imagePath);
|
||||
button.setGraphic(new ImageView(new Image(String.valueOf(imageURL), 16, 16, true, false)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces an ImageView's graphic with another.
|
||||
*
|
||||
* @param imageView The ImageView to change.
|
||||
* @param imagePath A path to an image to change the graphic to.
|
||||
*/
|
||||
private void setImage(ImageView imageView, String imagePath) {
|
||||
URL imageURL = getClass().getResource(imagePath);
|
||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the smiley with a pressed down variant when it is clicked.
|
||||
*/
|
||||
@FXML
|
||||
private void smileyPressed() {
|
||||
setImage(smiley, "img/face_smile_pressed.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the smiley from being pressed down, starts reinitialization.
|
||||
*
|
||||
* @see #reinitialize()
|
||||
*/
|
||||
@FXML
|
||||
private void smileyReleased() {
|
||||
setImage(smiley, "img/face_smile.png");
|
||||
reinitialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the graphic of a tile to indicate how many bombs are adjacent to it.
|
||||
*
|
||||
* @param tileClicked The tile to update.
|
||||
* @param adjacentBombs The number of bombs adjacent to the tile.
|
||||
*/
|
||||
private void setAdjacentCount(Node tileClicked, int adjacentBombs) {
|
||||
Button button = (Button) tileClicked;
|
||||
setImage(button, "img/num_" + adjacentBombs + ".png");
|
||||
|
@ -1,31 +1,18 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* Used to fill the GridWrapper with bombs. Planned to merge into GridWrapper.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Grid {
|
||||
/**
|
||||
* An instance of GridWrapper used to check generation of bombs.
|
||||
*/
|
||||
final GridWrapper grid = new GridWrapper();
|
||||
|
||||
/**
|
||||
* Generates the bomb-grid structure on instantiation
|
||||
*
|
||||
* @see #generateBombs(int)
|
||||
*/
|
||||
public Grid() {
|
||||
// todo fix beginner mode and intermediate!
|
||||
// sorry :3
|
||||
// 99 bombs in expert:
|
||||
generateBombs(99);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a boolean 2D array by randomly selecting a column and row, and setting it to true to represent a bomb.
|
||||
*
|
||||
* @param bombMax The number of bombs to generate.
|
||||
*/
|
||||
private void generateBombs(int bombMax) {
|
||||
int i;
|
||||
boolean success;
|
||||
|
@ -1,76 +1,33 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
/**
|
||||
* Simplifies operations on the bomb array. Preventing direct access leads to cleaner code.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GridWrapper {
|
||||
/**
|
||||
* Number of columns.
|
||||
*/
|
||||
private static final int COLUMNS = 30;
|
||||
/**
|
||||
* Number of rows.
|
||||
*/
|
||||
private static final int ROWS = 16;
|
||||
/**
|
||||
* A low level 2D array representing the position of bombs.
|
||||
*/
|
||||
final boolean[][] grid = new boolean[COLUMNS][ROWS];
|
||||
/**
|
||||
* Points at a column in grid.
|
||||
*/
|
||||
private int currentColumn;
|
||||
/**
|
||||
* Points at a row in grid.
|
||||
*/
|
||||
private int currentRow;
|
||||
|
||||
/**
|
||||
* On instantiation, initialize currentColumn and currentRow to 0
|
||||
*/
|
||||
public GridWrapper() {
|
||||
this.currentColumn = 0;
|
||||
this.currentRow = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets currentColumn to a specified column.
|
||||
*
|
||||
* @param column The column specified.
|
||||
* @return Current GridWrapper instance.
|
||||
*/
|
||||
public GridWrapper atColumn(int column) {
|
||||
this.currentColumn = column;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets currentColumn to a specified column.
|
||||
*
|
||||
* @param row The row specified.
|
||||
* @return Current GridWrapper instance.
|
||||
*/
|
||||
public GridWrapper atRow(int row) {
|
||||
this.currentRow = row;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bomb in grid at the position specified by currentColumn and currentRow.
|
||||
*/
|
||||
public void setBomb() {
|
||||
if (isValid(currentColumn, currentRow)) {
|
||||
grid[currentColumn][currentRow] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switches a bomb from one position to another.
|
||||
*
|
||||
* @param destinationColumn The new column for the bomb.
|
||||
* @param destinationRow The new row for the bomb.
|
||||
*/
|
||||
public void switchBomb(int destinationColumn, int destinationRow) {
|
||||
if (isValid(currentColumn, currentRow) && isValid(destinationColumn, destinationRow)) {
|
||||
grid[destinationColumn][destinationRow] = true;
|
||||
@ -78,20 +35,10 @@ public class GridWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a bomb at the specified position.
|
||||
*
|
||||
* @return The value in grid specified by currentColumn and currentRow.
|
||||
*/
|
||||
public boolean isBomb() {
|
||||
return isValid(currentColumn, currentRow) && grid[currentColumn][currentRow];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for bombs in every direction from the currentColumn and currentRow.
|
||||
*
|
||||
* @return The number of adjacent bombs.
|
||||
*/
|
||||
public int adjacentBombCount() {
|
||||
int count = 0;
|
||||
|
||||
@ -122,40 +69,15 @@ public class GridWrapper {
|
||||
return count;
|
||||
}
|
||||
|
||||
// todo use switchBomb
|
||||
|
||||
/**
|
||||
* Swaps one bomb with another.
|
||||
*
|
||||
* @param oldColumn The original column of the bomb.
|
||||
* @param oldRow The original row of the bomb.
|
||||
* @param newColumn The destination column of the bomb.
|
||||
* @param newRow The destination row of the bomb.
|
||||
*/
|
||||
public void updateGrid(int oldColumn, int oldRow, int newColumn, int newRow) {
|
||||
grid[oldColumn][oldRow] = false;
|
||||
grid[newColumn][newRow] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a bomb is at a specified position.
|
||||
*
|
||||
* @param column The column specified.
|
||||
* @param row The row specified.
|
||||
* @return A boolean AND representing a valid position and a bomb being present.
|
||||
* @see #isValid(int, int)
|
||||
*/
|
||||
private boolean isBombAt(int column, int row) {
|
||||
return isValid(column, row) && grid[column][row];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given column and row is in bounds.
|
||||
*
|
||||
* @param column The column provided.
|
||||
* @param row The row provided.
|
||||
* @return A boolean representing the tile being in bounds.
|
||||
*/
|
||||
private boolean isValid(int column, int row) {
|
||||
return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
@ -9,17 +8,7 @@ import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* The application opening point, used to bootstrap JavaFX and open to the GUI.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Main extends Application {
|
||||
/**
|
||||
* JavaFX opening method. Creates the stage and bootstraps the application.
|
||||
*
|
||||
* @param stage The stage object passed in by JavaFX.
|
||||
* @throws IOException If the FXML template or app icon are not found in resources.
|
||||
*/
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
Image icon = new Image(String.valueOf(getClass().getResource("winmine.png")));
|
||||
@ -32,19 +21,10 @@ public class Main extends Application {
|
||||
stage.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Application opening method. Calls the JavaFX start method.
|
||||
*
|
||||
* @param args Optional commandline parameters, unimplemented.
|
||||
* @see #start(Stage)
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
launch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the timer on application stop.
|
||||
*/
|
||||
@Override
|
||||
@FXML
|
||||
public void stop() {
|
||||
|
@ -1,8 +1,3 @@
|
||||
/**
|
||||
* The main module for the program. Required to launch to JavaFX as well as bundle into a native binary.
|
||||
* @author shrapnelnet admin@shr4pnel.com
|
||||
* @since 1.0.0
|
||||
*/
|
||||
module libremines {
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
|
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.image.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
|
||||
<AnchorPane prefHeight="225.0" prefWidth="454.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<ImageView fitHeight="150.0" fitWidth="200.0" layoutX="146.0" layoutY="31.0" pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@winmine.png" />
|
||||
</image>
|
||||
</ImageView>
|
||||
<Text layoutY="42.0" strokeType="OUTSIDE" strokeWidth="0.0" text="made with love - shrapnelnet" textAlignment="CENTER" wrappingWidth="454.0">
|
||||
<font>
|
||||
<Font name="Source Code Pro" size="13.0" />
|
||||
</font>
|
||||
</Text>
|
||||
<Text layoutY="183.0" strokeType="OUTSIDE" strokeWidth="0.0" text="greeTz: b4rkod, ping, cockpit, vulon, i330 n' porcupine" textAlignment="CENTER" wrappingWidth="454.0">
|
||||
<font>
|
||||
<Font name="Source Code Pro" size="13.0" />
|
||||
</font>
|
||||
</Text>
|
||||
<Text layoutY="200.0" strokeType="OUTSIDE" strokeWidth="0.0" text="next time make your own!" textAlignment="CENTER" wrappingWidth="454.0">
|
||||
<font>
|
||||
<Font name="Source Code Pro" size="13.0" />
|
||||
</font>
|
||||
</Text>
|
||||
|
||||
</children>
|
||||
</AnchorPane>
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB |
@ -8,7 +8,7 @@
|
||||
|
||||
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="500.0" style="-fx-border-color: black; -fx-border-width: 1px;" stylesheets="@fix-glow.css" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.shr4pnel.minesweeper.Controller">
|
||||
<children>
|
||||
<MenuBar prefWidth="498.0" style="-fx-background-color: white;">
|
||||
<MenuBar style="-fx-background-color: white;">
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="Game">
|
||||
<items>
|
||||
@ -23,7 +23,7 @@
|
||||
<ToggleGroup fx:id="difficulty" />
|
||||
</toggleGroup>
|
||||
</RadioMenuItem>
|
||||
<RadioMenuItem mnemonicParsing="false" text="Intermediate" toggleGroup="$difficulty" />
|
||||
<RadioMenuItem mnemonicParsing="false" text="Internmediate" toggleGroup="$difficulty" />
|
||||
<RadioMenuItem mnemonicParsing="false" selected="true" text="Expert" toggleGroup="$difficulty" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<RadioMenuItem fx:id="marks" mnemonicParsing="false" selected="true" text="Marks (?)" />
|
||||
@ -36,7 +36,7 @@
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Help">
|
||||
<items>
|
||||
<MenuItem fx:id="about" mnemonicParsing="false" text="About Minesweeper" />
|
||||
<MenuItem mnemonicParsing="false" text="About Minesweeper" />
|
||||
</items>
|
||||
</Menu>
|
||||
</menus>
|
||||
|
@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.image.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
|
||||
|
||||
<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="420.0" prefWidth="525.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<ImageView fitHeight="420.0" fitWidth="531.0" pickOnBounds="true" preserveRatio="true">
|
||||
<image>
|
||||
<Image url="@img/204.jpg" />
|
||||
</image>
|
||||
</ImageView>
|
||||
</children>
|
||||
</Pane>
|
Loading…
x
Reference in New Issue
Block a user