add comments
This commit is contained in:
18 files changed
+618
-120
No files matched your search
@@ -0,0 +1,40 @@
|
||||
lesson 1:
|
||||
- static initializer used in Mines.java
|
||||
- static initializer used in MinesUI.java
|
||||
- method overloading in Mines.java > startNewGame()
|
||||
|
||||
lesson 2:
|
||||
- inheritance in Mines.java (extends GameBoard)
|
||||
- custom exception in InvalidMoveException.java
|
||||
- throwing exception in Mines.java > reveal()
|
||||
- catching exception in MinesUI.java > handleReveal()
|
||||
|
||||
lesson 3:
|
||||
- method overriding in Mines.java > reset()
|
||||
- substitution via GameBoard parent reference in constructor chain
|
||||
|
||||
lesson 4:
|
||||
- abstract class in GameBoard.java
|
||||
- abstract method reset() in GameBoard.java
|
||||
- implementation of abstract method in Mines.java > reset()
|
||||
|
||||
lesson 5:
|
||||
- collections in MinesUI.java > List<Button> buttons
|
||||
- iterators in MinesUI.java > disableAllButtons()
|
||||
|
||||
lesson 6:
|
||||
- lambda expressions in Mines.java > forEachNeighbor()
|
||||
- lambda expressions in MinesUI.java > button.setOnMouseClicked()
|
||||
|
||||
lesson 8:
|
||||
- Scanner used in Mines.java > loadBestScore()
|
||||
- BufferedReader used in Mines.java > loadBestScore()
|
||||
- BufferedWriter used in Mines.java > saveScore()
|
||||
- File used in Mines.java > loadBestScore()
|
||||
|
||||
lesson 9:
|
||||
- JavaFX GUI in MinesUI.java
|
||||
- JavaFX application entry class in MyGame.java > start()
|
||||
|
||||
lesson 10:
|
||||
- unit tests to be shown in accompanying JUnit test files
|
||||
@@ -1,11 +1,26 @@
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
/**
|
||||
* AscendingPlacement contains the logical and
|
||||
* validation of placing an integer in an array
|
||||
* of integers following an ascending order.
|
||||
*/
|
||||
public class AscendingPlacement
|
||||
extends PlacementRule
|
||||
{
|
||||
private static final int FIRST = 0;
|
||||
private static final int NEXT = 1;
|
||||
|
||||
/**
|
||||
* isValidPlacement ensures that a value placed at a given index
|
||||
* is in the correct position, no number greater than the value
|
||||
* comes before and no number smaller than the value comes after
|
||||
* within the positions array.
|
||||
* @param positions represents a 2d int array in 1d array
|
||||
* @param index to check if value can be placed here
|
||||
* @param value to be placed
|
||||
* @return if the value is in a valid placement
|
||||
*/
|
||||
@Override
|
||||
public boolean isValidPlacement(int[] positions, int index, int value)
|
||||
{
|
||||
@@ -31,6 +46,14 @@ public class AscendingPlacement
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* canPlaceNext detects if a given value
|
||||
* has a valid position to be placed.
|
||||
* @param positions represents a 2d int array in 1d array
|
||||
* @param nextValue to place
|
||||
* @return if the value can be placed in the positions array
|
||||
* without violating the ascending rule
|
||||
*/
|
||||
@Override
|
||||
public boolean canPlaceNext(int[] positions, int nextValue)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,9 @@ package ca.bcit.comp2522.project;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Country class
|
||||
* Country class stores a country's
|
||||
* name, capital city name, and NUMBER_OF_FACTS
|
||||
* about the country.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
@@ -16,6 +18,11 @@ public class Country
|
||||
private final String capitalCityName;
|
||||
private final String[] facts;
|
||||
|
||||
/**
|
||||
* validateString ensures an input String is
|
||||
* not null and not blank
|
||||
* @param str to validate
|
||||
*/
|
||||
private static void validateString(final String str)
|
||||
{
|
||||
if (str == null || str.isBlank())
|
||||
@@ -24,6 +31,13 @@ public class Country
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Country constructor takes in the
|
||||
* name, capital, and facts of a country
|
||||
* @param name of country
|
||||
* @param capitalCityName of country
|
||||
* @param facts about the country
|
||||
*/
|
||||
public Country(
|
||||
final String name,
|
||||
final String capitalCityName,
|
||||
@@ -37,16 +51,28 @@ public class Country
|
||||
this.facts = facts;
|
||||
}
|
||||
|
||||
/**
|
||||
* getName of the country
|
||||
* @return name of the country
|
||||
*/
|
||||
public String getName()
|
||||
{
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* getCapital of country
|
||||
* @return capital of country
|
||||
*/
|
||||
public String getCapital()
|
||||
{
|
||||
return this.capitalCityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* getRandomFact of country
|
||||
* @return random fact from the list of facts of the country
|
||||
*/
|
||||
public String getRandomFact()
|
||||
{
|
||||
final Random rand;
|
||||
|
||||
@@ -1,25 +1,47 @@
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
/**
|
||||
* GameBoard is a simple abstract class
|
||||
* to represent some two-dimensional board,
|
||||
* it stores the width and height of board
|
||||
* and must have a reset method.
|
||||
*/
|
||||
public abstract class GameBoard
|
||||
{
|
||||
protected int width;
|
||||
protected int height;
|
||||
|
||||
/**
|
||||
* GameBoard constructor creates the board
|
||||
* @param width of board
|
||||
* @param height of board
|
||||
*/
|
||||
protected GameBoard(final int width, final int height)
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* getWidth of game board
|
||||
* @return width of game board
|
||||
*/
|
||||
public final int getWidth()
|
||||
{
|
||||
return this.width;
|
||||
}
|
||||
|
||||
/**
|
||||
* getHeight of game board
|
||||
* @return height of game board
|
||||
*/
|
||||
public final int getHeight()
|
||||
{
|
||||
return this.height;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset game board
|
||||
*/
|
||||
public abstract void reset();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
/**
|
||||
* Generator interface has a generate method
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public interface Generator
|
||||
{
|
||||
/**
|
||||
* generate integer value
|
||||
* @return integer value
|
||||
*/
|
||||
int generate();
|
||||
}
|
||||
@@ -1,7 +1,18 @@
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
/**
|
||||
* InvalidMoveException is a custom error
|
||||
* to convey that an attempted move is invalid.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class InvalidMoveException extends Exception
|
||||
{
|
||||
/**
|
||||
* InvalidMoveException constructor
|
||||
* @param message of InvalidMoveException
|
||||
*/
|
||||
public InvalidMoveException(final String message)
|
||||
{
|
||||
super(message);
|
||||
|
||||
@@ -3,13 +3,19 @@ package ca.bcit.comp2522.project;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Main program entry to access a games menu
|
||||
* Main program entry to access a games menu,
|
||||
* users can select from 3 games. Word Game,
|
||||
* Number Game, or My Game (Minesweeper)
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class Main
|
||||
{
|
||||
/**
|
||||
* main program entry
|
||||
* @param args from the command line
|
||||
*/
|
||||
public static void main(final String[] args)
|
||||
{
|
||||
final Scanner scanner;
|
||||
|
||||
@@ -10,6 +10,16 @@ import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Mines class holds all relevant game logic
|
||||
* for minesweeper, generating field, tracking
|
||||
* game board (field), tracks cells revealed,
|
||||
* cells flagged and flagged status, randomizing
|
||||
* board if needed and provide getters for cells.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class Mines extends GameBoard
|
||||
{
|
||||
private static final int MINE = -1;
|
||||
@@ -27,7 +37,7 @@ public class Mines extends GameBoard
|
||||
|
||||
private static final int INITIAL_BEST_SCORE = Integer.MAX_VALUE;
|
||||
|
||||
private static final String SCORE_FILE_NAME = "scores.txt";
|
||||
private static final String SCORE_FILE_NAME = "minesweeper-score.txt";
|
||||
|
||||
private static final Random RANDOM_GENERATOR;
|
||||
|
||||
@@ -36,8 +46,8 @@ public class Mines extends GameBoard
|
||||
RANDOM_GENERATOR = new Random();
|
||||
}
|
||||
|
||||
private final int totalMines;
|
||||
private boolean randomMode;
|
||||
private final int totalMines;
|
||||
private final boolean randomMode;
|
||||
|
||||
private int[] field;
|
||||
private boolean[] revealed;
|
||||
@@ -45,6 +55,14 @@ public class Mines extends GameBoard
|
||||
|
||||
private int bestScoreSeconds;
|
||||
|
||||
/**
|
||||
* Mines constructor generates minefield board
|
||||
* with a given width, height and number of mines.
|
||||
* @param width of minefield
|
||||
* @param height of minefield
|
||||
* @param mines to place in minefield
|
||||
* @param randomMode to enable randomizing the field
|
||||
*/
|
||||
public Mines(
|
||||
final int width,
|
||||
final int height,
|
||||
@@ -59,27 +77,21 @@ public class Mines extends GameBoard
|
||||
loadBestScore();
|
||||
}
|
||||
|
||||
public void startNewGame()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
public void startNewGame(final boolean randomMode)
|
||||
{
|
||||
this.randomMode = randomMode;
|
||||
reset();
|
||||
}
|
||||
|
||||
public void setRandomMode(final boolean randomMode)
|
||||
{
|
||||
this.randomMode = randomMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* isRandomMode checks if the mode is random or not
|
||||
* @return random mode value
|
||||
*/
|
||||
public boolean isRandomMode()
|
||||
{
|
||||
return this.randomMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset game board, refreshes field,
|
||||
* revealed, and flagged arrays to
|
||||
* default values of total number of cells
|
||||
* then generates field values
|
||||
*/
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
@@ -94,6 +106,12 @@ public class Mines extends GameBoard
|
||||
generateField();
|
||||
}
|
||||
|
||||
/**
|
||||
* generateField places number of mines randomly
|
||||
* within the minefield, then for each cell count
|
||||
* number of neighboring mines and set values in
|
||||
* the field
|
||||
*/
|
||||
private void generateField()
|
||||
{
|
||||
int placedMines;
|
||||
@@ -115,6 +133,19 @@ public class Mines extends GameBoard
|
||||
}
|
||||
}
|
||||
|
||||
countNeighboringMines();
|
||||
}
|
||||
|
||||
/**
|
||||
* countNeighboringMines iterates over the field
|
||||
* and for each cell of the field, checks all 8
|
||||
* neighbors, top, top right, right, bottom right,
|
||||
* and so on to count the total number of mines
|
||||
* surround that cell, then updates the mine count
|
||||
* for that cell in the field.
|
||||
*/
|
||||
private void countNeighboringMines()
|
||||
{
|
||||
for (int i = 0; i < this.field.length; i++)
|
||||
{
|
||||
if (this.field[i] == MINE)
|
||||
@@ -137,6 +168,16 @@ public class Mines extends GameBoard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* forEachNeighbor is a helper method that takes in
|
||||
* an index of the field and a Consumer to perform
|
||||
* an action for each neighbor of the given index.
|
||||
*
|
||||
* Performs bounds checking to ensure there is no
|
||||
* out of bounds errors.
|
||||
* @param index to get each neighbor of
|
||||
* @param action to perform on each neighbor of the given cell index
|
||||
*/
|
||||
private void forEachNeighbor(
|
||||
final int index,
|
||||
final Consumer<Integer> action
|
||||
@@ -176,6 +217,14 @@ public class Mines extends GameBoard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* popFieldVoid reveals all neighboring cells of a
|
||||
* 0 value cell till it reaches a cell that has a
|
||||
* value greater than 0. i.e. a cell that has a
|
||||
* neighboring mine. Recursively calls itself to
|
||||
* accomplish this and "pop" a "void" within the field.
|
||||
* @param index to pop
|
||||
*/
|
||||
private void popFieldVoid(final int index)
|
||||
{
|
||||
forEachNeighbor(index, neighborIndex -> {
|
||||
@@ -199,6 +248,13 @@ public class Mines extends GameBoard
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* reveal a given cell and returns if it was
|
||||
* a mine or not or if invalid reveal
|
||||
* @param index of the cell to reveal
|
||||
* @return if revealed cell was a mine
|
||||
* @throws InvalidMoveException when attempting to reveal a flagged cell
|
||||
*/
|
||||
public boolean reveal(final int index)
|
||||
throws InvalidMoveException
|
||||
{
|
||||
@@ -217,6 +273,12 @@ public class Mines extends GameBoard
|
||||
return this.field[index] == MINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* toggleFlag of a given cell to either flag,
|
||||
* question, or no flag.
|
||||
* @param index of cell to flag
|
||||
* @return the updated state of the flag
|
||||
*/
|
||||
public int toggleFlag(final int index)
|
||||
{
|
||||
final int nextState;
|
||||
@@ -226,36 +288,71 @@ public class Mines extends GameBoard
|
||||
return nextState;
|
||||
}
|
||||
|
||||
/**
|
||||
* getFieldValue returns the value of a given cell
|
||||
* used to show values in the button of the UI
|
||||
* @param index of cell to get value
|
||||
* @return value of given cell
|
||||
*/
|
||||
public int getFieldValue(final int index)
|
||||
{
|
||||
return this.field[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* isRevealed returns if a given cell has been revealed
|
||||
* @param index of cell to check if revealed
|
||||
* @return if given cell is revealed
|
||||
*/
|
||||
public boolean isRevealed(final int index)
|
||||
{
|
||||
return this.revealed[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* isMine checks if a given cell is a mine
|
||||
* @param index of cell to check if mine
|
||||
* @return if given cell is mine
|
||||
*/
|
||||
public boolean isMine(final int index)
|
||||
{
|
||||
return this.field[index] == MINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* isFlagged checks if a given cell has been flagged
|
||||
* @param index of cell to check if flagged
|
||||
* @return if given cell is flagged
|
||||
*/
|
||||
public boolean isFlagged(final int index)
|
||||
{
|
||||
return this.flagged[index] == FLAG;
|
||||
}
|
||||
|
||||
/**
|
||||
* isQuestionMarked checks if a given cell has been questioned
|
||||
* @param index of cell to check if questioned
|
||||
* @return if given cell is questioned
|
||||
*/
|
||||
public boolean isQuestionMarked(final int index)
|
||||
{
|
||||
return this.flagged[index] == FLAG_QUESTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* getTotalMines returns the total mines in the field
|
||||
* @return total mines in the field
|
||||
*/
|
||||
public int getTotalMines()
|
||||
{
|
||||
return this.totalMines;
|
||||
}
|
||||
|
||||
/**
|
||||
* hasWon checks if all cells that are not mines have
|
||||
* been revealed, which is considered a win
|
||||
* @return if the game is over and has won
|
||||
*/
|
||||
public boolean hasWon()
|
||||
{
|
||||
int revealedCount;
|
||||
@@ -277,6 +374,14 @@ public class Mines extends GameBoard
|
||||
return revealedCount == (this.field.length - this.totalMines);
|
||||
}
|
||||
|
||||
/**
|
||||
* randomizeRemaining removes any mines from the field
|
||||
* that have not been flagged, then for each mine removed
|
||||
* it is randomly placed back into the field in an unrevealed
|
||||
* cell. Effectively "randomizing" undiscovered cells within
|
||||
* the field. Field values are then recalculated to reflect new
|
||||
* mine positions, and newly discovered voids are popped.
|
||||
*/
|
||||
public void randomizeRemaining()
|
||||
{
|
||||
if (!this.randomMode)
|
||||
@@ -316,26 +421,7 @@ public class Mines extends GameBoard
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.field.length; i++)
|
||||
{
|
||||
if (this.field[i] == MINE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final int[] count;
|
||||
|
||||
count = new int[] { NO_MINE };
|
||||
|
||||
forEachNeighbor(i, neighborIndex -> {
|
||||
if (this.field[neighborIndex] == MINE)
|
||||
{
|
||||
count[SELF_OFFSET]++;
|
||||
}
|
||||
});
|
||||
|
||||
this.field[i] = count[SELF_OFFSET];
|
||||
}
|
||||
countNeighboringMines();
|
||||
|
||||
for (int i = 0; i < this.field.length; i++)
|
||||
{
|
||||
@@ -347,6 +433,11 @@ public class Mines extends GameBoard
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* saveScore to file, then store seconds if
|
||||
* less than last score
|
||||
* @param seconds of game time
|
||||
*/
|
||||
public void saveScore(final int seconds)
|
||||
{
|
||||
try
|
||||
@@ -369,6 +460,11 @@ public class Mines extends GameBoard
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* loadBestScore from score file, gets
|
||||
* the best score (the least number of
|
||||
* seconds) from the score file.
|
||||
*/
|
||||
private void loadBestScore()
|
||||
{
|
||||
final File scoreFile;
|
||||
@@ -408,6 +504,11 @@ public class Mines extends GameBoard
|
||||
this.bestScoreSeconds = best;
|
||||
}
|
||||
|
||||
/**
|
||||
* getBestScoreSeconds returns the best
|
||||
* score in seconds
|
||||
* @return best score in seconds
|
||||
*/
|
||||
public int getBestScoreSeconds()
|
||||
{
|
||||
return this.bestScoreSeconds;
|
||||
|
||||
@@ -22,6 +22,15 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MinesUI handles all Minesweeper UI elements,
|
||||
* main menu, grid generation of the minefield.
|
||||
* Updating button displays, disabling buttons,
|
||||
* showing flags, warnings, etc.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class MinesUI
|
||||
{
|
||||
private static final int FONT_SIZE = 18;
|
||||
@@ -89,6 +98,11 @@ public class MinesUI
|
||||
private Timeline timer;
|
||||
private boolean timerRunning;
|
||||
|
||||
/**
|
||||
* MinesUI constructor creates an ArrayList
|
||||
* to store buttons and track which mode
|
||||
* the game is in, normal or random
|
||||
*/
|
||||
public MinesUI()
|
||||
{
|
||||
this.buttons = new ArrayList<>();
|
||||
@@ -96,6 +110,11 @@ public class MinesUI
|
||||
this.timerRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* showMainMenu displays main menu to choose
|
||||
* game mode, and field size.
|
||||
* @param primaryStage to display main menu to
|
||||
*/
|
||||
public void showMainMenu(final Stage primaryStage)
|
||||
{
|
||||
final Label titleLabel;
|
||||
@@ -142,6 +161,17 @@ public class MinesUI
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* startGame creates new Mine game, to
|
||||
* generate field, place mines, handle
|
||||
* randomization if enabled. Creates
|
||||
* grid of buttons for minefield, displays
|
||||
* new window of game instance of given size.
|
||||
* @param width of field to generate
|
||||
* @param height of field to generates
|
||||
* @param mines to generate in field
|
||||
* @param ownerStage to display minefield grid to
|
||||
*/
|
||||
private void startGame(
|
||||
final int width,
|
||||
final int height,
|
||||
@@ -205,6 +235,14 @@ public class MinesUI
|
||||
gameStage.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* createGrid generates the button grid
|
||||
* that represents the minefield of the
|
||||
* given dimensions
|
||||
* @param width of minefield grid
|
||||
* @param height of minefield grid
|
||||
* @return GridPane containing buttons of minefield
|
||||
*/
|
||||
private GridPane createGrid(final int width, final int height)
|
||||
{
|
||||
final GridPane grid;
|
||||
@@ -251,6 +289,13 @@ public class MinesUI
|
||||
return grid;
|
||||
}
|
||||
|
||||
/**
|
||||
* handleReveal reveals the given cell in the
|
||||
* minefield ensures the timer is running if first
|
||||
* reveal, call randomize on board if random mode
|
||||
* enabled, and refresh all button UI elements.
|
||||
* @param index to reveal
|
||||
*/
|
||||
private void handleReveal(final int index)
|
||||
{
|
||||
if (!timerRunning)
|
||||
@@ -292,6 +337,11 @@ public class MinesUI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handleFlag updates the given cell to be
|
||||
* flagged, questions, or back to no flag.
|
||||
* @param index to flag
|
||||
*/
|
||||
private void handleFlag(final int index)
|
||||
{
|
||||
final int newState;
|
||||
@@ -315,6 +365,12 @@ public class MinesUI
|
||||
updateButtonDisplay(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* updateButtonDisplay updates a given button
|
||||
* by index depending on how the cell is configured.
|
||||
* Flagged, questioned, or revealed.
|
||||
* @param index of cell to update button
|
||||
*/
|
||||
private void updateButtonDisplay(final int index)
|
||||
{
|
||||
final Button button;
|
||||
@@ -363,6 +419,12 @@ public class MinesUI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* refreshAllButtons iterates over all buttons
|
||||
* and calls updateButtonDisplay for that button,
|
||||
* as well as disables button if revealed, preventing
|
||||
* further clicking on the button.
|
||||
*/
|
||||
private void refreshAllButtons()
|
||||
{
|
||||
for (int i = 0; i < this.buttons.size(); i++)
|
||||
@@ -375,6 +437,10 @@ public class MinesUI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* startTimer when initial cell is revealed to
|
||||
* track the game time.
|
||||
*/
|
||||
private void startTimer()
|
||||
{
|
||||
final KeyFrame tick;
|
||||
@@ -394,6 +460,9 @@ public class MinesUI
|
||||
this.timerRunning = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* stopTime once game is over, either lost or won.
|
||||
*/
|
||||
private void stopTimer()
|
||||
{
|
||||
if (this.timer != null)
|
||||
@@ -403,6 +472,11 @@ public class MinesUI
|
||||
this.timerRunning = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* handleWin displays a win message window, with the time
|
||||
* taken to win the game, show all mines, and disable all
|
||||
* buttons.
|
||||
*/
|
||||
private void handleWin()
|
||||
{
|
||||
final Alert winAlert;
|
||||
@@ -411,6 +485,7 @@ public class MinesUI
|
||||
this.game.saveScore(this.seconds);
|
||||
this.bestLabel.setText("Best: " + this.game.getBestScoreSeconds() + "s");
|
||||
|
||||
showAllMines();
|
||||
disableAllButtons();
|
||||
|
||||
winAlert = new Alert(Alert.AlertType.INFORMATION);
|
||||
@@ -419,6 +494,10 @@ public class MinesUI
|
||||
winAlert.showAndWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* handleLoss displays a loss message, reveals all
|
||||
* mines and stops timer. Forces user to restart game.
|
||||
*/
|
||||
private void handleLoss()
|
||||
{
|
||||
final Alert lossAlert;
|
||||
@@ -429,10 +508,14 @@ public class MinesUI
|
||||
|
||||
lossAlert = new Alert(Alert.AlertType.ERROR);
|
||||
lossAlert.setHeaderText("You lost...");
|
||||
lossAlert.setContentText("You dug up a mine. Better luck next time.");
|
||||
lossAlert.setContentText("You dug up a mine and lost your legs.");
|
||||
lossAlert.showAndWait();
|
||||
}
|
||||
|
||||
/**
|
||||
* showAllMines shows all mine locations for when
|
||||
* a user wins or loses.
|
||||
*/
|
||||
private void showAllMines()
|
||||
{
|
||||
for (int i = 0; i < this.buttons.size(); i++)
|
||||
@@ -448,6 +531,10 @@ public class MinesUI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disableAllButtons iterates over all buttons
|
||||
* and calls the disableButton method on it.
|
||||
*/
|
||||
private void disableAllButtons()
|
||||
{
|
||||
final Iterator<Button> iterator;
|
||||
@@ -463,6 +550,11 @@ public class MinesUI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disableButton prevents user from
|
||||
* interacting with it by clicking.
|
||||
* @param button to disable
|
||||
*/
|
||||
private void disableButton(final Button button)
|
||||
{
|
||||
button.setMouseTransparent(true);
|
||||
|
||||
@@ -4,11 +4,19 @@ import javafx.application.Application;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
/**
|
||||
* Main entry point for the Minesweeper game.
|
||||
* Lesson 9: JavaFX GUI entry class.
|
||||
* MyGame manager for Minesweeper application
|
||||
* in JavaFX.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class MyGame extends Application
|
||||
{
|
||||
/**
|
||||
* start JavaFX application by creating
|
||||
* the MinesUI handler to show main menu.
|
||||
* @param primaryStage to show minesweeper menu UI
|
||||
*/
|
||||
@Override
|
||||
public void start(final Stage primaryStage)
|
||||
{
|
||||
@@ -18,6 +26,10 @@ public class MyGame extends Application
|
||||
ui.showMainMenu(primaryStage);
|
||||
}
|
||||
|
||||
/**
|
||||
* main program entry for quick testing
|
||||
* @param args from command line
|
||||
*/
|
||||
public static void main(final String[] args)
|
||||
{
|
||||
launch(args);
|
||||
|
||||
@@ -12,6 +12,17 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.control.Button;
|
||||
|
||||
/**
|
||||
* NumberGame is a GUI game with JavaFX
|
||||
* where a user has to place randomly generated
|
||||
* numbers into a 5x4 grid of buttons. Numbers
|
||||
* must be played in order to win.
|
||||
*
|
||||
* Extends JavaFX Application
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class NumberGame
|
||||
extends Application
|
||||
{
|
||||
@@ -35,14 +46,20 @@ public class NumberGame
|
||||
private int currentNumber;
|
||||
private int[] positions;
|
||||
private RandomNumberGenerator generator;
|
||||
private AscendingPlacement placementValidator;
|
||||
|
||||
/**
|
||||
* start NumberGame GUI
|
||||
* @param stage to show
|
||||
*/
|
||||
@Override
|
||||
public void start(final Stage stage)
|
||||
{
|
||||
this.generator = new RandomNumberGenerator(MIN_RAND_NUM, MAX_RAND_NUM);
|
||||
this.numbersPlaced = STARTING_NUMBERS_PLACED;
|
||||
this.currentNumber = this.generator.generate();
|
||||
this.positions = new int[GRID_WIDTH * GRID_HEIGHT];
|
||||
this.placementValidator = new AscendingPlacement();
|
||||
this.generator = new RandomNumberGenerator(MIN_RAND_NUM, MAX_RAND_NUM);
|
||||
this.numbersPlaced = STARTING_NUMBERS_PLACED;
|
||||
this.currentNumber = this.generator.generate();
|
||||
this.positions = new int[GRID_WIDTH * GRID_HEIGHT];
|
||||
|
||||
this.numberLabel = new Label("Next number: " + this.currentNumber + " - Select a slot.");
|
||||
this.numberLabel.setFont(FONT);
|
||||
@@ -66,6 +83,11 @@ public class NumberGame
|
||||
stage.show();
|
||||
}
|
||||
|
||||
/*
|
||||
* createGrid is used to generate the
|
||||
* button grid for users to play in.
|
||||
* @return GridPane with Buttons
|
||||
*/
|
||||
private GridPane createGrid()
|
||||
{
|
||||
final GridPane grid;
|
||||
@@ -96,50 +118,22 @@ public class NumberGame
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void triggerFailed()
|
||||
/*
|
||||
* triggerFailed handles stopping the game
|
||||
* when lost, i.e. impossible to place next
|
||||
* number
|
||||
*/
|
||||
private void triggerFailed(final String message)
|
||||
{
|
||||
this.numberLabel.setText("Next number: " + this.currentNumber + " - Impossible to place next number");
|
||||
}
|
||||
|
||||
private boolean canBePlaced()
|
||||
{
|
||||
for (int i = 0; i < positions.length; i++) {
|
||||
|
||||
if (this.positions[i] != STARTING_NUMBERS_PLACED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int left;
|
||||
left = Integer.MIN_VALUE;
|
||||
|
||||
for (int j = i - INDEX_OFFSET; j >= STARTING_NUMBERS_PLACED; j--)
|
||||
{
|
||||
if (this.positions[j] != STARTING_NUMBERS_PLACED)
|
||||
{
|
||||
left = this.positions[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int right;
|
||||
right = Integer.MAX_VALUE;
|
||||
for (int j = i + INDEX_OFFSET; j < this.positions.length; j++)
|
||||
{
|
||||
if (this.positions[j] != STARTING_NUMBERS_PLACED) {
|
||||
right = this.positions[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (left < currentNumber && currentNumber < right) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
this.numberLabel.setText("Next number: " + this.currentNumber + " - " + message);
|
||||
}
|
||||
|
||||
/*
|
||||
* handlePress of button to place number
|
||||
* in that cell
|
||||
* @param button pressed
|
||||
* @param index of button to place value
|
||||
*/
|
||||
private void handlePress(final Button button, final int index)
|
||||
{
|
||||
button.setText("" + this.currentNumber);
|
||||
@@ -149,24 +143,17 @@ public class NumberGame
|
||||
this.positions[index] = this.currentNumber;
|
||||
|
||||
// Detect bad placement
|
||||
for (int i = 0; i < GRID_WIDTH * GRID_HEIGHT; i++)
|
||||
final boolean isValidPlacement;
|
||||
isValidPlacement = this.placementValidator.isValidPlacement(
|
||||
this.positions,
|
||||
index,
|
||||
this.currentNumber
|
||||
);
|
||||
|
||||
if (!isValidPlacement)
|
||||
{
|
||||
final boolean largerBelow;
|
||||
final boolean smallerAbove;
|
||||
|
||||
largerBelow = i < index &&
|
||||
this.positions[i] != STARTING_NUMBERS_PLACED &&
|
||||
this.positions[i] > this.positions[index];
|
||||
|
||||
smallerAbove = i > index &&
|
||||
this.positions[i] != STARTING_NUMBERS_PLACED &&
|
||||
this.positions[i] < this.positions[index];
|
||||
|
||||
if (largerBelow || smallerAbove)
|
||||
{
|
||||
triggerFailed();
|
||||
return;
|
||||
}
|
||||
triggerFailed("Placed number incorrectly.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.numbersPlaced >= TOTAL_NUMBERS)
|
||||
@@ -178,17 +165,21 @@ public class NumberGame
|
||||
this.currentNumber = this.generator.generate();
|
||||
|
||||
final boolean canPlaceNext;
|
||||
canPlaceNext = canBePlaced();
|
||||
canPlaceNext = this.placementValidator.canPlaceNext(this.positions, this.currentNumber);
|
||||
|
||||
if (!canPlaceNext)
|
||||
{
|
||||
triggerFailed();
|
||||
triggerFailed("Impossible to place next number.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.numberLabel.setText("Next number: " + this.currentNumber + " - Select a slot.");
|
||||
}
|
||||
|
||||
/**
|
||||
* main program entry for quick testing
|
||||
* @param args from command line
|
||||
*/
|
||||
public static void main(final String[] args)
|
||||
{
|
||||
launch(args);
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
public interface NumberGenerator
|
||||
{
|
||||
int generate();
|
||||
}
|
||||
@@ -1,13 +1,34 @@
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
/**
|
||||
* PlacementRule defines abstract methods
|
||||
* that must be implemented to validate positions
|
||||
* in a number game.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public abstract class PlacementRule
|
||||
{
|
||||
/**
|
||||
* isValidPlacement abstract method
|
||||
* @param positions represents a 2d int array in 1d array
|
||||
* @param index to check if value can be placed here
|
||||
* @param value to be placed
|
||||
* @return if value can be placed at index
|
||||
*/
|
||||
public abstract boolean isValidPlacement(
|
||||
final int[] positions,
|
||||
final int index,
|
||||
final int value
|
||||
);
|
||||
|
||||
/**
|
||||
* canPlaceNext abstract method
|
||||
* @param positions represents a 2d int array in 1d array
|
||||
* @param nextValue to place
|
||||
* @return if next value to place can be placed at all
|
||||
*/
|
||||
public abstract boolean canPlaceNext(
|
||||
final int[] positions,
|
||||
final int nextValue
|
||||
|
||||
@@ -2,24 +2,44 @@ package ca.bcit.comp2522.project;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* RandomNumberGenerator is a helper class
|
||||
* that generates random numbers within a
|
||||
* defined range
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class RandomNumberGenerator
|
||||
implements NumberGenerator
|
||||
implements Generator
|
||||
{
|
||||
private final Random random;
|
||||
private final int min;
|
||||
private final int max;
|
||||
|
||||
public RandomNumberGenerator(int min, int max)
|
||||
/**
|
||||
* RandomNumberGenerator constructor
|
||||
* @param min number that can be randomly generated inclusive
|
||||
* @param max number that can be randomly generated inclusive
|
||||
*/
|
||||
public RandomNumberGenerator(
|
||||
final int min,
|
||||
final int max)
|
||||
{
|
||||
random = new Random();
|
||||
this.random = new Random();
|
||||
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate a random number between
|
||||
* inclusive min and inclusive max value
|
||||
* @return random number between min and max inclusive
|
||||
*/
|
||||
@Override
|
||||
public int generate()
|
||||
{
|
||||
return random.nextInt(max - min) + min;
|
||||
return this.random.nextInt(this.max - this.min) + this.min;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,10 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Score manager for the word game.
|
||||
* Score manager for WordGame, writes and reads
|
||||
* scores from file, get and validate high-scores,
|
||||
* calculate score averages and provides useful
|
||||
* toString methods to summarize scores.
|
||||
*
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
@@ -31,6 +34,13 @@ public class Score
|
||||
private final int numIncorrectTwoAttempts;
|
||||
private final int score;
|
||||
|
||||
/**
|
||||
* appendScoreToFile takes in a Score object
|
||||
* and filepath, appends Score values to file
|
||||
* accordingly.
|
||||
* @param score to append to filepath
|
||||
* @param scoreFilePath filepath to append Score to
|
||||
*/
|
||||
public static void appendScoreToFile(
|
||||
final Score score,
|
||||
final String scoreFilePath
|
||||
@@ -52,6 +62,12 @@ public class Score
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* readScoresFromFile returns a history of all Scores
|
||||
* read from the given filepath.
|
||||
* @param scoreFilePath to read scores from
|
||||
* @return a list of all Scores read from given filepath
|
||||
*/
|
||||
public static List<Score> readScoresFromFile(final String scoreFilePath)
|
||||
{
|
||||
final List<Score> scores;
|
||||
@@ -110,6 +126,11 @@ public class Score
|
||||
return scores;
|
||||
}
|
||||
|
||||
/**
|
||||
* getHighScore from a given List of Scores
|
||||
* @param scores list to find high-score from
|
||||
* @return high Score from list of scores
|
||||
*/
|
||||
public static Score getHighScore(final List<Score> scores)
|
||||
{
|
||||
return scores.stream()
|
||||
@@ -117,6 +138,14 @@ public class Score
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* isHighScore takes a List of Scores and
|
||||
* new Score to check if the new Score is
|
||||
* a high-score in the given scores list.
|
||||
* @param score to check if is high score
|
||||
* @param scores list to compare Score to
|
||||
* @return if score is a new high-score in list
|
||||
*/
|
||||
public static boolean isHighScore(
|
||||
final Score score,
|
||||
final List<Score> scores
|
||||
@@ -129,6 +158,17 @@ public class Score
|
||||
highScore.getScore() < score.getScore());
|
||||
}
|
||||
|
||||
/**
|
||||
* Score constructor saves score dateTime,
|
||||
* number of games played for this score,
|
||||
* and relevant scores based on number of
|
||||
* guesses.
|
||||
* @param dateTime the score was recorded
|
||||
* @param numGamesPlayed is the number of WordGames played
|
||||
* @param numCorrectFirstAttempt is the number of times a guess was correct first try
|
||||
* @param numCorrectSecondAttempt is the number of times a guess was correct on second try
|
||||
* @param numIncorrectTwoAttempts is the number of times both guesses were incorrect
|
||||
*/
|
||||
public Score(
|
||||
final LocalDateTime dateTime,
|
||||
final int numGamesPlayed,
|
||||
@@ -151,11 +191,20 @@ public class Score
|
||||
this.numCorrectSecondAttempt * SECOND_GUESS_POINTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* getDateTimePlayed of Score
|
||||
* @return dateTimePlayed as a String
|
||||
*/
|
||||
public String getDateTimePlayed()
|
||||
{
|
||||
return this.dateTimePlayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* toString neatly presents this Score
|
||||
* in a String format
|
||||
* @return formatted String of Score details
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
@@ -185,11 +234,19 @@ public class Score
|
||||
return log.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* getScore returns total points of this Score
|
||||
* @return total points score
|
||||
*/
|
||||
public int getScore()
|
||||
{
|
||||
return this.score;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculateAverage points per round
|
||||
* @return average points scored per round
|
||||
*/
|
||||
public float calculateAverage()
|
||||
{
|
||||
return (float) this.score / (float) this.numGamesPlayed;
|
||||
|
||||
@@ -6,6 +6,16 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* WordGame asks NUMBER_OF_QUESTIONS where you are
|
||||
* either asked about a country by capital,
|
||||
* asked about a capital by country,
|
||||
* or asked about a country by a random fact.
|
||||
*
|
||||
* Score is kept and saved
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class WordGame
|
||||
{
|
||||
private static final String SCORE_PATH = "./data/score.txt";
|
||||
@@ -26,12 +36,24 @@ public class WordGame
|
||||
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* WordGame constructor creates a World class to
|
||||
* access Countries and their details.
|
||||
* @throws IOException if World failed to read countries
|
||||
*/
|
||||
public WordGame()
|
||||
throws IOException
|
||||
{
|
||||
this.world = new World();
|
||||
}
|
||||
|
||||
/*
|
||||
* checkAnswer reads user input and compares it to
|
||||
* a given correct answer and updates scores accordingly.
|
||||
* @param correctAnswer to check user input to
|
||||
* @param scanner to read user input from
|
||||
* @param scores to update accordingly
|
||||
*/
|
||||
private static void checkAnswer(
|
||||
final String correctAnswer,
|
||||
final Scanner scanner,
|
||||
@@ -66,6 +88,16 @@ public class WordGame
|
||||
System.out.printf("The correct answer was %s\n", correctAnswer);
|
||||
}
|
||||
|
||||
/*
|
||||
* startTrivia starts the game and asks NUMBER_OF_QUESTIONS,
|
||||
* randomly chooses a Country and randomly chooses which
|
||||
* kind of question to ask:
|
||||
* country by capital,
|
||||
* capital by country, or
|
||||
* country by fact.
|
||||
* @param scanner to pass to checkAnswer method
|
||||
* @param scores to pass to checkAnswer method
|
||||
*/
|
||||
private void startTrivia(
|
||||
final Scanner scanner,
|
||||
final int[] scores
|
||||
@@ -109,6 +141,14 @@ public class WordGame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* runTrivia initializes score, scanner, and keeps
|
||||
* track if the user wants to keep playing after
|
||||
* a round is completed.
|
||||
*
|
||||
* Once a user is done playing, score from all rounds is
|
||||
* saved and high-scores are calculated.
|
||||
*/
|
||||
public void runTrivia()
|
||||
{
|
||||
final Scanner scanner;
|
||||
@@ -201,6 +241,10 @@ public class WordGame
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* main method for quickly testing the WordGame
|
||||
* @param args from command line
|
||||
*/
|
||||
public static void main(final String[] args)
|
||||
{
|
||||
final WordGame test;
|
||||
|
||||
@@ -15,6 +15,10 @@ import java.util.Random;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* World class reads countries and their facts
|
||||
* from a file and stores the Country in a Map.
|
||||
* Also provides useful functions to get a random
|
||||
* Country from the Map.
|
||||
* @author Braeden Sowinski
|
||||
* @version 1.0.0
|
||||
*/
|
||||
@@ -27,6 +31,13 @@ public class World
|
||||
|
||||
private final Map<String, Country> countries;
|
||||
|
||||
/*
|
||||
* readCuntryData from a given line
|
||||
* @param line to parse
|
||||
* @param reader to read line
|
||||
* @return Country with name and facts
|
||||
* @throws IOException
|
||||
*/
|
||||
private static Country readCountryData(
|
||||
final String line,
|
||||
final BufferedReader reader
|
||||
@@ -50,6 +61,12 @@ public class World
|
||||
return new Country(countryName, countryCapital, facts);
|
||||
}
|
||||
|
||||
/**
|
||||
* World constructor creates a hashmap
|
||||
* where the key is a Country name, and
|
||||
* the value is the Country object.
|
||||
* @throws IOException
|
||||
*/
|
||||
public World()
|
||||
throws IOException
|
||||
{
|
||||
@@ -90,6 +107,11 @@ public class World
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getRandomCountry returns a random
|
||||
* Country from this countries Map.
|
||||
* @return random Country
|
||||
*/
|
||||
public Country getRandomCountry()
|
||||
{
|
||||
final Random rand;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package ca.bcit.comp2522.project.tests;
|
||||
package ca.bcit.comp2522.project;
|
||||
|
||||
import ca.bcit.comp2522.project.Mines;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
Reference in new issue
Block a user