diff --git a/WordGuessGame.java b/WordGuessGame.java
index e40967d..0475147 100644
--- a/WordGuessGame.java
+++ b/WordGuessGame.java
@@ -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.
- *
- * 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 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 wordOrdered = orderedUniqueLetters(word);
+ final Set 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 orderedUniqueLetters(final String s) {
+ final Set 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 uniqueLetters(final String s) {
+ final Set out = new HashSet<>();
+ for (char c : s.toCharArray()) {
+ if (Character.isLetter(c)) {
+ out.add(c);
+ }
+ }
+ return out;
}
}
+
+
+
diff --git a/WordGuessGameTest.java b/WordGuessGameTest.java
index aa85077..c713853 100644
--- a/WordGuessGameTest.java
+++ b/WordGuessGameTest.java
@@ -22,7 +22,7 @@ public void testCorrectGuessOnFirstTry() {
Optional result = game.play();
assertTrue(result.isPresent());
- assertEquals(6, result.get());
+ assertEquals(10, result.get());
System.setIn(originalIn);
}
@@ -37,14 +37,83 @@ public void testIncorrectThenCorrectGuess() {
Optional 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 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 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 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 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()));