Compare commits
	
		
			10 Commits
		
	
	
		
			1.3.0
			...
			d681f20b90
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d681f20b90 | |||
| ef569e1bcb | |||
| 74ba71d52c | |||
| 
						
						
							
						
						7708654bdb
	
				 | 
					
					
						|||
| 004fe776eb | |||
| 
						
						
							
						
						c2c5ac6e68
	
				 | 
					
					
						|||
| 
						
						
							
						
						0198ba6e56
	
				 | 
					
					
						|||
| 
						 | 
					f5ca09cc67 | ||
| 
						
						
							
						
						1187bedc5b
	
				 | 
					
					
						|||
| 
						
						
							
						
						21fa946011
	
				 | 
					
					
						
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							@@ -2,35 +2,33 @@
 | 
			
		||||
 | 
			
		||||
"named this way because i didn't realise there was another libremines!"
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## Building
 | 
			
		||||
 | 
			
		||||
### Requirements:
 | 
			
		||||
- Java 21 or newer (openjdk-21-jdk)
 | 
			
		||||
- Maven 3.8.8 (note: some versions cause gluon to freak out)
 | 
			
		||||
- Java 21
 | 
			
		||||
- Maven 3.8.8 or lower
 | 
			
		||||
- GraalVM 21
 | 
			
		||||
 | 
			
		||||
### Instructions:
 | 
			
		||||
 | 
			
		||||
Create the maven wrapper. gluonfx does not like versions of maven that are not 3.8.8:
 | 
			
		||||
Create the maven wrapper at version 3.8.8. GluonFX does not work with newer versions as of 2024-07-27.
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
mvn wrapper:wrapper -Dmaven=3.8.8
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This is helpful for version management, in case you have an incompatible version of maven installed.
 | 
			
		||||
Install dependencies:
 | 
			
		||||
Install dependencies, build and run:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
./mvnw install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Build and run:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
GRAALVM_HOME=/path/to/graalvm ./mvnw gluonfx:build
 | 
			
		||||
./mvnw dependency:resolve 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,31 +6,23 @@
 | 
			
		||||
 | 
			
		||||
    <groupId>com.shr4pnel.minesweeper</groupId>
 | 
			
		||||
    <artifactId>libremines</artifactId>
 | 
			
		||||
    <version>1.0-SNAPSHOT</version>
 | 
			
		||||
    <version>1.0</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.3</version>
 | 
			
		||||
            <version>21.0.4</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.openjfx</groupId>
 | 
			
		||||
            <artifactId>javafx-fxml</artifactId>
 | 
			
		||||
            <version>21.0.3</version>
 | 
			
		||||
            <version>21.0.4</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,55 +1,167 @@
 | 
			
		||||
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];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setNotYetImplemented(RadioMenuItem node) {
 | 
			
		||||
        node.setOnAction((ActionEvent e) -> System.out.println("https://http.cat/images/501.jpg"));
 | 
			
		||||
    /**
 | 
			
		||||
     * 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();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fills the GridPane with blank buttons
 | 
			
		||||
     */
 | 
			
		||||
    private void setupGrid() {
 | 
			
		||||
        for (int column = 0; column < 30; ++column) {
 | 
			
		||||
            for (int row = 0; row < 16; ++row) {
 | 
			
		||||
@@ -59,9 +171,13 @@ 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, true);
 | 
			
		||||
        Image blank = new Image(String.valueOf(getClass().getResource("img/blank.png")), 16, 16, true, false);
 | 
			
		||||
        ImageView blankImage = new ImageView(blank);
 | 
			
		||||
        Button blankButton = new Button();
 | 
			
		||||
        blankButton.setGraphic(blankImage);
 | 
			
		||||
@@ -72,18 +188,34 @@ 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;
 | 
			
		||||
@@ -104,9 +236,33 @@ 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) {
 | 
			
		||||
@@ -117,15 +273,27 @@ 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;
 | 
			
		||||
@@ -134,7 +302,7 @@ public class Controller {
 | 
			
		||||
                Button current = (Button) getNodeByRowColumnIndex(row, column);
 | 
			
		||||
                assert current != null;
 | 
			
		||||
                String currentURL = getButtonURL(current);
 | 
			
		||||
                if (currentURL.contains("blank.png") || currentURL.contains("flag.png")) {
 | 
			
		||||
                if (currentURL.contains("blank.png") || currentURL.contains("flagged.png")) {
 | 
			
		||||
                    unrevealedTiles++;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -142,11 +310,24 @@ 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);
 | 
			
		||||
@@ -174,6 +355,13 @@ 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()) {
 | 
			
		||||
@@ -192,6 +380,12 @@ 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) {
 | 
			
		||||
@@ -207,6 +401,13 @@ 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) {
 | 
			
		||||
@@ -216,6 +417,9 @@ public class Controller {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Resets important state variables on restart
 | 
			
		||||
     */
 | 
			
		||||
    @FXML
 | 
			
		||||
    private void reinitialize() {
 | 
			
		||||
        gameOver = false;
 | 
			
		||||
@@ -229,6 +433,11 @@ 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)));
 | 
			
		||||
@@ -239,6 +448,11 @@ 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()) {
 | 
			
		||||
@@ -247,6 +461,11 @@ 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();
 | 
			
		||||
@@ -255,6 +474,9 @@ public class Controller {
 | 
			
		||||
        showAllBombs(GridPane.getColumnIndex(tileClicked), GridPane.getRowIndex(tileClicked));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a win state, change the smiley.
 | 
			
		||||
     */
 | 
			
		||||
    private void win() {
 | 
			
		||||
        gameOver = true;
 | 
			
		||||
        timer.cancel();
 | 
			
		||||
@@ -262,6 +484,9 @@ 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) {
 | 
			
		||||
@@ -277,12 +502,17 @@ 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");
 | 
			
		||||
@@ -299,17 +529,30 @@ 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() {
 | 
			
		||||
@@ -325,6 +568,11 @@ 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);
 | 
			
		||||
@@ -334,11 +582,24 @@ 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;
 | 
			
		||||
@@ -355,27 +616,53 @@ 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,18 +1,31 @@
 | 
			
		||||
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,33 +1,76 @@
 | 
			
		||||
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;
 | 
			
		||||
@@ -35,10 +78,20 @@ 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;
 | 
			
		||||
 | 
			
		||||
@@ -69,15 +122,40 @@ 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,6 +1,7 @@
 | 
			
		||||
package com.shr4pnel.minesweeper;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import javafx.application.Application;
 | 
			
		||||
import javafx.fxml.FXML;
 | 
			
		||||
import javafx.fxml.FXMLLoader;
 | 
			
		||||
@@ -8,7 +9,17 @@ 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")));
 | 
			
		||||
@@ -21,10 +32,19 @@ 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,3 +1,8 @@
 | 
			
		||||
/**
 | 
			
		||||
 * 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;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								src/main/resources/com/shr4pnel/minesweeper/about.fxml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/main/resources/com/shr4pnel/minesweeper/about.fxml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
<?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>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/main/resources/com/shr4pnel/minesweeper/img/204.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/main/resources/com/shr4pnel/minesweeper/img/204.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After 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 style="-fx-background-color: white;">
 | 
			
		||||
        <MenuBar prefWidth="498.0" 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="Internmediate" toggleGroup="$difficulty" />
 | 
			
		||||
                        <RadioMenuItem mnemonicParsing="false" text="Intermediate" 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 mnemonicParsing="false" text="About Minesweeper" />
 | 
			
		||||
                        <MenuItem fx:id="about" mnemonicParsing="false" text="About Minesweeper" />
 | 
			
		||||
                    </items>
 | 
			
		||||
                </Menu>
 | 
			
		||||
            </menus>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
<?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>
 | 
			
		||||
		Reference in New Issue
	
	Block a user