Skip to content

Commit 2509f4c

Browse files
authored
Merge pull request #69 from Project516/master
Prep 0.1.1
2 parents a774c6b + b3a2ed1 commit 2509f4c

22 files changed

Lines changed: 1916 additions & 27 deletions

File tree

.github/workflows/javadoc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ jobs:
2323

2424
- name: Generate JavaDoc
2525
run: ./gradlew javadoc
26+
27+
- name: Build TeaVM (JavaScript compilation)
28+
run: ./teavm.sh
2629

2730
- name: Deploy to GitHub Pages
2831
uses: peaceiris/actions-gh-pages@v4

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,7 @@ NumberGuessingGame-macos/
3535
NumberGuessingGame-linux/
3636
NumberGuessingGame-windows.zip
3737
NumberGuessingGame-macos.zip
38-
NumberGuessingGame-linux.tar.gz
38+
NumberGuessingGame-linux.tar.gz
39+
40+
# TeaVM generated JavaScript (build artifact)
41+
teavm/classes.js

README.md

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
A simple number guessing game where you try to guess a randomly generated number. The game features both a user-friendly graphical interface (GUI) and a classic console mode. The GUI provides visual feedback with color-coded hints and tracks your progress in real-time.
44

55
**Features:**
6-
- 🎮 Modern Swing-based GUI (default)
7-
- 💻 Classic console mode (use `--console` flag)
8-
- 🎯 Visual feedback with color coding
9-
- 📊 Real-time guess counter
10-
- ⌨️ Keyboard shortcuts for quick navigation
11-
- 🌍 Cross-platform compatible (Windows, macOS, Linux)
6+
- Swing-based GUI (default)
7+
- Console mode (use `--console` flag)
8+
- Web browser version (available on GitHub Pages)
9+
- High score tracking with usernames
10+
- Persistent score storage
11+
- Cross-platform
1212

1313
## Installation & Running
1414

@@ -62,7 +62,7 @@ Download the `archive.zip` from the [latest release](https://github.com/project5
6262

6363
#### Requirements
6464

65-
- Java 8 or higher (may require Java 17+ in future versions)
65+
- Java 11 or higher
6666

6767
#### How to Run
6868

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

9598
#### Console Mode
@@ -108,6 +111,18 @@ In console mode:
108111
2. The game will tell you if your guess is too high or too low
109112
3. Keep guessing until you find the correct number
110113
4. The game will display how many guesses it took you
114+
5. Enter your username when prompted to save your score
115+
6. The top high scores will be displayed after saving your score
116+
117+
### High Scores
118+
119+
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`.
120+
121+
- The top 10 scores are kept
122+
- Scores are sorted by the number of guesses (fewest is best)
123+
- Each score includes the username and number of guesses
124+
- High scores persist across game sessions
125+
- View high scores from the GUI menu (View → High Scores) or after completing a game
111126

112127
## Development
113128

app/build.gradle

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ plugins {
44

55
//Spotless
66
id 'com.diffplug.spotless' version '8.0.0'
7+
8+
// TeaVM plugin for JavaScript compilation
9+
id 'io.github.zebalu.teavm-gradle-plugin' version '1.0.0'
710
}
811

912
repositories {
@@ -14,6 +17,9 @@ repositories {
1417
dependencies {
1518
// This dependency is used by the application.
1619
implementation libs.guava
20+
21+
// TeaVM JSO APIs for web development (needed at compile time for WebGUI)
22+
compileOnly 'org.teavm:teavm-jso-apis:0.10.2'
1723
}
1824

1925
testing {
@@ -35,7 +41,10 @@ java {
3541
}
3642

3743
tasks.withType(JavaCompile) {
38-
options.release.set(8)
44+
// Changed from 8 to 11 to support TeaVM for web deployment.
45+
// TeaVM 0.10.2+ requires Java 11 as minimum target.
46+
// This change affects the minimum JRE required to run the JAR.
47+
options.release.set(11)
3948
}
4049

4150
application {
@@ -61,3 +70,9 @@ jar {
6170
)
6271
}
6372
}
73+
74+
// TeaVM configuration for compiling Java GUI to JavaScript
75+
teavm {
76+
// Main class to compile
77+
mainClass = 'io.github.project516.NumberGuessingGame.WebGUI'
78+
}

app/src/main/java/io/github/project516/NumberGuessingGame/GUI.java

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public class GUI extends JFrame {
1616
private RandomNumber randomGenerator;
1717
private CheckGuess guessChecker;
1818
private GameInfo gameInfo;
19+
private HighScoreManager highScoreManager;
1920

2021
// UI Components
2122
private JTextField guessField;
@@ -38,6 +39,15 @@ public GUI() {
3839
guessChecker = new CheckGuess();
3940
gameInfo = new GameInfo();
4041

42+
// Initialize high score manager
43+
try {
44+
highScoreManager = new HighScoreManager();
45+
} catch (Exception e) {
46+
System.err.println(
47+
"Warning: Could not initialize high score system: " + e.getMessage());
48+
highScoreManager = null;
49+
}
50+
4151
// Set up the frame
4252
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
4353
setSize(500, 400);
@@ -76,6 +86,14 @@ private void createMenuBar() {
7686
exitItem.addActionListener(e -> System.exit(0));
7787
fileMenu.add(exitItem);
7888

89+
// View menu
90+
JMenu viewMenu = new JMenu("View");
91+
viewMenu.setMnemonic(KeyEvent.VK_V);
92+
93+
JMenuItem highScoresItem = new JMenuItem("High Scores", KeyEvent.VK_H);
94+
highScoresItem.addActionListener(e -> showHighScores());
95+
viewMenu.add(highScoresItem);
96+
7997
// Help menu
8098
JMenu helpMenu = new JMenu("Help");
8199
helpMenu.setMnemonic(KeyEvent.VK_H);
@@ -85,6 +103,7 @@ private void createMenuBar() {
85103
helpMenu.add(aboutItem);
86104

87105
menuBar.add(fileMenu);
106+
menuBar.add(viewMenu);
88107
menuBar.add(helpMenu);
89108

90109
setJMenuBar(menuBar);
@@ -223,13 +242,8 @@ private void submitGuess() {
223242
newGameButton.setVisible(true);
224243
newGameButton.requestFocus();
225244

226-
// Show congratulations dialog
227-
String message =
228-
String.format(
229-
"You guessed the number in %d %s!",
230-
numberOfGuesses, numberOfGuesses == 1 ? "guess" : "guesses");
231-
JOptionPane.showMessageDialog(
232-
this, message, "Congratulations!", JOptionPane.INFORMATION_MESSAGE);
245+
// Handle high score
246+
handleHighScore();
233247
}
234248

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

287+
/**
288+
* Handles high score submission after a successful game. Prompts the user for their username
289+
* and saves the score if applicable.
290+
*/
291+
private void handleHighScore() {
292+
if (highScoreManager == null) {
293+
// Show basic congratulations dialog if high score system is unavailable
294+
String message =
295+
String.format(
296+
"You guessed the number in %d %s!",
297+
numberOfGuesses, numberOfGuesses == 1 ? "guess" : "guesses");
298+
JOptionPane.showMessageDialog(
299+
this, message, "Congratulations!", JOptionPane.INFORMATION_MESSAGE);
300+
return;
301+
}
302+
303+
// Prompt for username
304+
String username =
305+
JOptionPane.showInputDialog(
306+
this,
307+
String.format(
308+
"You guessed the number in %d %s!\n\nEnter your username (1-20 characters):",
309+
numberOfGuesses, numberOfGuesses == 1 ? "guess" : "guesses"),
310+
"Congratulations!",
311+
JOptionPane.QUESTION_MESSAGE);
312+
313+
// Validate username
314+
if (username != null && Username.isValid(username)) {
315+
highScoreManager.addHighScore(username, numberOfGuesses);
316+
showHighScores();
317+
} else if (username != null) {
318+
JOptionPane.showMessageDialog(
319+
this, "Invalid username. Score not saved.", "Error", JOptionPane.ERROR_MESSAGE);
320+
}
321+
}
322+
323+
/** Displays the top high scores in a dialog. */
324+
private void showHighScores() {
325+
if (highScoreManager == null) {
326+
return;
327+
}
328+
329+
java.util.List<HighScore> topScores = highScoreManager.getTopHighScores(10);
330+
if (topScores.isEmpty()) {
331+
return;
332+
}
333+
334+
StringBuilder sb = new StringBuilder();
335+
sb.append("Top High Scores\n\n");
336+
for (int i = 0; i < topScores.size(); i++) {
337+
sb.append(String.format("%d. %s\n", i + 1, topScores.get(i)));
338+
}
339+
340+
JOptionPane.showMessageDialog(
341+
this, sb.toString(), "High Scores", JOptionPane.INFORMATION_MESSAGE);
342+
}
343+
273344
/**
274345
* Gets the version of the application.
275346
*

app/src/main/java/io/github/project516/NumberGuessingGame/GameLogic.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,25 @@
11
package io.github.project516.NumberGuessingGame;
22

3+
import java.util.List;
4+
35
/**
46
* Contains the main game logic for the Number Guessing Game. This class manages the game loop, user
57
* input, and guess validation.
68
*/
79
public class GameLogic {
10+
private HighScoreManager highScoreManager;
11+
12+
/** Constructs a new GameLogic instance and initializes the high score manager. */
13+
public GameLogic() {
14+
try {
15+
highScoreManager = new HighScoreManager();
16+
} catch (Exception e) {
17+
System.err.println(
18+
"Warning: Could not initialize high score system: " + e.getMessage());
19+
highScoreManager = null;
20+
}
21+
}
22+
823
/**
924
* Runs the main game loop. Generates a random number and prompts the user to guess it. Provides
1025
* feedback on each guess and tracks the number of attempts.
@@ -30,9 +45,36 @@ void game(ScannerHelper scan) {
3045
} else {
3146
numOfGuesses++;
3247
System.out.println("Took you " + numOfGuesses + " guesses!");
48+
49+
// Handle high score
50+
if (highScoreManager != null) {
51+
String username = Username.promptUsername(scan);
52+
if (highScoreManager.addHighScore(username, numOfGuesses)) {
53+
System.out.println("Score saved!");
54+
}
55+
displayHighScores();
56+
}
3357
break;
3458
}
3559
numOfGuesses++;
3660
}
3761
}
62+
63+
/** Displays the top high scores to the console. */
64+
private void displayHighScores() {
65+
if (highScoreManager == null) {
66+
return;
67+
}
68+
69+
List<HighScore> topScores = highScoreManager.getTopHighScores(5);
70+
if (topScores.isEmpty()) {
71+
return;
72+
}
73+
74+
System.out.println("\n=== Top High Scores ===");
75+
for (int i = 0; i < topScores.size(); i++) {
76+
System.out.println((i + 1) + ". " + topScores.get(i));
77+
}
78+
System.out.println("=======================\n");
79+
}
3880
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.github.project516.NumberGuessingGame;
2+
3+
/**
4+
* Represents a single high score entry in the Number Guessing Game. Each entry contains a username
5+
* and the number of guesses it took to win the game.
6+
*/
7+
public class HighScore implements Comparable<HighScore> {
8+
private final String username;
9+
private final int numberOfGuesses;
10+
11+
/**
12+
* Constructs a new HighScore entry.
13+
*
14+
* @param username the username of the player
15+
* @param numberOfGuesses the number of guesses it took to win
16+
* @throws IllegalArgumentException if username is null or empty, or if numberOfGuesses is less
17+
* than 1
18+
*/
19+
public HighScore(String username, int numberOfGuesses) {
20+
if (username == null || username.trim().isEmpty()) {
21+
throw new IllegalArgumentException("Username cannot be null or empty");
22+
}
23+
if (numberOfGuesses < 1) {
24+
throw new IllegalArgumentException("Number of guesses must be at least 1");
25+
}
26+
this.username = username.trim();
27+
this.numberOfGuesses = numberOfGuesses;
28+
}
29+
30+
/**
31+
* Gets the username for this high score entry.
32+
*
33+
* @return the username
34+
*/
35+
public String getUsername() {
36+
return username;
37+
}
38+
39+
/**
40+
* Gets the number of guesses for this high score entry.
41+
*
42+
* @return the number of guesses
43+
*/
44+
public int getNumberOfGuesses() {
45+
return numberOfGuesses;
46+
}
47+
48+
/**
49+
* Compares this high score to another. High scores are ordered by number of guesses (ascending)
50+
* so that lower scores (fewer guesses) come first.
51+
*
52+
* @param other the other high score to compare to
53+
* @return a negative integer, zero, or a positive integer as this high score is less than,
54+
* equal to, or greater than the specified high score
55+
*/
56+
@Override
57+
public int compareTo(HighScore other) {
58+
return Integer.compare(this.numberOfGuesses, other.numberOfGuesses);
59+
}
60+
61+
@Override
62+
public String toString() {
63+
return username + ": " + numberOfGuesses + " guess" + (numberOfGuesses == 1 ? "" : "es");
64+
}
65+
}

0 commit comments

Comments
 (0)