add comments

This commit is contained in:
SowinskiBraeden committed 2025-11-28 00:11:21 -08:00
1 parent 6c2255ea1c
commit 13000cce58
18 files changed
+618 -120

No files matched your search

+40
View File
@@ -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)
{
+27 -1
View File
@@ -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);
+7 -1
View File
@@ -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;
+140 -39
View File
@@ -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;
+93 -1
View File
@@ -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);
+14 -2
View File
@@ -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;
}
}
+58 -1
View File
@@ -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;