Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ A simple number guessing game where you try to guess a randomly generated number
**Features:**
- Swing-based GUI (default)
- Console mode (use `--console` flag)
- High score tracking with usernames
- Persistent score storage
- Cross-platform

## Installation & Running
Expand Down Expand Up @@ -83,10 +85,13 @@ The game now features both a graphical user interface (GUI) and a console mode.
- Orange text indicates your guess was too high
- Green text indicates you guessed correctly!
5. The number of guesses is displayed and updated in real-time
6. When you guess correctly, click "New Game" to play again
7. Use the menu bar for additional options:
6. When you guess correctly, you'll be prompted to enter your username
7. After entering your username, your score will be saved and the top high scores will be displayed
8. Click "New Game" to play again
9. Use the menu bar for additional options:
- File → New Game (Ctrl+N): Start a new game
- File → Exit: Close the application
- View → High Scores: View the top high scores
- Help → About: View game information

#### Console Mode
Expand All @@ -105,6 +110,18 @@ In console mode:
2. The game will tell you if your guess is too high or too low
3. Keep guessing until you find the correct number
4. The game will display how many guesses it took you
5. Enter your username when prompted to save your score
6. The top high scores will be displayed after saving your score

### High Scores

The game automatically tracks high scores (games won with the fewest guesses). High scores are stored persistently in your home directory at `~/.numberguessinggame/highscores.properties`.

- The top 10 scores are kept
- Scores are sorted by the number of guesses (fewest is best)
- Each score includes the username and number of guesses
- High scores persist across game sessions
- View high scores from the GUI menu (View → High Scores) or after completing a game

## Development

Expand Down
85 changes: 78 additions & 7 deletions app/src/main/java/io/github/project516/NumberGuessingGame/GUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class GUI extends JFrame {
private RandomNumber randomGenerator;
private CheckGuess guessChecker;
private GameInfo gameInfo;
private HighScoreManager highScoreManager;

// UI Components
private JTextField guessField;
Expand All @@ -38,6 +39,15 @@ public GUI() {
guessChecker = new CheckGuess();
gameInfo = new GameInfo();

// Initialize high score manager
try {
highScoreManager = new HighScoreManager();
} catch (Exception e) {
System.err.println(
"Warning: Could not initialize high score system: " + e.getMessage());
highScoreManager = null;
}

// Set up the frame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 400);
Expand Down Expand Up @@ -76,6 +86,14 @@ private void createMenuBar() {
exitItem.addActionListener(e -> System.exit(0));
fileMenu.add(exitItem);

// View menu
JMenu viewMenu = new JMenu("View");
viewMenu.setMnemonic(KeyEvent.VK_V);

JMenuItem highScoresItem = new JMenuItem("High Scores", KeyEvent.VK_H);
highScoresItem.addActionListener(e -> showHighScores());
viewMenu.add(highScoresItem);

// Help menu
JMenu helpMenu = new JMenu("Help");
helpMenu.setMnemonic(KeyEvent.VK_H);
Expand All @@ -85,6 +103,7 @@ private void createMenuBar() {
helpMenu.add(aboutItem);

menuBar.add(fileMenu);
menuBar.add(viewMenu);
menuBar.add(helpMenu);

setJMenuBar(menuBar);
Expand Down Expand Up @@ -223,13 +242,8 @@ private void submitGuess() {
newGameButton.setVisible(true);
newGameButton.requestFocus();

// Show congratulations dialog
String message =
String.format(
"You guessed the number in %d %s!",
numberOfGuesses, numberOfGuesses == 1 ? "guess" : "guesses");
JOptionPane.showMessageDialog(
this, message, "Congratulations!", JOptionPane.INFORMATION_MESSAGE);
// Handle high score
handleHighScore();
}

guessField.setText("");
Expand Down Expand Up @@ -270,6 +284,63 @@ private void showAboutDialog() {
this, message, "About Number Guessing Game", JOptionPane.INFORMATION_MESSAGE);
}

/**
* Handles high score submission after a successful game. Prompts the user for their username
* and saves the score if applicable.
*/
private void handleHighScore() {
if (highScoreManager == null) {
// Show basic congratulations dialog if high score system is unavailable
String message =
String.format(
"You guessed the number in %d %s!",
numberOfGuesses, numberOfGuesses == 1 ? "guess" : "guesses");
JOptionPane.showMessageDialog(
this, message, "Congratulations!", JOptionPane.INFORMATION_MESSAGE);
return;
}

// Prompt for username
String username =
JOptionPane.showInputDialog(
this,
String.format(
"You guessed the number in %d %s!\n\nEnter your username (1-20 characters):",
numberOfGuesses, numberOfGuesses == 1 ? "guess" : "guesses"),
"Congratulations!",
JOptionPane.QUESTION_MESSAGE);

// Validate username
if (username != null && Username.isValid(username)) {
highScoreManager.addHighScore(username, numberOfGuesses);
showHighScores();
} else if (username != null) {
JOptionPane.showMessageDialog(
this, "Invalid username. Score not saved.", "Error", JOptionPane.ERROR_MESSAGE);
}
}

/** Displays the top high scores in a dialog. */
private void showHighScores() {
if (highScoreManager == null) {
return;
}

java.util.List<HighScore> topScores = highScoreManager.getTopHighScores(10);
if (topScores.isEmpty()) {
return;
}

StringBuilder sb = new StringBuilder();
sb.append("Top High Scores\n\n");
for (int i = 0; i < topScores.size(); i++) {
sb.append(String.format("%d. %s\n", i + 1, topScores.get(i)));
}

JOptionPane.showMessageDialog(
this, sb.toString(), "High Scores", JOptionPane.INFORMATION_MESSAGE);
}

/**
* Gets the version of the application.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
package io.github.project516.NumberGuessingGame;

import java.util.List;

/**
* Contains the main game logic for the Number Guessing Game. This class manages the game loop, user
* input, and guess validation.
*/
public class GameLogic {
private HighScoreManager highScoreManager;

/** Constructs a new GameLogic instance and initializes the high score manager. */
public GameLogic() {
try {
highScoreManager = new HighScoreManager();
} catch (Exception e) {
System.err.println(
"Warning: Could not initialize high score system: " + e.getMessage());
highScoreManager = null;
}
}

/**
* Runs the main game loop. Generates a random number and prompts the user to guess it. Provides
* feedback on each guess and tracks the number of attempts.
Expand All @@ -30,9 +45,36 @@ void game(ScannerHelper scan) {
} else {
numOfGuesses++;
System.out.println("Took you " + numOfGuesses + " guesses!");

// Handle high score
if (highScoreManager != null) {
String username = Username.promptUsername(scan);
if (highScoreManager.addHighScore(username, numOfGuesses)) {
System.out.println("Score saved!");
}
displayHighScores();
}
break;
}
numOfGuesses++;
}
}

/** Displays the top high scores to the console. */
private void displayHighScores() {
if (highScoreManager == null) {
return;
}

List<HighScore> topScores = highScoreManager.getTopHighScores(5);
if (topScores.isEmpty()) {
return;
}

System.out.println("\n=== Top High Scores ===");
for (int i = 0; i < topScores.size(); i++) {
System.out.println((i + 1) + ". " + topScores.get(i));
}
System.out.println("=======================\n");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.github.project516.NumberGuessingGame;

/**
* Represents a single high score entry in the Number Guessing Game. Each entry contains a username
* and the number of guesses it took to win the game.
*/
public class HighScore implements Comparable<HighScore> {
private final String username;
private final int numberOfGuesses;

/**
* Constructs a new HighScore entry.
*
* @param username the username of the player
* @param numberOfGuesses the number of guesses it took to win
* @throws IllegalArgumentException if username is null or empty, or if numberOfGuesses is less
* than 1
*/
public HighScore(String username, int numberOfGuesses) {
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException("Username cannot be null or empty");
}
if (numberOfGuesses < 1) {
throw new IllegalArgumentException("Number of guesses must be at least 1");
}
this.username = username.trim();
this.numberOfGuesses = numberOfGuesses;
}

/**
* Gets the username for this high score entry.
*
* @return the username
*/
public String getUsername() {
return username;
}

/**
* Gets the number of guesses for this high score entry.
*
* @return the number of guesses
*/
public int getNumberOfGuesses() {
return numberOfGuesses;
}

/**
* Compares this high score to another. High scores are ordered by number of guesses (ascending)
* so that lower scores (fewer guesses) come first.
*
* @param other the other high score to compare to
* @return a negative integer, zero, or a positive integer as this high score is less than,
* equal to, or greater than the specified high score
*/
@Override
public int compareTo(HighScore other) {
return Integer.compare(this.numberOfGuesses, other.numberOfGuesses);
}

@Override
public String toString() {
return username + ": " + numberOfGuesses + " guess" + (numberOfGuesses == 1 ? "" : "es");
}
}
Loading
Loading