Compare commits

..

No commits in common. "ea70aa5181d79086b70ef91eddbc072c39f754f3" and "d681f20b90d22e764b0a498ca4c0139c28bd3804" have entirely different histories.

3 changed files with 35 additions and 115 deletions

View File

@ -8,23 +8,11 @@
### Requirements: ### Requirements:
- Java 21 - Java 21
- Maven - Maven 3.8.8 or lower
- 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
@ -38,3 +26,9 @@ 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
```

View File

@ -2,7 +2,6 @@ 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;
@ -237,70 +236,25 @@ 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 int adjacentFlagCount(int column, int row) { // private void chord(Button clicked, String clickedURL) {
int flagCount = 0; // int column = GridPane.getColumnIndex(clicked);
for (int innerColumn = column - 1; innerColumn <= column + 1; innerColumn++) { // int row = GridPane.getRowIndex(clicked);
for (int innerRow = row - 1; innerRow <= row + 1; innerRow++) { // int urlLength = clickedURL.length();
if (innerColumn == column && innerRow == row) // char expectedAdjacentChar = clickedURL.charAt(urlLength-5);
continue; // int expectedAdjacent = Integer.parseInt(Character.toString(expectedAdjacentChar));
// int actualAdjacent = wrapper.atColumn(column).atRow(row).adjacentBombCount();
if (!wrapper.atColumn(innerColumn).atRow(innerRow).isValid()) { // if (expectedAdjacent != actualAdjacent) {
continue; // return;
} // }
// // 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
@ -319,8 +273,8 @@ public class Controller {
} }
} }
} }
System.out.println("If you see this, congrats! this should never happen. please email me."); // this realistically should never happen... sorry!
return new int[]{0, 0}; return null;
} }
/** /**
@ -336,8 +290,7 @@ 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
*/ */
@ -346,11 +299,8 @@ 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) getNodeByColumnRowIndex(column, row); Button current = (Button) getNodeByRowColumnIndex(row, column);
// this will hopefully never happen..... or will it ...... assert current != null;
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++;
@ -385,11 +335,13 @@ 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) getNodeByColumnRowIndex(column, row); clicked = (Button) getNodeByRowColumnIndex(row, column);
} }
isFirstClick = false; isFirstClick = false;
int adjacentBombs = wrapper.adjacentBombCount(); int adjacentBombs = wrapper.adjacentBombCount();
@ -435,7 +387,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 = getNodeByColumnRowIndex(column, row); Node tile = getNodeByRowColumnIndex(row, column);
if (tile != null) { if (tile != null) {
Button button = (Button) tile; Button button = (Button) tile;
if (button.isVisible()) { if (button.isVisible()) {
@ -449,23 +401,6 @@ 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
* *
@ -473,7 +408,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 getNodeByColumnRowIndex(int column, int row) { private Node getNodeByRowColumnIndex(int row, int column) {
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;
@ -556,7 +491,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) getNodeByColumnRowIndex(column, row); Button current = (Button) getNodeByRowColumnIndex(row, column);
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();

View File

@ -159,13 +159,4 @@ 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;
}
} }