9 Commits

Author SHA1 Message Date
2827d79556 Win condition, flagging underflow fix 2024-07-23 18:54:23 +01:00
shr4pnel
367ad5921a Update README.md 2024-06-16 11:20:28 +01:00
shr4pnel
fd82088a08 Update README.md 2024-06-16 11:19:48 +01:00
8e836b1183 fix button glow 2024-06-16 10:36:27 +01:00
44125ce13a Add not yet implemented messages 2024-06-16 10:31:10 +01:00
76b44d22cf clarify mvn reqs in readme 2024-06-16 10:21:58 +01:00
d19f9899cf Fix initial bomb moving adjacency logic 2024-06-16 10:20:40 +01:00
shr4pnel
7e536cf644 Update README.md 2024-06-11 23:44:27 +01:00
shr4pnel
f5c63f9401 Update README.md 2024-06-10 22:51:41 +01:00
4 changed files with 84 additions and 13 deletions

View File

@@ -2,6 +2,9 @@
"named this way because i didn't realise there was another libremines!"
![Libremines screenshot](https://github.com/shrapnelnet/libremines/assets/133451255/f19e0006-a587-4f39-8626-67606db7cd58)
## Building
### Requirements:
@@ -11,14 +14,13 @@
### Instructions:
Optional, create maven wrapper:
Create the maven wrapper. gluonfx does not like versions of maven that are not 3.8.8:
```shell
mvn wrapper:wrapper
mvn wrapper:wrapper -Dmaven=3.8.8
```
This is helpful for version management, in case you have an incompatible version of maven installed, but most people will not need this.
This is helpful for version management, in case you have an incompatible version of maven installed.
Install dependencies:
```shell
@@ -31,4 +33,4 @@ Build and run:
GRAALVM_HOME=/path/to/graalvm ./mvnw gluonfx:build
```
A native binary should be placed at `target/gluonfx/<your architecture>/libremines`
A native binary should be placed at `target/gluonfx/<your architecture>/libremines`

View File

@@ -4,9 +4,11 @@ import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
@@ -20,6 +22,9 @@ public class Controller {
@FXML
private ImageView smiley, time_1, time_2, time_3, bomb_2, bomb_3;
@FXML
private RadioMenuItem color, marks;
private Grid gridHandler;
private GridWrapper wrapper;
private boolean gameOver = false;
@@ -33,12 +38,18 @@ public class Controller {
@FXML
private void initialize() {
setNotYetImplemented(color);
setNotYetImplemented(marks);
setupGrid();
gridHandler = new Grid();
wrapper = gridHandler.grid;
expandedTiles = new boolean[30][16];
}
private void setNotYetImplemented(RadioMenuItem node) {
node.setOnAction((ActionEvent e) -> System.out.println("https://http.cat/images/501.jpg"));
}
private void setupGrid() {
for (int column = 0; column < 30; ++column) {
for (int row = 0; row < 16; ++row) {
@@ -109,6 +120,33 @@ public class Controller {
return null;
}
private String getButtonURL(Button button) {
ImageView graphic = (ImageView) button.getGraphic();
Image image = graphic.getImage();
return image.getUrl();
}
private int numberOfUnrevealedTiles() {
int unrevealedTiles = 0;
int column, row;
for (column = 0; column < 30; ++column) {
for (row = 0; row < 16; ++row) {
Button current = (Button) getNodeByRowColumnIndex(row, column);
assert current != null;
String currentURL = getButtonURL(current);
if (currentURL.contains("blank.png") || currentURL.contains("flag.png")) {
unrevealedTiles++;
}
}
}
return unrevealedTiles;
}
private boolean checkWinCondition() {
int unrevealedTiles = numberOfUnrevealedTiles();
return unrevealedTiles == 99;
}
private void handlePrimaryClick(Button clicked, int column, int row) {
if (wrapper.atColumn(column).atRow(row).isBomb() && !isFirstClick) {
gameOver(clicked);
@@ -122,14 +160,18 @@ public class Controller {
int rowMovedTo = chosenColumnAndRow[1];
wrapper.atColumn(column).atRow(row).switchBomb(columnMovedTo, rowMovedTo);
recursiveExpandTiles(column, row);
isFirstClick = false;
clicked = (Button) getNodeByRowColumnIndex(row, column);
}
isFirstClick = false;
int adjacentBombs = wrapper.adjacentBombCount();
setAdjacentCount(clicked, adjacentBombs);
if (adjacentBombs == 0) {
recursiveExpandTiles(column, row);
}
boolean win = checkWinCondition();
if (win) {
win();
}
}
private void recursiveExpandTiles(int column, int row) {
@@ -213,6 +255,28 @@ public class Controller {
showAllBombs(GridPane.getColumnIndex(tileClicked), GridPane.getRowIndex(tileClicked));
}
private void win() {
gameOver = true;
timer.cancel();
setImage(smiley, "img/face_win.png");
flagAllRemaining();
}
private void flagAllRemaining() {
int column, row;
for (column = 0; column < 30; ++column) {
for (row = 0; row < 16; ++row) {
Button current = (Button) getNodeByRowColumnIndex(row, column);
assert current != null;
String currentURL = getButtonURL(current);
boolean tileIsBomb = wrapper.atColumn(column).atRow(row).isBomb();
if (currentURL.contains("blank.png") && tileIsBomb) {
setImage(current, "img/bomb_flagged.png");
}
}
}
}
private void flag(Node tileClicked) {
Button tileAsButton = (Button) tileClicked;
ImageView tileGraphic = (ImageView) tileAsButton.getGraphic();
@@ -229,7 +293,8 @@ public class Controller {
return;
}
bombCount--;
updateBombCounter();
if (bombCount > 0)
updateBombCounter();
setImage((Button) tileClicked, "img/bomb_flagged.png");
}
@@ -280,8 +345,8 @@ public class Controller {
String buttonURL = ((ImageView) b.getGraphic()).getImage().getUrl();
int column = GridPane.getColumnIndex(node);
int row = GridPane.getRowIndex(node);
if (!(column == clickedColumn && row == clickedRow) &&
wrapper.atColumn(column).atRow(row).isBomb()) {
// if the tile isn't the one that was clicked AND the tile is a bomb
if (!(column == clickedColumn && row == clickedRow) && wrapper.atColumn(column).atRow(row).isBomb()) {
setImage((Button) node, "img/bomb_revealed.png");
}
if (buttonURL.contains("flagged.png") && !wrapper.atColumn(column).atRow(row).isBomb()) {

View File

@@ -0,0 +1,4 @@
* {
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
}

View File

@@ -6,7 +6,7 @@
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="350.0" prefWidth="500.0" style="-fx-border-color: black; -fx-border-width: 1px;" xmlns="http://javafx.com/javafx/11.0.14-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.shr4pnel.minesweeper.Controller">
<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 style="-fx-background-color: white;">
<menus>
@@ -26,8 +26,8 @@
<RadioMenuItem mnemonicParsing="false" text="Internmediate" toggleGroup="$difficulty" />
<RadioMenuItem mnemonicParsing="false" selected="true" text="Expert" toggleGroup="$difficulty" />
<SeparatorMenuItem mnemonicParsing="false" />
<RadioMenuItem mnemonicParsing="false" selected="true" text="Marks (?)" />
<RadioMenuItem mnemonicParsing="false" selected="true" text="Color" />
<RadioMenuItem fx:id="marks" mnemonicParsing="false" selected="true" text="Marks (?)" />
<RadioMenuItem fx:id="color" mnemonicParsing="false" selected="true" text="Color" />
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem mnemonicParsing="false" style="-fx-padding-right: 15; -fx-border-insets: 10px; -fx-background-insets: 10px;" text="Best Times..." />
<SeparatorMenuItem mnemonicParsing="false" />