in my anger, switch to maven
This commit is contained in:
275
src/main/java/com/shr4pnel/minesweeper/Controller.java
Normal file
275
src/main/java/com/shr4pnel/minesweeper/Controller.java
Normal file
@@ -0,0 +1,275 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
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;
|
||||
|
||||
public class Controller {
|
||||
@FXML
|
||||
private GridPane grid;
|
||||
|
||||
@FXML
|
||||
private ImageView smiley, time_1, time_2, time_3, bomb_2, bomb_3;
|
||||
|
||||
private Grid gridHandler;
|
||||
private GridWrapper wrapper;
|
||||
private boolean gameOver = false;
|
||||
private boolean isFirstLoad = true;
|
||||
static Timer timer = new Timer();
|
||||
private int time = 0;
|
||||
private long startTime;
|
||||
private int bombCount = 99;
|
||||
private boolean[][] expandedTiles;
|
||||
|
||||
@FXML
|
||||
private void initialize() {
|
||||
setupGrid();
|
||||
gridHandler = new Grid();
|
||||
wrapper = gridHandler.grid;
|
||||
expandedTiles = new boolean[30][16];
|
||||
|
||||
}
|
||||
|
||||
private void setupGrid() {
|
||||
for (int column = 0; column < 30; ++column) {
|
||||
for (int row = 0; row < 16; ++row) {
|
||||
Button blankButton = createBlankButton();
|
||||
grid.add(blankButton, column, row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Button createBlankButton() {
|
||||
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);
|
||||
blankButton.setMinSize(16, 16);
|
||||
blankButton.setOnMouseClicked(this::buttonClicked);
|
||||
return blankButton;
|
||||
}
|
||||
|
||||
private void buttonClicked(MouseEvent e) {
|
||||
if (gameOver) {
|
||||
return;
|
||||
}
|
||||
Button clicked = (Button) e.getSource();
|
||||
ImageView buttonImageView = (ImageView) clicked.getGraphic();
|
||||
Image buttonImage = buttonImageView.getImage();
|
||||
int column = GridPane.getColumnIndex(clicked);
|
||||
int row = GridPane.getRowIndex(clicked);
|
||||
if (isFirstLoad) {
|
||||
scheduleTimer();
|
||||
isFirstLoad = false;
|
||||
}
|
||||
if (e.getButton() == MouseButton.SECONDARY) {
|
||||
flag(clicked);
|
||||
return;
|
||||
}
|
||||
if (buttonImage.getUrl().contains("flagged.png")) {
|
||||
return;
|
||||
}
|
||||
handlePrimaryClick(clicked, column, row);
|
||||
}
|
||||
|
||||
private void handlePrimaryClick(Button clicked, int column, int row) {
|
||||
if (wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||
gameOver(clicked);
|
||||
return;
|
||||
}
|
||||
int adjacentBombs = wrapper.adjacentBombCount();
|
||||
setAdjacentCount(clicked, adjacentBombs);
|
||||
if (adjacentBombs == 0) {
|
||||
recursiveExpandTiles(column, row);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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()) {
|
||||
return;
|
||||
}
|
||||
expandTile(column, row);
|
||||
if (wrapper.atColumn(column).atRow(row).adjacentBombCount() == 0) {
|
||||
recursiveExpandTiles(column, row - 1);
|
||||
recursiveExpandTiles(column + 1, row - 1);
|
||||
recursiveExpandTiles(column + 1, row);
|
||||
recursiveExpandTiles(column + 1, row + 1);
|
||||
recursiveExpandTiles(column, row + 1);
|
||||
recursiveExpandTiles(column - 1, row + 1);
|
||||
recursiveExpandTiles(column - 1, row);
|
||||
recursiveExpandTiles(column - 1, row - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void expandTile(int column, int row) {
|
||||
Node tile = getNodeByRowColumnIndex(row, column);
|
||||
if (tile != null) {
|
||||
Button button = (Button) tile;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Node getNodeByRowColumnIndex(int row, int column) {
|
||||
for (Node node : grid.getChildren()) {
|
||||
if (GridPane.getRowIndex(node) == row && GridPane.getColumnIndex(node) == column) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void reinitialize() {
|
||||
bombCount = 99;
|
||||
updateBombCounter();
|
||||
resetTimer();
|
||||
resetGrid();
|
||||
gridHandler = new Grid();
|
||||
wrapper = gridHandler.grid;
|
||||
expandedTiles = new boolean[30][16];
|
||||
}
|
||||
|
||||
private void resetTimer() {
|
||||
URL zeroSecondURL = getClass().getResource("img/0_seconds.png");
|
||||
time_1.setImage(new Image(String.valueOf(zeroSecondURL)));
|
||||
time_2.setImage(new Image(String.valueOf(zeroSecondURL)));
|
||||
time_3.setImage(new Image(String.valueOf(zeroSecondURL)));
|
||||
timer.cancel();
|
||||
isFirstLoad = true;
|
||||
timer = new Timer();
|
||||
}
|
||||
|
||||
private void resetGrid() {
|
||||
URL blank = getClass().getResource("img/blank.png");
|
||||
for (Node node : grid.getChildren()) {
|
||||
Button button = (Button) node;
|
||||
button.setGraphic(new ImageView(new Image(String.valueOf(blank), 16, 16, true, false)));
|
||||
}
|
||||
}
|
||||
|
||||
private void gameOver(Node tileClicked) {
|
||||
gameOver = true;
|
||||
timer.cancel();
|
||||
setImage(smiley, "img/face_dead.png");
|
||||
setImage((Button) tileClicked, "img/bomb_death.png");
|
||||
showAllBombs(GridPane.getColumnIndex(tileClicked), GridPane.getRowIndex(tileClicked));
|
||||
}
|
||||
|
||||
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")) {
|
||||
return;
|
||||
}
|
||||
boolean flagged = tileGraphicImage.getUrl().contains("flagged.png");
|
||||
if (flagged) {
|
||||
bombCount++;
|
||||
setImage(tileAsButton, "img/blank.png");
|
||||
updateBombCounter();
|
||||
return;
|
||||
}
|
||||
bombCount--;
|
||||
updateBombCounter();
|
||||
setImage((Button) tileClicked, "img/bomb_flagged.png");
|
||||
|
||||
}
|
||||
|
||||
private void updateBombCounter() {
|
||||
String bombCountString = String.format("%03d", bombCount);
|
||||
setBombCounterImage(bomb_2, bombCountString.charAt(1));
|
||||
setBombCounterImage(bomb_3, bombCountString.charAt(2));
|
||||
}
|
||||
|
||||
private void setBombCounterImage(ImageView imageView, char digit) {
|
||||
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||
}
|
||||
|
||||
private void scheduleTimer() {
|
||||
startTime = System.currentTimeMillis();
|
||||
TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (time >= 999) {
|
||||
timer.cancel();
|
||||
} else {
|
||||
updateTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
timer.schedule(task, 0, 1000);
|
||||
}
|
||||
|
||||
private void updateTimer() {
|
||||
long elapsedTimeMillis = System.currentTimeMillis() - startTime;
|
||||
time = (int) (elapsedTimeMillis / 1000);
|
||||
String timeString = String.format("%03d", time);
|
||||
setTimerImage(time_1, timeString.charAt(0));
|
||||
setTimerImage(time_2, timeString.charAt(1));
|
||||
setTimerImage(time_3, timeString.charAt(2));
|
||||
}
|
||||
|
||||
private void setTimerImage(ImageView imageView, char digit) {
|
||||
URL imageURL = getClass().getResource("img/" + digit + "_seconds.png");
|
||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||
}
|
||||
|
||||
private void showAllBombs(int clickedColumn, int clickedRow) {
|
||||
for (Node node : grid.getChildren()) {
|
||||
int column = GridPane.getColumnIndex(node);
|
||||
int row = GridPane.getRowIndex(node);
|
||||
if (!(column == clickedColumn && row == clickedRow) &&
|
||||
wrapper.atColumn(column).atRow(row).isBomb()) {
|
||||
setImage((Button) node, "img/bomb_revealed.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
private void setImage(ImageView imageView, String imagePath) {
|
||||
URL imageURL = getClass().getResource(imagePath);
|
||||
imageView.setImage(new Image(String.valueOf(imageURL)));
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void smileyPressed() {
|
||||
setImage(smiley, "img/face_smile_pressed.png");
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void smileyReleased() {
|
||||
gameOver = false;
|
||||
setImage(smiley, "img/face_smile.png");
|
||||
reinitialize();
|
||||
}
|
||||
|
||||
private void setAdjacentCount(Node tileClicked, int adjacentBombs) {
|
||||
Button button = (Button) tileClicked;
|
||||
URL imageURL = getClass().getResource("img/num_" + adjacentBombs + ".png");
|
||||
button.setGraphic(new ImageView(new Image(String.valueOf(imageURL), 16, 16, true, false)));
|
||||
}
|
||||
}
|
32
src/main/java/com/shr4pnel/minesweeper/Grid.java
Normal file
32
src/main/java/com/shr4pnel/minesweeper/Grid.java
Normal file
@@ -0,0 +1,32 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class Grid {
|
||||
final GridWrapper grid = new GridWrapper();
|
||||
|
||||
public Grid() {
|
||||
// todo fix beginner mode and intermediate!
|
||||
// sorry :3
|
||||
// 99 bombs in expert:
|
||||
generateBombs(99);
|
||||
}
|
||||
|
||||
private void generateBombs(int bombMax) {
|
||||
int i;
|
||||
boolean success;
|
||||
for (i = 0; i < bombMax; ++i) {
|
||||
success = false;
|
||||
while (!success) {
|
||||
int column = ThreadLocalRandom.current().nextInt(30);
|
||||
int row = ThreadLocalRandom.current().nextInt(16);
|
||||
if (grid.atColumn(column).atRow(row).isBomb()) {
|
||||
continue;
|
||||
}
|
||||
grid.atColumn(column).atRow(row).setBomb();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
72
src/main/java/com/shr4pnel/minesweeper/GridWrapper.java
Normal file
72
src/main/java/com/shr4pnel/minesweeper/GridWrapper.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
public class GridWrapper {
|
||||
private static final int COLUMNS = 30;
|
||||
private static final int ROWS = 16;
|
||||
final boolean[][] grid = new boolean[COLUMNS][ROWS];
|
||||
private int currentColumn;
|
||||
private int currentRow;
|
||||
|
||||
public GridWrapper() {
|
||||
this.currentColumn = 0;
|
||||
this.currentRow = 0;
|
||||
}
|
||||
|
||||
public GridWrapper atColumn(int column) {
|
||||
this.currentColumn = column;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GridWrapper atRow(int row) {
|
||||
this.currentRow = row;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setBomb() {
|
||||
if (isValid(currentColumn, currentRow)) {
|
||||
grid[currentColumn][currentRow] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBomb() {
|
||||
return isValid(currentColumn, currentRow) && grid[currentColumn][currentRow];
|
||||
}
|
||||
|
||||
public int adjacentBombCount() {
|
||||
int count = 0;
|
||||
|
||||
if (isBombAt(currentColumn - 1, currentRow - 1)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn, currentRow - 1)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn + 1, currentRow - 1)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn - 1, currentRow)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn + 1, currentRow)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn - 1, currentRow + 1)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn, currentRow + 1)) {
|
||||
count++;
|
||||
}
|
||||
if (isBombAt(currentColumn + 1, currentRow + 1)) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private boolean isBombAt(int column, int row) {
|
||||
return isValid(column, row) && grid[column][row];
|
||||
}
|
||||
|
||||
private boolean isValid(int column, int row) {
|
||||
return column >= 0 && column < COLUMNS && row >= 0 && row < ROWS;
|
||||
}
|
||||
}
|
33
src/main/java/com/shr4pnel/minesweeper/Main.java
Normal file
33
src/main/java/com/shr4pnel/minesweeper/Main.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package com.shr4pnel.minesweeper;
|
||||
|
||||
import java.io.IOException;
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class Main extends Application {
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
Image icon = new Image(String.valueOf(getClass().getResource("winmine.png")));
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("minesweeper.fxml"));
|
||||
Scene scene = new Scene(fxmlLoader.load());
|
||||
stage.setTitle("Minesweeper");
|
||||
stage.setScene(scene);
|
||||
stage.setResizable(false);
|
||||
stage.getIcons().add(icon);
|
||||
stage.show();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch();
|
||||
}
|
||||
|
||||
@Override
|
||||
@FXML
|
||||
public void stop() {
|
||||
Controller.timer.cancel();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user