Compare commits
5 Commits
d681f20b90
...
ea70aa5181
Author | SHA1 | Date | |
---|---|---|---|
ea70aa5181 | |||
ef8050a5f9 | |||
7d7e660c77 | |||
acaa18ffcc | |||
c781b364d8 |
22
README.md
22
README.md
@ -8,11 +8,23 @@
|
|||||||
|
|
||||||
### Requirements:
|
### Requirements:
|
||||||
- Java 21
|
- Java 21
|
||||||
- Maven 3.8.8 or lower
|
- Maven
|
||||||
- GraalVM 21
|
|
||||||
|
|
||||||
### Instructions:
|
### Instructions:
|
||||||
|
|
||||||
|
This will automatically fetch dependencies and run the project:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
./mvnw javafx:run
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Native Image:
|
||||||
|
|
||||||
|
##### Requirements:
|
||||||
|
- GraalVM
|
||||||
|
- Maven 3.8.8
|
||||||
|
|
||||||
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 at version 3.8.8. GluonFX does not work with newer versions as of 2024-07-27.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@ -26,9 +38,3 @@ Install dependencies, build and run:
|
|||||||
```
|
```
|
||||||
|
|
||||||
A native binary should be placed at `target/gluonfx/<your architecture>/libremines`
|
A native binary should be placed at `target/gluonfx/<your architecture>/libremines`
|
||||||
|
|
||||||
Alternatively, to run using the JVM, use:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./mvnw javafx:run
|
|
||||||
```
|
|
||||||
|
@ -2,6 +2,7 @@ package com.shr4pnel.minesweeper;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
@ -236,25 +237,70 @@ public class Controller {
|
|||||||
if (buttonImage.getUrl().contains("flagged.png")) {
|
if (buttonImage.getUrl().contains("flagged.png")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// if (buttonImage.getUrl().contains("num") && !buttonImage.getUrl().contains("num_0.png")) {
|
if (buttonImage.getUrl().contains("num") && !buttonImage.getUrl().contains("num_0.png")) {
|
||||||
// chord(clicked, buttonImage.getUrl());
|
chord(clicked, buttonImage.getUrl());
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
handlePrimaryClick(clicked, column, row);
|
handlePrimaryClick(clicked, column, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void chord(Button clicked, String clickedURL) {
|
private int adjacentFlagCount(int column, int row) {
|
||||||
// int column = GridPane.getColumnIndex(clicked);
|
int flagCount = 0;
|
||||||
// int row = GridPane.getRowIndex(clicked);
|
for (int innerColumn = column - 1; innerColumn <= column + 1; innerColumn++) {
|
||||||
// int urlLength = clickedURL.length();
|
for (int innerRow = row - 1; innerRow <= row + 1; innerRow++) {
|
||||||
// char expectedAdjacentChar = clickedURL.charAt(urlLength-5);
|
if (innerColumn == column && innerRow == row)
|
||||||
// int expectedAdjacent = Integer.parseInt(Character.toString(expectedAdjacentChar));
|
continue;
|
||||||
// int actualAdjacent = wrapper.atColumn(column).atRow(row).adjacentBombCount();
|
|
||||||
// if (expectedAdjacent != actualAdjacent) {
|
if (!wrapper.atColumn(innerColumn).atRow(innerRow).isValid()) {
|
||||||
// return;
|
continue;
|
||||||
// }
|
}
|
||||||
// // chord logic
|
|
||||||
// }
|
Button b = (Button) getNodeByColumnRowIndex(innerColumn, innerRow);
|
||||||
|
String bURL = getButtonURL(b);
|
||||||
|
if (bURL.contains("flag")) {
|
||||||
|
flagCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flagCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Button[] chordTilesToOpen(int column, int row) {
|
||||||
|
ArrayList<Button> buttons = new ArrayList<>(8);
|
||||||
|
for (int innerColumn = column - 1; innerColumn <= column + 1; innerColumn++) {
|
||||||
|
for (int innerRow = row - 1; innerRow <= row + 1; innerRow++) {
|
||||||
|
if (innerColumn == column && innerRow == row)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!wrapper.atColumn(innerColumn).atRow(innerRow).isValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Button b = (Button) getNodeByColumnRowIndex(innerColumn, innerRow);
|
||||||
|
String bURL = getButtonURL(b);
|
||||||
|
// if the tile is unflagged and unopened:
|
||||||
|
if (bURL.contains("blank")) {
|
||||||
|
buttons.add(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buttons.toArray(Button[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void chord(Button clicked, String clickedURL) {
|
||||||
|
int column = GridPane.getColumnIndex(clicked);
|
||||||
|
int row = GridPane.getRowIndex(clicked);
|
||||||
|
int urlLength = clickedURL.length();
|
||||||
|
char requiredAdjacentChar = clickedURL.charAt(urlLength-5);
|
||||||
|
int requiredAdjacent = Integer.parseInt(Character.toString(requiredAdjacentChar));
|
||||||
|
int actualAdjacent = adjacentFlagCount(column, row);
|
||||||
|
if (requiredAdjacent != actualAdjacent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Button[] buttons = chordTilesToOpen(column, row);
|
||||||
|
for (Button b: buttons) {
|
||||||
|
expandTile(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the first tile clicked was a bomb, move that bomb to the first available column on row 0 before opening it
|
* If the first tile clicked was a bomb, move that bomb to the first available column on row 0 before opening it
|
||||||
@ -273,8 +319,8 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// this realistically should never happen... sorry!
|
System.out.println("If you see this, congrats! this should never happen. please email me.");
|
||||||
return null;
|
return new int[]{0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -290,7 +336,8 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates through the grid to find all tiles that are either blank or flagged
|
* Iterates through the grid to find all tiles that are either blank or flagged.
|
||||||
|
* Used to check if win condition has been met
|
||||||
*
|
*
|
||||||
* @return The number of tiles that were blank or flagged
|
* @return The number of tiles that were blank or flagged
|
||||||
*/
|
*/
|
||||||
@ -299,8 +346,11 @@ public class Controller {
|
|||||||
int column, row;
|
int column, row;
|
||||||
for (column = 0; column < 30; ++column) {
|
for (column = 0; column < 30; ++column) {
|
||||||
for (row = 0; row < 16; ++row) {
|
for (row = 0; row < 16; ++row) {
|
||||||
Button current = (Button) getNodeByRowColumnIndex(row, column);
|
Button current = (Button) getNodeByColumnRowIndex(column, row);
|
||||||
assert current != null;
|
// this will hopefully never happen..... or will it ......
|
||||||
|
if (current == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
String currentURL = getButtonURL(current);
|
String currentURL = getButtonURL(current);
|
||||||
if (currentURL.contains("blank.png") || currentURL.contains("flagged.png")) {
|
if (currentURL.contains("blank.png") || currentURL.contains("flagged.png")) {
|
||||||
unrevealedTiles++;
|
unrevealedTiles++;
|
||||||
@ -335,13 +385,11 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
if (wrapper.isBomb() && isFirstClick) {
|
if (wrapper.isBomb() && isFirstClick) {
|
||||||
int[] chosenColumnAndRow = setBombIfFirstTileIsBomb(column, row);
|
int[] chosenColumnAndRow = setBombIfFirstTileIsBomb(column, row);
|
||||||
// assertions are evil but i dont care
|
|
||||||
assert chosenColumnAndRow != null;
|
|
||||||
int columnMovedTo = chosenColumnAndRow[0];
|
int columnMovedTo = chosenColumnAndRow[0];
|
||||||
int rowMovedTo = chosenColumnAndRow[1];
|
int rowMovedTo = chosenColumnAndRow[1];
|
||||||
wrapper.atColumn(column).atRow(row).switchBomb(columnMovedTo, rowMovedTo);
|
wrapper.atColumn(column).atRow(row).switchBomb(columnMovedTo, rowMovedTo);
|
||||||
recursiveExpandTiles(column, row);
|
recursiveExpandTiles(column, row);
|
||||||
clicked = (Button) getNodeByRowColumnIndex(row, column);
|
clicked = (Button) getNodeByColumnRowIndex(column, row);
|
||||||
}
|
}
|
||||||
isFirstClick = false;
|
isFirstClick = false;
|
||||||
int adjacentBombs = wrapper.adjacentBombCount();
|
int adjacentBombs = wrapper.adjacentBombCount();
|
||||||
@ -387,7 +435,7 @@ public class Controller {
|
|||||||
* @param row The row of the button to open
|
* @param row The row of the button to open
|
||||||
*/
|
*/
|
||||||
private void expandTile(int column, int row) {
|
private void expandTile(int column, int row) {
|
||||||
Node tile = getNodeByRowColumnIndex(row, column);
|
Node tile = getNodeByColumnRowIndex(column, row);
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
Button button = (Button) tile;
|
Button button = (Button) tile;
|
||||||
if (button.isVisible()) {
|
if (button.isVisible()) {
|
||||||
@ -401,6 +449,23 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void expandTile(Button button) {
|
||||||
|
Node node = (Node) button;
|
||||||
|
int column = GridPane.getColumnIndex(node);
|
||||||
|
int row = GridPane.getRowIndex(node);
|
||||||
|
if (wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||||
|
gameOver(node);
|
||||||
|
}
|
||||||
|
if (button.isVisible()) {
|
||||||
|
int adjacentBombs = wrapper.atColumn(column).atRow(row).adjacentBombCount();
|
||||||
|
setAdjacentCount(button, adjacentBombs);
|
||||||
|
if (adjacentBombs == 0 && !expandedTiles[column][row]) {
|
||||||
|
expandedTiles[column][row] = true;
|
||||||
|
recursiveExpandTiles(column, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over the grid and returns the node when it's at the correct child
|
* Iterates over the grid and returns the node when it's at the correct child
|
||||||
*
|
*
|
||||||
@ -408,7 +473,7 @@ public class Controller {
|
|||||||
* @param column The desired column to find
|
* @param column The desired column to find
|
||||||
* @return The node at the specified position
|
* @return The node at the specified position
|
||||||
*/
|
*/
|
||||||
private Node getNodeByRowColumnIndex(int row, int column) {
|
private Node getNodeByColumnRowIndex(int column, int row) {
|
||||||
for (Node node : grid.getChildren()) {
|
for (Node node : grid.getChildren()) {
|
||||||
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
|
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
|
||||||
return node;
|
return node;
|
||||||
@ -491,7 +556,7 @@ public class Controller {
|
|||||||
int column, row;
|
int column, row;
|
||||||
for (column = 0; column < 30; ++column) {
|
for (column = 0; column < 30; ++column) {
|
||||||
for (row = 0; row < 16; ++row) {
|
for (row = 0; row < 16; ++row) {
|
||||||
Button current = (Button) getNodeByRowColumnIndex(row, column);
|
Button current = (Button) getNodeByColumnRowIndex(column, row);
|
||||||
assert current != null;
|
assert current != null;
|
||||||
String currentURL = getButtonURL(current);
|
String currentURL = getButtonURL(current);
|
||||||
boolean tileIsBomb = wrapper.atColumn(column).atRow(row).isBomb();
|
boolean tileIsBomb = wrapper.atColumn(column).atRow(row).isBomb();
|
||||||
|
@ -159,4 +159,13 @@ public class GridWrapper {
|
|||||||
private boolean isValid(int column, int row) {
|
private boolean isValid(int column, int row) {
|
||||||
return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
|
return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a given column and row is in bounds using local state
|
||||||
|
*
|
||||||
|
* @return A boolean representing the tile being in bounds.
|
||||||
|
*/
|
||||||
|
public boolean isValid() {
|
||||||
|
return this.currentColumn >= 0 && this.currentColumn < COLUMNS && this.currentRow >= 0 && this.currentRow < ROWS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user