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;
|
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
|
public class AscendingPlacement
|
||||||
extends PlacementRule
|
extends PlacementRule
|
||||||
{
|
{
|
||||||
private static final int FIRST = 0;
|
private static final int FIRST = 0;
|
||||||
private static final int NEXT = 1;
|
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
|
@Override
|
||||||
public boolean isValidPlacement(int[] positions, int index, int value)
|
public boolean isValidPlacement(int[] positions, int index, int value)
|
||||||
{
|
{
|
||||||
@@ -31,6 +46,14 @@ public class AscendingPlacement
|
|||||||
return true;
|
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
|
@Override
|
||||||
public boolean canPlaceNext(int[] positions, int nextValue)
|
public boolean canPlaceNext(int[] positions, int nextValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package ca.bcit.comp2522.project;
|
|||||||
import java.util.Random;
|
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
|
* @author Braeden Sowinski
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
@@ -16,6 +18,11 @@ public class Country
|
|||||||
private final String capitalCityName;
|
private final String capitalCityName;
|
||||||
private final String[] facts;
|
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)
|
private static void validateString(final String str)
|
||||||
{
|
{
|
||||||
if (str == null || str.isBlank())
|
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(
|
public Country(
|
||||||
final String name,
|
final String name,
|
||||||
final String capitalCityName,
|
final String capitalCityName,
|
||||||
@@ -37,16 +51,28 @@ public class Country
|
|||||||
this.facts = facts;
|
this.facts = facts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getName of the country
|
||||||
|
* @return name of the country
|
||||||
|
*/
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return this.name;
|
return this.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getCapital of country
|
||||||
|
* @return capital of country
|
||||||
|
*/
|
||||||
public String getCapital()
|
public String getCapital()
|
||||||
{
|
{
|
||||||
return this.capitalCityName;
|
return this.capitalCityName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getRandomFact of country
|
||||||
|
* @return random fact from the list of facts of the country
|
||||||
|
*/
|
||||||
public String getRandomFact()
|
public String getRandomFact()
|
||||||
{
|
{
|
||||||
final Random rand;
|
final Random rand;
|
||||||
|
|||||||
@@ -1,25 +1,47 @@
|
|||||||
package ca.bcit.comp2522.project;
|
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
|
public abstract class GameBoard
|
||||||
{
|
{
|
||||||
protected int width;
|
protected int width;
|
||||||
protected int height;
|
protected int height;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GameBoard constructor creates the board
|
||||||
|
* @param width of board
|
||||||
|
* @param height of board
|
||||||
|
*/
|
||||||
protected GameBoard(final int width, final int height)
|
protected GameBoard(final int width, final int height)
|
||||||
{
|
{
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getWidth of game board
|
||||||
|
* @return width of game board
|
||||||
|
*/
|
||||||
public final int getWidth()
|
public final int getWidth()
|
||||||
{
|
{
|
||||||
return this.width;
|
return this.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getHeight of game board
|
||||||
|
* @return height of game board
|
||||||
|
*/
|
||||||
public final int getHeight()
|
public final int getHeight()
|
||||||
{
|
{
|
||||||
return this.height;
|
return this.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reset game board
|
||||||
|
*/
|
||||||
public abstract void reset();
|
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;
|
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
|
public class InvalidMoveException extends Exception
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* InvalidMoveException constructor
|
||||||
|
* @param message of InvalidMoveException
|
||||||
|
*/
|
||||||
public InvalidMoveException(final String message)
|
public InvalidMoveException(final String message)
|
||||||
{
|
{
|
||||||
super(message);
|
super(message);
|
||||||
|
|||||||
@@ -3,13 +3,19 @@ package ca.bcit.comp2522.project;
|
|||||||
import java.util.Scanner;
|
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
|
* @author Braeden Sowinski
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
public class Main
|
public class Main
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* main program entry
|
||||||
|
* @param args from the command line
|
||||||
|
*/
|
||||||
public static void main(final String[] args)
|
public static void main(final String[] args)
|
||||||
{
|
{
|
||||||
final Scanner scanner;
|
final Scanner scanner;
|
||||||
|
|||||||
@@ -10,6 +10,16 @@ import java.util.Random;
|
|||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.function.Consumer;
|
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
|
public class Mines extends GameBoard
|
||||||
{
|
{
|
||||||
private static final int MINE = -1;
|
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 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;
|
private static final Random RANDOM_GENERATOR;
|
||||||
|
|
||||||
@@ -36,8 +46,8 @@ public class Mines extends GameBoard
|
|||||||
RANDOM_GENERATOR = new Random();
|
RANDOM_GENERATOR = new Random();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final int totalMines;
|
private final int totalMines;
|
||||||
private boolean randomMode;
|
private final boolean randomMode;
|
||||||
|
|
||||||
private int[] field;
|
private int[] field;
|
||||||
private boolean[] revealed;
|
private boolean[] revealed;
|
||||||
@@ -45,6 +55,14 @@ public class Mines extends GameBoard
|
|||||||
|
|
||||||
private int bestScoreSeconds;
|
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(
|
public Mines(
|
||||||
final int width,
|
final int width,
|
||||||
final int height,
|
final int height,
|
||||||
@@ -59,27 +77,21 @@ public class Mines extends GameBoard
|
|||||||
loadBestScore();
|
loadBestScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startNewGame()
|
/**
|
||||||
{
|
* isRandomMode checks if the mode is random or not
|
||||||
reset();
|
* @return random mode value
|
||||||
}
|
*/
|
||||||
|
|
||||||
public void startNewGame(final boolean randomMode)
|
|
||||||
{
|
|
||||||
this.randomMode = randomMode;
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRandomMode(final boolean randomMode)
|
|
||||||
{
|
|
||||||
this.randomMode = randomMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRandomMode()
|
public boolean isRandomMode()
|
||||||
{
|
{
|
||||||
return this.randomMode;
|
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
|
@Override
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
@@ -94,6 +106,12 @@ public class Mines extends GameBoard
|
|||||||
generateField();
|
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()
|
private void generateField()
|
||||||
{
|
{
|
||||||
int placedMines;
|
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++)
|
for (int i = 0; i < this.field.length; i++)
|
||||||
{
|
{
|
||||||
if (this.field[i] == MINE)
|
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(
|
private void forEachNeighbor(
|
||||||
final int index,
|
final int index,
|
||||||
final Consumer<Integer> action
|
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)
|
private void popFieldVoid(final int index)
|
||||||
{
|
{
|
||||||
forEachNeighbor(index, neighborIndex -> {
|
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)
|
public boolean reveal(final int index)
|
||||||
throws InvalidMoveException
|
throws InvalidMoveException
|
||||||
{
|
{
|
||||||
@@ -217,6 +273,12 @@ public class Mines extends GameBoard
|
|||||||
return this.field[index] == MINE;
|
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)
|
public int toggleFlag(final int index)
|
||||||
{
|
{
|
||||||
final int nextState;
|
final int nextState;
|
||||||
@@ -226,36 +288,71 @@ public class Mines extends GameBoard
|
|||||||
return nextState;
|
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)
|
public int getFieldValue(final int index)
|
||||||
{
|
{
|
||||||
return this.field[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)
|
public boolean isRevealed(final int index)
|
||||||
{
|
{
|
||||||
return this.revealed[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)
|
public boolean isMine(final int index)
|
||||||
{
|
{
|
||||||
return this.field[index] == MINE;
|
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)
|
public boolean isFlagged(final int index)
|
||||||
{
|
{
|
||||||
return this.flagged[index] == FLAG;
|
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)
|
public boolean isQuestionMarked(final int index)
|
||||||
{
|
{
|
||||||
return this.flagged[index] == FLAG_QUESTION;
|
return this.flagged[index] == FLAG_QUESTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getTotalMines returns the total mines in the field
|
||||||
|
* @return total mines in the field
|
||||||
|
*/
|
||||||
public int getTotalMines()
|
public int getTotalMines()
|
||||||
{
|
{
|
||||||
return this.totalMines;
|
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()
|
public boolean hasWon()
|
||||||
{
|
{
|
||||||
int revealedCount;
|
int revealedCount;
|
||||||
@@ -277,6 +374,14 @@ public class Mines extends GameBoard
|
|||||||
return revealedCount == (this.field.length - this.totalMines);
|
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()
|
public void randomizeRemaining()
|
||||||
{
|
{
|
||||||
if (!this.randomMode)
|
if (!this.randomMode)
|
||||||
@@ -316,26 +421,7 @@ public class Mines extends GameBoard
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < this.field.length; i++)
|
countNeighboringMines();
|
||||||
{
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < this.field.length; i++)
|
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)
|
public void saveScore(final int seconds)
|
||||||
{
|
{
|
||||||
try
|
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()
|
private void loadBestScore()
|
||||||
{
|
{
|
||||||
final File scoreFile;
|
final File scoreFile;
|
||||||
@@ -408,6 +504,11 @@ public class Mines extends GameBoard
|
|||||||
this.bestScoreSeconds = best;
|
this.bestScoreSeconds = best;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getBestScoreSeconds returns the best
|
||||||
|
* score in seconds
|
||||||
|
* @return best score in seconds
|
||||||
|
*/
|
||||||
public int getBestScoreSeconds()
|
public int getBestScoreSeconds()
|
||||||
{
|
{
|
||||||
return this.bestScoreSeconds;
|
return this.bestScoreSeconds;
|
||||||
|
|||||||
@@ -22,6 +22,15 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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
|
public class MinesUI
|
||||||
{
|
{
|
||||||
private static final int FONT_SIZE = 18;
|
private static final int FONT_SIZE = 18;
|
||||||
@@ -89,6 +98,11 @@ public class MinesUI
|
|||||||
private Timeline timer;
|
private Timeline timer;
|
||||||
private boolean timerRunning;
|
private boolean timerRunning;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MinesUI constructor creates an ArrayList
|
||||||
|
* to store buttons and track which mode
|
||||||
|
* the game is in, normal or random
|
||||||
|
*/
|
||||||
public MinesUI()
|
public MinesUI()
|
||||||
{
|
{
|
||||||
this.buttons = new ArrayList<>();
|
this.buttons = new ArrayList<>();
|
||||||
@@ -96,6 +110,11 @@ public class MinesUI
|
|||||||
this.timerRunning = false;
|
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)
|
public void showMainMenu(final Stage primaryStage)
|
||||||
{
|
{
|
||||||
final Label titleLabel;
|
final Label titleLabel;
|
||||||
@@ -142,6 +161,17 @@ public class MinesUI
|
|||||||
primaryStage.show();
|
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(
|
private void startGame(
|
||||||
final int width,
|
final int width,
|
||||||
final int height,
|
final int height,
|
||||||
@@ -205,6 +235,14 @@ public class MinesUI
|
|||||||
gameStage.show();
|
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)
|
private GridPane createGrid(final int width, final int height)
|
||||||
{
|
{
|
||||||
final GridPane grid;
|
final GridPane grid;
|
||||||
@@ -251,6 +289,13 @@ public class MinesUI
|
|||||||
return grid;
|
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)
|
private void handleReveal(final int index)
|
||||||
{
|
{
|
||||||
if (!timerRunning)
|
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)
|
private void handleFlag(final int index)
|
||||||
{
|
{
|
||||||
final int newState;
|
final int newState;
|
||||||
@@ -315,6 +365,12 @@ public class MinesUI
|
|||||||
updateButtonDisplay(index);
|
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)
|
private void updateButtonDisplay(final int index)
|
||||||
{
|
{
|
||||||
final Button button;
|
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()
|
private void refreshAllButtons()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < this.buttons.size(); i++)
|
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()
|
private void startTimer()
|
||||||
{
|
{
|
||||||
final KeyFrame tick;
|
final KeyFrame tick;
|
||||||
@@ -394,6 +460,9 @@ public class MinesUI
|
|||||||
this.timerRunning = true;
|
this.timerRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stopTime once game is over, either lost or won.
|
||||||
|
*/
|
||||||
private void stopTimer()
|
private void stopTimer()
|
||||||
{
|
{
|
||||||
if (this.timer != null)
|
if (this.timer != null)
|
||||||
@@ -403,6 +472,11 @@ public class MinesUI
|
|||||||
this.timerRunning = false;
|
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()
|
private void handleWin()
|
||||||
{
|
{
|
||||||
final Alert winAlert;
|
final Alert winAlert;
|
||||||
@@ -411,6 +485,7 @@ public class MinesUI
|
|||||||
this.game.saveScore(this.seconds);
|
this.game.saveScore(this.seconds);
|
||||||
this.bestLabel.setText("Best: " + this.game.getBestScoreSeconds() + "s");
|
this.bestLabel.setText("Best: " + this.game.getBestScoreSeconds() + "s");
|
||||||
|
|
||||||
|
showAllMines();
|
||||||
disableAllButtons();
|
disableAllButtons();
|
||||||
|
|
||||||
winAlert = new Alert(Alert.AlertType.INFORMATION);
|
winAlert = new Alert(Alert.AlertType.INFORMATION);
|
||||||
@@ -419,6 +494,10 @@ public class MinesUI
|
|||||||
winAlert.showAndWait();
|
winAlert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handleLoss displays a loss message, reveals all
|
||||||
|
* mines and stops timer. Forces user to restart game.
|
||||||
|
*/
|
||||||
private void handleLoss()
|
private void handleLoss()
|
||||||
{
|
{
|
||||||
final Alert lossAlert;
|
final Alert lossAlert;
|
||||||
@@ -429,10 +508,14 @@ public class MinesUI
|
|||||||
|
|
||||||
lossAlert = new Alert(Alert.AlertType.ERROR);
|
lossAlert = new Alert(Alert.AlertType.ERROR);
|
||||||
lossAlert.setHeaderText("You lost...");
|
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();
|
lossAlert.showAndWait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* showAllMines shows all mine locations for when
|
||||||
|
* a user wins or loses.
|
||||||
|
*/
|
||||||
private void showAllMines()
|
private void showAllMines()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < this.buttons.size(); i++)
|
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()
|
private void disableAllButtons()
|
||||||
{
|
{
|
||||||
final Iterator<Button> iterator;
|
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)
|
private void disableButton(final Button button)
|
||||||
{
|
{
|
||||||
button.setMouseTransparent(true);
|
button.setMouseTransparent(true);
|
||||||
|
|||||||
@@ -4,11 +4,19 @@ import javafx.application.Application;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main entry point for the Minesweeper game.
|
* MyGame manager for Minesweeper application
|
||||||
* Lesson 9: JavaFX GUI entry class.
|
* in JavaFX.
|
||||||
|
*
|
||||||
|
* @author Braeden Sowinski
|
||||||
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
public class MyGame extends Application
|
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
|
@Override
|
||||||
public void start(final Stage primaryStage)
|
public void start(final Stage primaryStage)
|
||||||
{
|
{
|
||||||
@@ -18,6 +26,10 @@ public class MyGame extends Application
|
|||||||
ui.showMainMenu(primaryStage);
|
ui.showMainMenu(primaryStage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main program entry for quick testing
|
||||||
|
* @param args from command line
|
||||||
|
*/
|
||||||
public static void main(final String[] args)
|
public static void main(final String[] args)
|
||||||
{
|
{
|
||||||
launch(args);
|
launch(args);
|
||||||
|
|||||||
@@ -12,6 +12,17 @@ import javafx.scene.control.Label;
|
|||||||
import javafx.scene.layout.VBox;
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.scene.control.Button;
|
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
|
public class NumberGame
|
||||||
extends Application
|
extends Application
|
||||||
{
|
{
|
||||||
@@ -35,14 +46,20 @@ public class NumberGame
|
|||||||
private int currentNumber;
|
private int currentNumber;
|
||||||
private int[] positions;
|
private int[] positions;
|
||||||
private RandomNumberGenerator generator;
|
private RandomNumberGenerator generator;
|
||||||
|
private AscendingPlacement placementValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start NumberGame GUI
|
||||||
|
* @param stage to show
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(final Stage stage)
|
public void start(final Stage stage)
|
||||||
{
|
{
|
||||||
this.generator = new RandomNumberGenerator(MIN_RAND_NUM, MAX_RAND_NUM);
|
this.placementValidator = new AscendingPlacement();
|
||||||
this.numbersPlaced = STARTING_NUMBERS_PLACED;
|
this.generator = new RandomNumberGenerator(MIN_RAND_NUM, MAX_RAND_NUM);
|
||||||
this.currentNumber = this.generator.generate();
|
this.numbersPlaced = STARTING_NUMBERS_PLACED;
|
||||||
this.positions = new int[GRID_WIDTH * GRID_HEIGHT];
|
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 = new Label("Next number: " + this.currentNumber + " - Select a slot.");
|
||||||
this.numberLabel.setFont(FONT);
|
this.numberLabel.setFont(FONT);
|
||||||
@@ -66,6 +83,11 @@ public class NumberGame
|
|||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* createGrid is used to generate the
|
||||||
|
* button grid for users to play in.
|
||||||
|
* @return GridPane with Buttons
|
||||||
|
*/
|
||||||
private GridPane createGrid()
|
private GridPane createGrid()
|
||||||
{
|
{
|
||||||
final GridPane grid;
|
final GridPane grid;
|
||||||
@@ -96,50 +118,22 @@ public class NumberGame
|
|||||||
return grid;
|
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");
|
this.numberLabel.setText("Next number: " + this.currentNumber + " - " + message);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
private void handlePress(final Button button, final int index)
|
||||||
{
|
{
|
||||||
button.setText("" + this.currentNumber);
|
button.setText("" + this.currentNumber);
|
||||||
@@ -149,24 +143,17 @@ public class NumberGame
|
|||||||
this.positions[index] = this.currentNumber;
|
this.positions[index] = this.currentNumber;
|
||||||
|
|
||||||
// Detect bad placement
|
// 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;
|
triggerFailed("Placed number incorrectly.");
|
||||||
final boolean smallerAbove;
|
return;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.numbersPlaced >= TOTAL_NUMBERS)
|
if (this.numbersPlaced >= TOTAL_NUMBERS)
|
||||||
@@ -178,17 +165,21 @@ public class NumberGame
|
|||||||
this.currentNumber = this.generator.generate();
|
this.currentNumber = this.generator.generate();
|
||||||
|
|
||||||
final boolean canPlaceNext;
|
final boolean canPlaceNext;
|
||||||
canPlaceNext = canBePlaced();
|
canPlaceNext = this.placementValidator.canPlaceNext(this.positions, this.currentNumber);
|
||||||
|
|
||||||
if (!canPlaceNext)
|
if (!canPlaceNext)
|
||||||
{
|
{
|
||||||
triggerFailed();
|
triggerFailed("Impossible to place next number.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.numberLabel.setText("Next number: " + this.currentNumber + " - Select a slot.");
|
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)
|
public static void main(final String[] args)
|
||||||
{
|
{
|
||||||
launch(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;
|
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
|
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(
|
public abstract boolean isValidPlacement(
|
||||||
final int[] positions,
|
final int[] positions,
|
||||||
final int index,
|
final int index,
|
||||||
final int value
|
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(
|
public abstract boolean canPlaceNext(
|
||||||
final int[] positions,
|
final int[] positions,
|
||||||
final int nextValue
|
final int nextValue
|
||||||
|
|||||||
@@ -2,24 +2,44 @@ package ca.bcit.comp2522.project;
|
|||||||
|
|
||||||
import java.util.Random;
|
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
|
public class RandomNumberGenerator
|
||||||
implements NumberGenerator
|
implements Generator
|
||||||
{
|
{
|
||||||
private final Random random;
|
private final Random random;
|
||||||
private final int min;
|
private final int min;
|
||||||
private final int max;
|
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.min = min;
|
||||||
this.max = max;
|
this.max = max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generate a random number between
|
||||||
|
* inclusive min and inclusive max value
|
||||||
|
* @return random number between min and max inclusive
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int generate()
|
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;
|
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
|
* @author Braeden Sowinski
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
@@ -31,6 +34,13 @@ public class Score
|
|||||||
private final int numIncorrectTwoAttempts;
|
private final int numIncorrectTwoAttempts;
|
||||||
private final int score;
|
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(
|
public static void appendScoreToFile(
|
||||||
final Score score,
|
final Score score,
|
||||||
final String scoreFilePath
|
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)
|
public static List<Score> readScoresFromFile(final String scoreFilePath)
|
||||||
{
|
{
|
||||||
final List<Score> scores;
|
final List<Score> scores;
|
||||||
@@ -110,6 +126,11 @@ public class Score
|
|||||||
return scores;
|
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)
|
public static Score getHighScore(final List<Score> scores)
|
||||||
{
|
{
|
||||||
return scores.stream()
|
return scores.stream()
|
||||||
@@ -117,6 +138,14 @@ public class Score
|
|||||||
.orElse(null);
|
.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(
|
public static boolean isHighScore(
|
||||||
final Score score,
|
final Score score,
|
||||||
final List<Score> scores
|
final List<Score> scores
|
||||||
@@ -129,6 +158,17 @@ public class Score
|
|||||||
highScore.getScore() < score.getScore());
|
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(
|
public Score(
|
||||||
final LocalDateTime dateTime,
|
final LocalDateTime dateTime,
|
||||||
final int numGamesPlayed,
|
final int numGamesPlayed,
|
||||||
@@ -151,11 +191,20 @@ public class Score
|
|||||||
this.numCorrectSecondAttempt * SECOND_GUESS_POINTS;
|
this.numCorrectSecondAttempt * SECOND_GUESS_POINTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getDateTimePlayed of Score
|
||||||
|
* @return dateTimePlayed as a String
|
||||||
|
*/
|
||||||
public String getDateTimePlayed()
|
public String getDateTimePlayed()
|
||||||
{
|
{
|
||||||
return this.dateTimePlayed;
|
return this.dateTimePlayed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toString neatly presents this Score
|
||||||
|
* in a String format
|
||||||
|
* @return formatted String of Score details
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
@@ -185,11 +234,19 @@ public class Score
|
|||||||
return log.toString();
|
return log.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getScore returns total points of this Score
|
||||||
|
* @return total points score
|
||||||
|
*/
|
||||||
public int getScore()
|
public int getScore()
|
||||||
{
|
{
|
||||||
return this.score;
|
return this.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculateAverage points per round
|
||||||
|
* @return average points scored per round
|
||||||
|
*/
|
||||||
public float calculateAverage()
|
public float calculateAverage()
|
||||||
{
|
{
|
||||||
return (float) this.score / (float) this.numGamesPlayed;
|
return (float) this.score / (float) this.numGamesPlayed;
|
||||||
|
|||||||
@@ -6,6 +6,16 @@ import java.util.List;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Scanner;
|
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
|
public class WordGame
|
||||||
{
|
{
|
||||||
private static final String SCORE_PATH = "./data/score.txt";
|
private static final String SCORE_PATH = "./data/score.txt";
|
||||||
@@ -26,12 +36,24 @@ public class WordGame
|
|||||||
|
|
||||||
private final World world;
|
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()
|
public WordGame()
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
this.world = new World();
|
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(
|
private static void checkAnswer(
|
||||||
final String correctAnswer,
|
final String correctAnswer,
|
||||||
final Scanner scanner,
|
final Scanner scanner,
|
||||||
@@ -66,6 +88,16 @@ public class WordGame
|
|||||||
System.out.printf("The correct answer was %s\n", correctAnswer);
|
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(
|
private void startTrivia(
|
||||||
final Scanner scanner,
|
final Scanner scanner,
|
||||||
final int[] scores
|
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()
|
public void runTrivia()
|
||||||
{
|
{
|
||||||
final Scanner scanner;
|
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)
|
public static void main(final String[] args)
|
||||||
{
|
{
|
||||||
final WordGame test;
|
final WordGame test;
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ import java.util.Random;
|
|||||||
import java.util.stream.Stream;
|
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
|
* @author Braeden Sowinski
|
||||||
* @version 1.0.0
|
* @version 1.0.0
|
||||||
*/
|
*/
|
||||||
@@ -27,6 +31,13 @@ public class World
|
|||||||
|
|
||||||
private final Map<String, Country> countries;
|
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(
|
private static Country readCountryData(
|
||||||
final String line,
|
final String line,
|
||||||
final BufferedReader reader
|
final BufferedReader reader
|
||||||
@@ -50,6 +61,12 @@ public class World
|
|||||||
return new Country(countryName, countryCapital, facts);
|
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()
|
public World()
|
||||||
throws IOException
|
throws IOException
|
||||||
{
|
{
|
||||||
@@ -90,6 +107,11 @@ public class World
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getRandomCountry returns a random
|
||||||
|
* Country from this countries Map.
|
||||||
|
* @return random Country
|
||||||
|
*/
|
||||||
public Country getRandomCountry()
|
public Country getRandomCountry()
|
||||||
{
|
{
|
||||||
final Random rand;
|
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 ca.bcit.comp2522.project.Mines;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|||||||
Reference in new issue
Block a user