From 68b3127134da50de0a2f146fc0ac22df37953332 Mon Sep 17 00:00:00 2001 From: SowinskiBraeden Date: Sun, 23 Nov 2025 13:46:41 -0800 Subject: [PATCH] start mines + fix WordGame + nearly finish NumberGame --- src/code/ca/bcit/comp2522/project/Mines.java | 305 +++++++++++++++++- .../ca/bcit/comp2522/project/NumberGame.java | 162 +++++++--- .../ca/bcit/comp2522/project/WordGame.java | 219 +++++++++++++ src/code/ca/bcit/comp2522/project/World.java | 228 +------------ 4 files changed, 661 insertions(+), 253 deletions(-) create mode 100644 src/code/ca/bcit/comp2522/project/WordGame.java diff --git a/src/code/ca/bcit/comp2522/project/Mines.java b/src/code/ca/bcit/comp2522/project/Mines.java index a1e01d9..469ba51 100644 --- a/src/code/ca/bcit/comp2522/project/Mines.java +++ b/src/code/ca/bcit/comp2522/project/Mines.java @@ -1,15 +1,314 @@ package ca.bcit.comp2522.project; import javafx.application.Application; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.input.MouseButton; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.Font; +import javafx.scene.text.FontWeight; import javafx.stage.Stage; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + public class Mines extends Application { + private static final int FONT_SIZE = 18; + private static final Font FONT = Font.font("Arial", FontWeight.BOLD, FONT_SIZE); + + private static final int WINDOW_WIDTH = 1920; + private static final int WINDOW_HEIGHT = 1080; + private static final int BUTTON_WIDTH = 60; + private static final int BUTTON_HEIGHT = 60; + private static final int EASY_WIDTH = 8; + private static final int EASY_HEIGHT = 8; + private static final int HARD_WIDTH = 36; + private static final int HARD_HEIGHT = 16; + private static final int PADDING = 20; + private static final int GAME_PADDING = 5; + private static final int VERTICAL_MARGIN = 15; + + private static final int EASY_MINES = 10; + private static final int HARD_MINES = 99; + private static final int MINE = -1; + private static final int NO_MINE = 0; + + private static final int MIN_OFFSET = -1; + private static final int MAX_OFFSET = 1; + private static final int SELF_OFFSET = 0; + private static final int FIRST_ROW = 0; + private static final int FIRST_COL = 0; + + private static final int NO_FLAG = 0; + private static final int FLAG = 1; + private static final int FLAG_QUESTION = 2; + + private static final int DEFAULT_BUTTON = -2; + private static final Map BUTTON_THEMES = new HashMap<>(); + + static { + BUTTON_THEMES.put(-2, "-fx-background-color: #b3b3b3; -fx-text-fill: black;"); + BUTTON_THEMES.put(-1, "-fx-background-color: #d9d9d9; -fx-text-fill: black;"); + BUTTON_THEMES.put(0, "-fx-background-color: #d9d9d9; -fx-text-fill: black;"); + BUTTON_THEMES.put(1, "-fx-background-color: #c8ffbf; -fx-text-fill: black;"); + BUTTON_THEMES.put(2, "-fx-background-color: #edfc9f; -fx-text-fill: black;"); + BUTTON_THEMES.put(3, "-fx-background-color: #fad08c; -fx-text-fill: black;"); + BUTTON_THEMES.put(4, "-fx-background-color: #f59338; -fx-text-fill: black;"); + BUTTON_THEMES.put(5, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + BUTTON_THEMES.put(6, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + BUTTON_THEMES.put(7, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + BUTTON_THEMES.put(8, "-fx-background-color: #ff644d; -fx-text-fill: black;"); + } + + private int[] field; + private boolean[] revealed; + private int[] flagged; + private Button[] buttons; + private int width; + private int height; + private int flags; + @Override - public void start(final Stage s) + public void start(final Stage stage) { - s.setTitle("MineSweeper Random"); - s.show(); + final Label title; + title = new Label("Select Game Size"); + title.setStyle("-fx-font-size: 20px; -fx-font-weight: bold;"); + + final Button smallBtn; + final Button largeBtn; + + smallBtn = new Button("8 × 8 (Beginner)"); + largeBtn = new Button("36 × 16 (Expert)"); + + smallBtn.setPrefWidth(BUTTON_WIDTH); + largeBtn.setPrefWidth(BUTTON_WIDTH); + + smallBtn.setOnAction(e -> startGame(EASY_WIDTH, EASY_HEIGHT, EASY_MINES)); + largeBtn.setOnAction(e -> startGame(HARD_WIDTH, HARD_HEIGHT, HARD_MINES)); + + final VBox root; + root = new VBox(VERTICAL_MARGIN); + + root.setPadding(new Insets(PADDING)); + root.setAlignment(Pos.CENTER); + root.getChildren().addAll(title, smallBtn, largeBtn); + + final Scene scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT); + stage.setTitle("Random Mines - A Minesweeper Game"); + stage.setResizable(false); + stage.setScene(scene); + stage.show(); + } + + private void forEachNeighbor(final int index, final java.util.function.IntConsumer action) + { + final int row = index / width; + final int col = index % width; + + for (int dr = MIN_OFFSET; dr <= MAX_OFFSET; dr++) + { + for (int dc = MIN_OFFSET; dc <= MAX_OFFSET; dc++) + { + if (dr == SELF_OFFSET && dc == SELF_OFFSET) + { + continue; + } + + final int nr = row + dr; + final int nc = col + dc; + + if (nr < FIRST_ROW || nr >= height || + nc < FIRST_COL || nc >= width) + { + continue; + } + + final int neighborIndex = nr * width + nc; + action.accept(neighborIndex); + } + } + } + + private void generateField(final int mines) + { + this.revealed = new boolean[width * height]; + this.field = new int[width * height]; + this.flagged = new int[width * height]; + + final Random rand; + int placed; + + rand = new Random(); + placed = NO_MINE; + + while (placed < mines) + { + final int index; + index = rand.nextInt(width * height); + + if (this.field[index] != MINE) + { + this.field[index] = MINE; + placed++; + } + } + + for (int i = 0; i < field.length; i++) + { + if (this.field[i] == MINE) + { + continue; + } + + int[] count = { NO_MINE }; + + forEachNeighbor(i, neighborIndex -> { + if (this.field[neighborIndex] == MINE) + { + count[SELF_OFFSET]++; + } + }); + + this.field[i] = count[SELF_OFFSET]; + } + } + + private void popFieldVoid(final int index) + { + forEachNeighbor(index, neighborIndex -> { + + if (!revealed[neighborIndex]) + { + reveal(neighborIndex); + + if (field[neighborIndex] == NO_MINE) + { + popFieldVoid(neighborIndex); + } + } + }); + } + + private void startGame( + final int width, + final int height, + final int mines + ) { + this.flags = NO_FLAG; + this.buttons = new Button[width * height]; + this.width = width; + this.height = height; + + generateField(mines); + + final Stage gameStage; + final VBox box; + final GridPane grid; + + gameStage = new Stage(); + box = new VBox(); + grid = createGrid(width, height); + + box.getChildren().add(grid); + box.setAlignment(Pos.CENTER); + + final Scene scene; + scene = new Scene(box, WINDOW_WIDTH, WINDOW_HEIGHT); + + gameStage.setScene(scene); + gameStage.setTitle("Random Mines " + width + "x" + height); + gameStage.show(); + } + + private void flag(final int index) + { + this.flagged[index] = (this.flagged[index] + FLAG) % (FLAG_QUESTION + FLAG); + + final String buttonText; + + buttonText = this.flagged[index] == FLAG ? "F" : + this.flagged[index] == FLAG_QUESTION ? "?" : ""; + + this.buttons[index].setText(buttonText); + + this.flags = this.flagged[index] == FLAG ? this.flags + FLAG : this.flags - FLAG; + } + + private GridPane createGrid(final int width, final int height) + { + final GridPane grid; + grid = new GridPane(); + + grid.setPadding(new Insets(GAME_PADDING)); + grid.setHgap(GAME_PADDING); + grid.setVgap(GAME_PADDING); + + for (int i = 0; i < width; i++) + { + for (int j = 0; j < height; j++) + { + final Button button; + final int index; + + index = (j * width) + i; + button = new Button(); + + button.setFont(FONT); + button.setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT); + button.setStyle(BUTTON_THEMES.get(DEFAULT_BUTTON)); + button.setOnMouseEntered(e -> button.setCursor(javafx.scene.Cursor.HAND)); + button.setOnMouseExited(e -> button.setCursor(javafx.scene.Cursor.DEFAULT)); + button.setOnMouseClicked(e -> { + if (e.getButton() == MouseButton.PRIMARY) { + reveal(index); + } + else if (e.getButton() == MouseButton.SECONDARY) { + flag(index); + } + }); + + grid.add(button, i, j); + this.buttons[index] = button; + } + } + + return grid; + } + + private void reveal(final int index) + { + if (this.revealed[index]) + { + return; + } + + final String buttonText; + final Button button; + + button = this.buttons[index]; + + buttonText = "" + (this.field[index] == MINE ? "*" : + this.field[index] == NO_MINE ? " " : + this.field[index]); + + button.setText(buttonText); + button.setStyle(BUTTON_THEMES.get(this.field[index])); + button.setMouseTransparent(true); + button.setFocusTraversable(false); + + this.revealed[index] = true; + + if (this.field[index] == NO_MINE) + { + popFieldVoid(index); + } } public static void main(final String[] args) diff --git a/src/code/ca/bcit/comp2522/project/NumberGame.java b/src/code/ca/bcit/comp2522/project/NumberGame.java index d8fbec4..70d66fb 100644 --- a/src/code/ca/bcit/comp2522/project/NumberGame.java +++ b/src/code/ca/bcit/comp2522/project/NumberGame.java @@ -16,6 +16,8 @@ import java.util.Random; public class NumberGame extends Application { + private static final int STARTING_NUMBERS_PLACED = 0; + private static final int INDEX_OFFSET = 1; private static final int FONT_SIZE = 24; private static final int WINDOW_WIDTH = 700; private static final int WINDOW_HEIGHT = 600; @@ -24,39 +26,39 @@ public class NumberGame extends Application private static final int GRID_HEIGHT = 4; private static final int BUTTON_WIDTH = 200; private static final int BUTTON_HEIGHT = 160; - private static final int RANDOM_NUMBERS = 20; + private static final int TOTAL_NUMBERS = 20; private static final int MIN_RAND_NUM = 1; private static final int MAX_RAND_NUM = 1001; private static final Font FONT = Font.font("Arial", FontWeight.BOLD, FONT_SIZE); - private static final int STARTING_NUMBER_INDEX = 0; - private int currentIndex = STARTING_NUMBER_INDEX; - - private int[] numbers; + private int numbersPlaced; private Label numberLabel; + private int currentNumber; + private int[] positions; @Override public void start(final Stage stage) { - final Random rand = new Random(); + this.numbersPlaced = STARTING_NUMBERS_PLACED; + this.currentNumber = generateRandomNumber(); + this.positions = new int[GRID_WIDTH * GRID_HEIGHT]; - numbers = new int[RANDOM_NUMBERS]; - for (int i = 0; i < RANDOM_NUMBERS; i++) { - numbers[i] = rand.nextInt(MAX_RAND_NUM - MIN_RAND_NUM) + MIN_RAND_NUM; - } + this.numberLabel = new Label("Next number: " + this.currentNumber + " - Select a slot."); + this.numberLabel.setFont(FONT); + this.numberLabel.setMaxWidth(Double.MAX_VALUE); + this.numberLabel.setAlignment(Pos.CENTER); - numberLabel = new Label("Next number: " + numbers[currentIndex] + " - Select a slot."); - numberLabel.setFont(FONT); - numberLabel.setMaxWidth(Double.MAX_VALUE); - numberLabel.setAlignment(Pos.CENTER); + final VBox root; + root = new VBox(); + root.getChildren().add(this.numberLabel); - final VBox root = new VBox(10); - root.getChildren().add(numberLabel); - - final GridPane grid = createGrid(); + final GridPane grid; + grid = createGrid(); root.getChildren().add(grid); - final Scene scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT); + final Scene scene; + scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT); + stage.setScene(scene); stage.setTitle("20 Number Challenge"); stage.setResizable(false); @@ -65,28 +67,26 @@ public class NumberGame extends Application private GridPane createGrid() { - final GridPane grid = new GridPane(); + final GridPane grid; + grid = new GridPane(); + grid.setPadding(new Insets(GRID_PADDING)); grid.setHgap(GRID_PADDING); grid.setVgap(GRID_PADDING); - final Button[] buttons; - - buttons = new Button[GRID_WIDTH * GRID_HEIGHT]; - for (int i = 0; i < GRID_HEIGHT; i++) { for (int j = 0; j < GRID_WIDTH; j++) { - final Button button = new Button("[]"); + final Button button; + final int index; + + button = new Button("[]"); + index = (j * GRID_HEIGHT) + i; + button.setFont(FONT); button.setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT); - - final int index; - index = i * GRID_WIDTH + j; - buttons[index] = button; - - button.setOnAction(e -> handlePress(button)); + button.setOnAction(e -> handlePress(button, index)); grid.add(button, i, j); } @@ -95,20 +95,104 @@ public class NumberGame extends Application return grid; } - private void handlePress(final Button button) + private int generateRandomNumber() { - button.setText("" + numbers[currentIndex]); + final Random rand; + rand = new Random(); + return rand.nextInt(MAX_RAND_NUM - MIN_RAND_NUM) + MIN_RAND_NUM; + } + + private void triggerFailed() + { + 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; + } + + private void handlePress(final Button button, final int index) + { + button.setText("" + this.currentNumber); button.setDisable(true); + this.numbersPlaced++; - currentIndex++; + this.positions[index] = this.currentNumber; - if (currentIndex < RANDOM_NUMBERS) { - numberLabel.setText("Next number: " + numbers[currentIndex] + " - Select a slot."); - } - else + // Detect bad placement + for (int i = 0; i < GRID_WIDTH * GRID_HEIGHT; i++) { - numberLabel.setText("All numbers placed!"); + 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; + } } + + if (this.numbersPlaced >= TOTAL_NUMBERS) + { + this.numberLabel.setText("All numbers placed!"); + return; + } + + this.currentNumber = generateRandomNumber(); + + final boolean canPlaceNext; + canPlaceNext = canBePlaced(); + + if (!canPlaceNext) + { + triggerFailed(); + return; + } + + this.numberLabel.setText("Next number: " + this.currentNumber + " - Select a slot."); } public static void main(final String[] args) diff --git a/src/code/ca/bcit/comp2522/project/WordGame.java b/src/code/ca/bcit/comp2522/project/WordGame.java new file mode 100644 index 0000000..610bdbb --- /dev/null +++ b/src/code/ca/bcit/comp2522/project/WordGame.java @@ -0,0 +1,219 @@ +package ca.bcit.comp2522.project; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Random; +import java.util.Scanner; + +public class WordGame +{ + private static final String SCORE_PATH = "./data/score.txt"; + private static final int NUMBER_OF_QUESTIONS = 10; + private static final int QUESTION_NUM_OFFSET = 1; + private static final int QUEST_ASK_CAPITAL = 0; + private static final int QUEST_ASK_COUNTRY = 1; + private static final int QUEST_ASK_FACT = 2; + private static final int QUESTION_TYPES = 3; + private static final int MAX_ATTEMPTS = 2; + private static final int FIRST_ATTEMPT = 0; + private static final int SPLIT_DATE = 0; + private static final int SPLIT_TIME = 1; + private static final int FIRST_ATTEMPT_SCORE = 0; + private static final int SECOND_ATTEMPT_SCORE = 1; + private static final int INCORRECT_SCORE = 2; + private static final int DEFAULT_SCORE = 0; + + private final World world; + + public WordGame() + throws IOException + { + this.world = new World(); + } + + private static void checkAnswer( + final String correctAnswer, + final Scanner scanner, + final int[] scores + ) { + for (int i = 0; i < MAX_ATTEMPTS; i++) + { + final String answer; + + System.out.print("> "); + answer = scanner.nextLine(); + + if (answer.equalsIgnoreCase(correctAnswer)) + { + if (i == FIRST_ATTEMPT) + { + scores[FIRST_ATTEMPT_SCORE]++; + } + else + { + scores[SECOND_ATTEMPT_SCORE]++; + } + + System.out.println("CORRECT!"); + return; + } + + System.out.println("INCORRECT!"); + } + + scores[INCORRECT_SCORE]++; + System.out.printf("The correct answer was %s\n", correctAnswer); + } + + private void startTrivia( + final Scanner scanner, + final int[] scores + ) { + for (int i = 0; i < NUMBER_OF_QUESTIONS; i++) + { + System.out.printf("Question %d:\n", i + QUESTION_NUM_OFFSET); + + final Random rand; + final Country country; + final int questionType; + + rand = new Random(); + + country = this.world.getRandomCountry(); + questionType = rand.nextInt(QUESTION_TYPES); + + switch (questionType) + { + case QUEST_ASK_CAPITAL: + System.out.println("What is the country of the following capital?"); + System.out.println(country.getCapital()); + + checkAnswer(country.getName(), scanner, scores); + break; + + case QUEST_ASK_COUNTRY: + System.out.println("What is the capital of the following country?"); + System.out.println(country.getName()); + + checkAnswer(country.getCapital(), scanner, scores); + break; + + case QUEST_ASK_FACT: + System.out.println("What is the country of the following fact?"); + System.out.println(country.getRandomFact()); + + checkAnswer(country.getName(), scanner, scores); + break; + } + } + } + + public void runTrivia() + { + final Scanner scanner; + Score score; + boolean continuePlaying; + + continuePlaying = true; + scanner = new Scanner(System.in); + + final int[] scores; + int gamesPlayed; + + scores = new int[]{DEFAULT_SCORE,DEFAULT_SCORE,DEFAULT_SCORE}; + gamesPlayed = DEFAULT_SCORE; + + do + { + gamesPlayed++; + + this.startTrivia(scanner, scores); + + score = new Score( + LocalDateTime.now(), + gamesPlayed, + scores[FIRST_ATTEMPT_SCORE], + scores[SECOND_ATTEMPT_SCORE], + scores[INCORRECT_SCORE] + ); + + System.out.println(score); + + do + { + System.out.println("\nDo you want to play again?"); + System.out.print("> "); + + final String playAgain; + playAgain = scanner.nextLine(); + + if (playAgain.equalsIgnoreCase("no")) + { + continuePlaying = false; + break; + } + else if (playAgain.equalsIgnoreCase("yes")) + { + // break inner do-while loop + break; + } + else + { + System.out.printf("Invalid option \"%s\"\n", playAgain); + } + } while (true); + + } while (continuePlaying); + + scanner.close(); + + final List history; + + history = Score.readScoresFromFile(SCORE_PATH); + Score.appendScoreToFile(score, SCORE_PATH); + + if (Score.isHighScore(score, history)) + { + System.out.printf( + "CONGRATULATIONS! You have a new high score with an average of %.2f points per game; ", + score.calculateAverage() + ); + + final Score prevHighScore; + prevHighScore = Score.getHighScore(history); + + if (prevHighScore == null) + { + return; + } + + System.out.printf( + "the previous record was %.2f points per game ", + prevHighScore.calculateAverage() + ); + + System.out.printf( + "on %s at %s.\n", + prevHighScore.getDateTimePlayed().split(" ")[SPLIT_DATE], + prevHighScore.getDateTimePlayed().split(" ")[SPLIT_TIME] + ); + } + } + + public static void main(final String[] args) + { + final WordGame test; + + try + { + test = new WordGame(); + } + catch (final IOException e) + { + throw new RuntimeException(e); + } + + test.runTrivia(); + } +} diff --git a/src/code/ca/bcit/comp2522/project/World.java b/src/code/ca/bcit/comp2522/project/World.java index 3991ae3..98ef510 100644 --- a/src/code/ca/bcit/comp2522/project/World.java +++ b/src/code/ca/bcit/comp2522/project/World.java @@ -6,14 +6,12 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; -import java.util.Scanner; import java.util.stream.Stream; /** @@ -22,25 +20,10 @@ import java.util.stream.Stream; */ public class World { - private static final String SCORE_PATH = "./data/score.txt"; - private static final String BASE_PATH = "./data/facts"; - private static final int COUNTRY_PARAM = 0; - private static final int CAPITAL_PARAM = 1; - private static final int NUMBER_OF_FACTS = 3; - private static final int NUMBER_OF_QUESTIONS = 10; - private static final int QUESTION_NUM_OFFSET = 1; - private static final int QUEST_ASK_CAPITAL = 0; - private static final int QUEST_ASK_COUNTRY = 1; - private static final int QUEST_ASK_FACT = 2; - private static final int QUESTION_TYPES = 3; - private static final int MAX_ATTEMPTS = 2; - private static final int FIRST_ATTEMPT = 0; - private static final int SPLIT_DATE = 0; - private static final int SPLIT_TIME = 1; - private static final int FIRST_ATTEMPT_SCORE = 0; - private static final int SECOND_ATTEMPT_SCORE = 1; - private static final int INCORRECT_SCORE = 2; - private static final int DEFAULT_SCORE = 0; + private static final String BASE_PATH = "./data/facts"; + private static final int COUNTRY_PARAM = 0; + private static final int CAPITAL_PARAM = 1; + private static final int NUMBER_OF_FACTS = 3; private final Map countries; @@ -72,11 +55,12 @@ public class World { this.countries = new HashMap<>(); - try (Stream walk = Files.walk(Paths.get(BASE_PATH))) + try (final Stream walk = Files.walk(Paths.get(BASE_PATH))) { - List filesInFolder = walk - .filter(Files::isRegularFile) - .toList(); + final List filesInFolder; + filesInFolder = walk + .filter(Files::isRegularFile) + .toList(); for (final Path file : filesInFolder) { @@ -106,195 +90,17 @@ public class World } } - private void checkAnswer( - final String correctAnswer, - final Scanner scanner, - final int[] scores - ) { - for (int i = 0; i < MAX_ATTEMPTS; i++) - { - final String answer; - - System.out.print("> "); - answer = scanner.nextLine(); - - if (answer.equalsIgnoreCase(correctAnswer)) - { - if (i == FIRST_ATTEMPT) - { - scores[FIRST_ATTEMPT_SCORE]++; - } - else - { - scores[SECOND_ATTEMPT_SCORE]++; - } - - System.out.println("CORRECT!"); - return; - } - - System.out.println("INCORRECT!"); - } - - scores[INCORRECT_SCORE]++; - System.out.printf("The correct answer was %s\n", correctAnswer); - } - - private void startTrivia( - final Scanner scanner, - final int[] scores - ) { - for (int i = 0; i < NUMBER_OF_QUESTIONS; i++) - { - System.out.printf("Question %d:\n", i + QUESTION_NUM_OFFSET); - - final Random rand; - final Country country; - final String key; - final List keys; - final int questionType; - - rand = new Random(); - - keys = new ArrayList<>(this.countries.keySet()); - key = keys.get(rand.nextInt(keys.size())); - - questionType = rand.nextInt(QUESTION_TYPES); - country = this.countries.get(key); - - switch (questionType) - { - case QUEST_ASK_CAPITAL: - System.out.println("What is the country of the following capital?"); - System.out.println(country.getCapital()); - - checkAnswer(country.getName(), scanner, scores); - break; - - case QUEST_ASK_COUNTRY: - System.out.println("What is the capital of the following country?"); - System.out.println(country.getName()); - - checkAnswer(country.getCapital(), scanner, scores); - break; - - case QUEST_ASK_FACT: - System.out.println("What is the country of the following fact?"); - System.out.println(country.getRandomFact()); - - checkAnswer(country.getName(), scanner, scores); - break; - } - } - } - - public void runTrivia() + public Country getRandomCountry() { - final Scanner scanner; - Score score; - boolean continuePlaying; + final Random rand; + final String key; + final List keys; - continuePlaying = true; - scanner = new Scanner(System.in); + rand = new Random(); - final int[] scores; - int gamesPlayed; + keys = new ArrayList<>(this.countries.keySet()); + key = keys.get(rand.nextInt(keys.size())); - scores = new int[]{DEFAULT_SCORE,DEFAULT_SCORE,DEFAULT_SCORE}; - gamesPlayed = DEFAULT_SCORE; - - do - { - gamesPlayed++; - - this.startTrivia(scanner, scores); - - score = new Score( - LocalDateTime.now(), - gamesPlayed, - scores[FIRST_ATTEMPT_SCORE], - scores[SECOND_ATTEMPT_SCORE], - scores[INCORRECT_SCORE] - ); - - System.out.println(score); - - do - { - System.out.println("\nDo you want to play again?"); - System.out.print("> "); - - final String playAgain; - playAgain = scanner.nextLine(); - - if (playAgain.equalsIgnoreCase("no")) - { - continuePlaying = false; - break; - } - else if (playAgain.equalsIgnoreCase("yes")) - { - // break inner do-while loop - break; - } - else - { - System.out.printf("Invalid option \"%s\"\n", playAgain); - } - } while (true); - - } while (continuePlaying); - - scanner.close(); - - final List history; - - history = Score.readScoresFromFile(SCORE_PATH); - Score.appendScoreToFile(score, SCORE_PATH); - - if (Score.isHighScore(score, history)) - { - System.out.printf( - "CONGRATULATIONS! You have a new high score with an average of %.2f points per game; ", - score.calculateAverage() - ); - - final Score prevHighScore; - prevHighScore = Score.getHighScore(history); - - if (prevHighScore == null) - { - return; - } - - System.out.printf( - "the previous record was %.2f points per game ", - prevHighScore.calculateAverage() - ); - - System.out.printf( - "on %s at %s.\n", - prevHighScore.getDateTimePlayed().split(" ")[SPLIT_DATE], - prevHighScore.getDateTimePlayed().split(" ")[SPLIT_TIME] - ); - } - - - } - - public static void main(final String[] args) - { - final World test; - - try - { - test = new World(); - } - catch (final IOException e) - { - throw new RuntimeException(e); - } - - test.runTrivia(); + return this.countries.get(key); } }