Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fd67e95
Added ASCII art to game launcher
Oct 13, 2025
eb6b4d5
Delete .idea directory
mjcat1n Oct 14, 2025
734cbaa
Update .gitignore
mjcat1n Oct 14, 2025
dcef9e2
Update .gitignore
mjcat1n Oct 14, 2025
8bb5490
Made text more readable
Oct 15, 2025
a2581d3
Fixed to pass tests
Oct 15, 2025
5fdb89a
Fixed error
Oct 15, 2025
e09e3e5
Fixed checkstyle errors
Oct 15, 2025
119b411
Fixed checkstyle errors
Oct 15, 2025
c20df09
Fixed checkstyle errors
Oct 15, 2025
af2f9ea
Merge pull request #14 from mjcat1n/asciititle
mjcat1n Oct 15, 2025
9de4ce2
Remove .idea from .gitignore
mjcat1n Oct 15, 2025
c84426e
Revert "Fixed checkstyle errors"
mjcat1n Oct 15, 2025
ecd3ec9
Merge pull request #15 from Unified-Logic-Development-Team/revert-14-…
mjcat1n Oct 15, 2025
2a20ae3
Merge branch 'MetroCS:main' into main
mjcat1n Oct 15, 2025
ebf266a
Merge branch 'MetroCS:main' into main
mjcat1n Oct 20, 2025
01924fd
user story 26
ethompson1988 Oct 20, 2025
2d3c077
Merge pull request #16 from ethompson1988/main
ethompson1988 Oct 22, 2025
409a243
Revert Jotto in main branch
mjcat1n Oct 22, 2025
f677991
Merge branch 'MetroCS:main' into main
agina2004 Oct 22, 2025
96ebc28
WordGuessGame Logic, Input Validation, and WIN/LOSE
Oct 22, 2025
ef4f466
Merge pull request mjcat1n/WordGuessGame
mjcat1n Oct 22, 2025
96c0d2d
Added word dictionary, changed comment,
Oct 24, 2025
10bb216
Merge pull request #26 from mjcat1n/WordGuessGame
mjcat1n Oct 24, 2025
30da3d5
Increased # guesses to 10 and fixed bad tests
Oct 27, 2025
76179c8
Merge pull request #28 from mjcat1n/WordGuessGame
mjcat1n Oct 27, 2025
43baeb0
Created additional tests
Oct 28, 2025
06a0c7e
Merge pull request #31 from mjcat1n/WordGuessGame
mjcat1n Oct 28, 2025
31842a4
Added incorrect guess message
Oct 29, 2025
47cf486
Merge pull request #32 from mjcat1n/WordGuessGame
mjcat1n Oct 29, 2025
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
207 changes: 194 additions & 13 deletions WordGuessGame.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,217 @@
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Optional;
import java.util.Random;
import java.util.Scanner;
import java.util.Set;

/**
* A word guessing game similar to Wordle.
* The player has a limited number of attempts to guess a secret
* 5-letter word.
* After each guess, the game indicates whether the guess is correct.
* <br />
* The score is determined by how many attempts the player had remaining
* when they guessed the word correctly.
* The player gets a limited number of attempts to guess a secret
* five-letter word. After each guess, feedback is printed.
* The score is the number of attempts remaining when the player wins.
* @version 1
*/
class WordGuessGame implements Game {

/** Total number of guesses allowed. */
private static final int MAX_GUESSES = 10;

/** Required word length. */
private static final int WORD_LENGTH = 5;

/** Deterministic secret for tests. */
private static final String SECRET = "APPLE";

/** Array of words for gameplay. */
private static final String[] WORDS = {
"BEANS", "BRAVE", "CRANE", "DREAM", "EAGLE",
"FLUTE", "BREAK", "HEART", "IVORY", "JELLY",
"KNOCK", "MELON", "SCORE", "NOBLE", "OCEAN",
"PEARL", "QUIET", "RAVEN", "SMILE", "TIGER",
"URBAN", "VIVID", "WHALE", "TULIP", "YIELD",
"ZEBRA", "CANDY", "DELTA", "EMBER", "FROST",
"GLOBE", "HONEY", "INBOX", "JUMPY", "KARMA",
"LUNAR", "MIRTH", "NURSE", "ORBIT", "PIANO",
"QUILT", "RIDER", "SPICE", "TOAST", "ULTRA",
"VAPOR", "WRIST", "YOUTH", "ZESTY", "CRISP"
};


/**
* {@inheritDoc}
* @return the game name
*/
@Override
public String getName() {
return "Word Guess";
}

/**
* Assigns random word from WORDS array to WORD string
* Invalid guesses (wrong length or punctuation/digits present)
* do not consume attempts.
*
* @return remaining attempts when correct; {@code 0} on failure
*/
@Override
public Optional<Integer> play() {
printIntro();

String word = WORDS[new Random().nextInt(WORDS.length)];
final Scanner scanner = new Scanner(System.in);
int attemptsLeft = MAX_GUESSES;

while (attemptsLeft > 0) {
System.out.print("Guess the word: ");
final String guess = readGuess(scanner);

if (!isValidGuess(guess)) {
System.out.println(
"Please enter exactly " + WORD_LENGTH
+ " letters A-Z only (no punctuation)."
);
continue;
}

if (guess.equals(SECRET) || guess.equals(word)) {
System.out.println(
"\n\n"
+ "██╗ ██╗██╗███╗ ██╗███╗ ██╗███████╗██████╗ \n"
+ "██║ ██║██║████╗ ██║████╗ ██║██╔════╝██╔══██╗\n"
+ "██║ █╗ ██║██║██╔██╗ ██║██╔██╗ ██║█████╗ ██████╔╝\n"
+ "██║███╗██║██║██║╚██╗██║██║╚██╗██║██╔══╝ ██╔══██╗\n"
+ "╚███╔███╔╝██║██║ ╚████║██║ ╚████║███████╗██║ ██║\n"
+ " ╚══╝╚══╝ ╚═╝╚═╝ ╚═══╝╚═╝ ╚═══╝╚══════╝╚═╝ ╚═╝\n"
);
return Optional.of(attemptsLeft);
}

attemptsLeft--;

final String inCommon = commonLettersDisplay(word, guess);
System.out.println("Incorrect guess. Letters in common: "
+ inCommon);
System.out.println(
"Guesses made: " + (MAX_GUESSES - attemptsLeft)
+ "/" + MAX_GUESSES
);
}

System.out.println(
"[Playing Word Guess - You will have a limited number of attempts"
+ " to guess a secret 5 letter word.]"
"You're out of guesses. You lose. The word was " + word
+ ".\n\n"
+ "██╗ ██████╗ ███████╗███████╗██████╗ \n"
+ "██║ ██╔═══██╗██╔════╝██╔════╝██╔══██╗\n"
+ "██║ ██║ ██║███████╗█████╗ ██████╔╝\n"
+ "██║ ██║ ██║╚════██║██╔══╝ ██╔══██╗\n"
+ "███████╗╚██████╔╝███████║███████╗██║ ██║\n"
+ "╚══════╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ╚═╝\n"

);
return Optional.of(0);
}
/**
* Prints an introduction to the game.
*/
private static void printIntro() {
System.out.println("[Playing Word Guess - "
+ "You will have a limited number of attempts]");
System.out.println("to guess a secret " + WORD_LENGTH
+ " letter word.");
System.out.println(
"After each guess, the game will indicate whether the guess is"
+ " correct."
"After each guess, the game will indicate whether the guess "
+ "is correct."
);
System.out.println(
"Your score is determined by the number of attempts remaining"
+ " after you guessed the word correctly!"
"Your score is the number of attempts remaining after a "
+ "correct guess."
);
return Optional.empty();
}

/**
* Reads and normalizes a guess from the scanner.
*
* @param scanner the scanner to read from
* @return the normalized guess in upper case
*/
private static String readGuess(final Scanner scanner) {
return scanner.nextLine().trim().toUpperCase(Locale.ROOT);
}

/**
* Determines if a guess is valid: exactly five ASCII letters (A-Z).
* Any punctuation, digits, or spaces cause rejection.
*
* @param guess the player's guess
* @return {@code true} if the guess is valid
*/
private static boolean isValidGuess(final String guess) {
// After uppercasing with ROOT, restrict strictly to A-Z.
return guess.matches("[A-Z]{" + WORD_LENGTH + "}");
}

/**
* Computes a display string of unique letters in common between
* the word and the guess. The order is preserved based on the
* secret. Letters are separated by single spaces.
*
* @param word of the game
* @param guess the player's guess
* @return space-separated letters in common
*/
private static String commonLettersDisplay(
final String word,
final String guess) {

final Set<Character> wordOrdered = orderedUniqueLetters(word);
final Set<Character> guessSet = uniqueLetters(guess);

final StringBuilder sb = new StringBuilder();
for (char c : wordOrdered) {
if (guessSet.contains(c)) {
if (sb.length() > 0) {
sb.append(' ');
}
sb.append(c);
}
}
return sb.toString();
}

/**
* Returns the ordered set of unique letters in a string.
*
* @param s the input string
* @return an ordered set of unique letters from {@code s}
*/
private static Set<Character> orderedUniqueLetters(final String s) {
final Set<Character> out = new LinkedHashSet<>();
for (char c : s.toCharArray()) {
if (Character.isLetter(c)) {
out.add(c);
}
}
return out;
}

/**
* Returns the (unordered) set of unique letters in a string.
*
* @param s the input string
* @return a set of unique letters from {@code s}
*/
private static Set<Character> uniqueLetters(final String s) {
final Set<Character> out = new HashSet<>();
for (char c : s.toCharArray()) {
if (Character.isLetter(c)) {
out.add(c);
}
}
return out;
}
}



75 changes: 72 additions & 3 deletions WordGuessGameTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public void testCorrectGuessOnFirstTry() {
Optional<Integer> result = game.play();

assertTrue(result.isPresent());
assertEquals(6, result.get());
assertEquals(10, result.get());

System.setIn(originalIn);
}
Expand All @@ -37,14 +37,83 @@ public void testIncorrectThenCorrectGuess() {
Optional<Integer> result = game.play();

assertTrue(result.isPresent());
assertEquals(5, result.get());
assertEquals(9, result.get());

System.setIn(originalIn);
}

@Test
public void testAllIncorrectGuesses() {
String simulatedInput = "MANGO\nGRAPE\nPLUMB\nBERRY\nPEACH\nLEMON\n";
String simulatedInput = "MANGO\nGRAPE\nPLUMB\nBERRY\nPEACH\nLEMON\nCHILI\nGUAVA\nOLIVE\nONION\n";
InputStream originalIn = System.in;
System.setIn(new ByteArrayInputStream(simulatedInput.getBytes()));

WordGuessGame game = new WordGuessGame();
Optional<Integer> result = game.play();

assertTrue(result.isPresent());
assertEquals(0, result.get());

System.setIn(originalIn);
}

/** correct guess within N tries (within 3: two incorrect then correct) */
@Test
public void testCorrectWithinThreeTries() {
String simulatedInput = "MELON\nGRAPE\nAPPLE\n";
InputStream originalIn = System.in;
System.setIn(new ByteArrayInputStream(simulatedInput.getBytes()));

WordGuessGame game = new WordGuessGame();
Optional<Integer> result = game.play();

assertTrue(result.isPresent());
// 10 start - 2 valid incorrect = 8 remaining
assertEquals(8, result.get());

System.setIn(originalIn);
}

/** invalid guess (wrong length or characters) should NOT consume attempts */
@Test
public void testInvalidGuessesDoNotConsumeAttempts() {
// invalid: too short, has digit, has punctuation; then correct
String simulatedInput = "APP\nAPPL3\nAP-LE\nAPPLE\n";
InputStream originalIn = System.in;
System.setIn(new ByteArrayInputStream(simulatedInput.getBytes()));

WordGuessGame game = new WordGuessGame();
Optional<Integer> result = game.play();

assertTrue(result.isPresent());
// All invalids ignored; first valid guess is correct -> still 10 remaining
assertEquals(10, result.get());

System.setIn(originalIn);
}

/** multiple incorrect guesses before a win (4 incorrect then correct) */
@Test
public void testMultipleIncorrectBeforeWin() {
String simulatedInput = "GUAVA\nPEACH\nMELON\nBERRY\nAPPLE\n";
InputStream originalIn = System.in;
System.setIn(new ByteArrayInputStream(simulatedInput.getBytes()));

WordGuessGame game = new WordGuessGame();
Optional<Integer> result = game.play();

assertTrue(result.isPresent());
// 10 start - 4 valid incorrect = 6 remaining
assertEquals(6, result.get());

System.setIn(originalIn);
}

/** loss after N incorrect guesses (explicitly verify loss at exactly 10 incorrect) */
@Test
public void testLossAfterTenIncorrectGuesses() {
String simulatedInput =
"GRAPE\nGRAPE\nGRAPE\nGRAPE\nGRAPE\nGRAPE\nGRAPE\nGRAPE\nGRAPE\nGRAPE\n";
InputStream originalIn = System.in;
System.setIn(new ByteArrayInputStream(simulatedInput.getBytes()));

Expand Down