diff --git a/src/main/java/edu/project1/ConsoleHangman.java b/src/main/java/edu/project1/ConsoleHangman.java new file mode 100644 index 0000000..2933e90 --- /dev/null +++ b/src/main/java/edu/project1/ConsoleHangman.java @@ -0,0 +1,40 @@ +package edu.project1; + +import java.io.PrintWriter; +import java.util.Scanner; + +public class ConsoleHangman { + private static final String EXIT_COMMAND = "exit"; + private static final String GUESS_MESSAGE = "Guess a letter:"; + private static final int MAX_ATTEMPTS = 10; + + private final PrintWriter out = new PrintWriter(System.out); + private final Scanner scanner = new Scanner(System.in); + private final Dictionary dictionary = new RandomDictionary(); + + public void run() { + Session session = new Session(dictionary.getWord(), MAX_ATTEMPTS); + + GuessResult lastResult = null; + while (!(lastResult instanceof GuessResult.Win) && (!(lastResult instanceof GuessResult.Defeat))) { + out.println(GUESS_MESSAGE); + out.flush(); + + lastResult = tryGuess(session, scanner.nextLine()); + printState(lastResult); + } + } + + private GuessResult tryGuess(Session session, String input) { + if (EXIT_COMMAND.equals(input)) { + return session.giveUp(); + } + + return session.guess(input); + } + + private void printState(GuessResult result) { + out.println(result.getMessage()); + out.flush(); + } +} diff --git a/src/main/java/edu/project1/Dictionary.java b/src/main/java/edu/project1/Dictionary.java new file mode 100644 index 0000000..5a14019 --- /dev/null +++ b/src/main/java/edu/project1/Dictionary.java @@ -0,0 +1,7 @@ +package edu.project1; + +import org.jetbrains.annotations.NotNull; + +public interface Dictionary { + @NotNull String getWord(); +} diff --git a/src/main/java/edu/project1/GuessResult.java b/src/main/java/edu/project1/GuessResult.java new file mode 100644 index 0000000..6f29b2b --- /dev/null +++ b/src/main/java/edu/project1/GuessResult.java @@ -0,0 +1,58 @@ +package edu.project1; + +import org.jetbrains.annotations.NotNull; + +public sealed interface GuessResult { + @SuppressWarnings("unused") + char[] state(); + + @SuppressWarnings("unused") + int attempt(); + + @SuppressWarnings("unused") + int maxAttempts(); + + @SuppressWarnings("unused") + @NotNull String getMessage(); + + record Defeat(char[] state, int attempt, int maxAttempts) implements GuessResult { + @Override public @NotNull String getMessage() { + return String.format( + "The word: %s\nYou lost! (attempts %d out of %d)\n", + new String(state), + attempt, + maxAttempts + ); + } + } + + record Win(char[] state, int attempt, int maxAttempts) implements GuessResult { + @Override public @NotNull String getMessage() { + return String.format( + "You won! (attempts %d out of %d).\nThe word was: %s", + attempt, + maxAttempts, + new String(state) + ); + } + } + + record SuccessGuess(char[] state, int attempt, int maxAttempts) implements GuessResult { + + @Override public @NotNull String getMessage() { + return String.format("Hit!\nThe word: %s", new String(state)); + } + } + + record FailedGuess(char[] state, int attempt, int maxAttempts) implements GuessResult { + @Override public @NotNull String getMessage() { + return String.format("Missed, mistake %d out of %d\nThe word: %s", attempt, maxAttempts, new String(state)); + } + } + + record IncorrectGuess(char[] state, int attempt, int maxAttempts) implements GuessResult { + @Override public @NotNull String getMessage() { + return "Incorrect input. Try again!"; + } + } +} diff --git a/src/main/java/edu/project1/Main.java b/src/main/java/edu/project1/Main.java index cbd494f..0336af3 100644 --- a/src/main/java/edu/project1/Main.java +++ b/src/main/java/edu/project1/Main.java @@ -1,27 +1,13 @@ package edu.project1; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - // Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`, // then press Enter. You can now see whitespace characters in your code. public final class Main { - private final static Logger LOGGER = LogManager.getLogger(); - private Main() { } public static void main(String[] args) { - // Press Alt+Enter with your caret at the highlighted text to see how - // IntelliJ IDEA suggests fixing it. - LOGGER.info("Hello and welcome!"); - - // Press Shift+F10 or click the green arrow button in the gutter to run the code. - for (int i = 0; i <= 2; i++) { - - // Press Shift+F9 to start debugging your code. We have set one breakpoint - // for you, but you can always add more by pressing Ctrl+F8. - LOGGER.info("i = {}", i); - } + ConsoleHangman consoleHangman = new ConsoleHangman(); + consoleHangman.run(); } } diff --git a/src/main/java/edu/project1/RandomDictionary.java b/src/main/java/edu/project1/RandomDictionary.java new file mode 100644 index 0000000..89a2981 --- /dev/null +++ b/src/main/java/edu/project1/RandomDictionary.java @@ -0,0 +1,14 @@ +package edu.project1; + +import java.util.Random; +import org.jetbrains.annotations.NotNull; + +public class RandomDictionary implements Dictionary { + private static final String[] WORDS = {"hello", "easy", "project"}; + private static final Random RANDOM = new Random(); + + @Override + public @NotNull String getWord() { + return WORDS[RANDOM.nextInt(WORDS.length)]; + } +} diff --git a/src/main/java/edu/project1/Session.java b/src/main/java/edu/project1/Session.java new file mode 100644 index 0000000..216ae54 --- /dev/null +++ b/src/main/java/edu/project1/Session.java @@ -0,0 +1,67 @@ +package edu.project1; + +import org.jetbrains.annotations.NotNull; + +public class Session { + private final String answer; + private final char[] userAnswer; + private final int maxAttempts; + private int attempts; + private int guessCount; + + public Session(String answer, int maxAttempts) { + assert answer != null && !answer.isEmpty(); + this.answer = answer; + this.userAnswer = "*".repeat(answer.length()).toCharArray(); + this.maxAttempts = maxAttempts; + this.attempts = 0; + this.guessCount = 0; + } + + @NotNull GuessResult guess(String guess) { + if (guess.length() != 1) { + return new GuessResult.IncorrectGuess(userAnswer, attempts, maxAttempts); + } + + char guessLetter = guess.charAt(0); + + boolean wasGuess = false; + + for (int i = 0; i < answer.length(); ++i) { + if (userAnswer[i] == '*' && answer.charAt(i) == guessLetter) { + ++guessCount; + userAnswer[i] = guessLetter; + wasGuess = true; + } + } + + if (!wasGuess) { + attempts++; + } + + if (guessCount == answer.length()) { + return new GuessResult.Win(userAnswer, attempts, maxAttempts); + } + + if (attempts == maxAttempts) { + return new GuessResult.Defeat(userAnswer, attempts, maxAttempts); + } + + return terminalGuess(wasGuess); + } + + /** + * function to fix limit on <= 4 returns in one function in mvn::checkstyle + **/ + private @NotNull GuessResult terminalGuess(boolean wasGuess) { + if (wasGuess) { + return new GuessResult.SuccessGuess(userAnswer, attempts, maxAttempts); + } else { + return new GuessResult.FailedGuess(userAnswer, attempts, maxAttempts); + } + } + + @NotNull GuessResult giveUp() { + return new GuessResult.Defeat(userAnswer, attempts, maxAttempts); + } +} diff --git a/src/main/java/edu/project1/SingleWordDictionary.java b/src/main/java/edu/project1/SingleWordDictionary.java new file mode 100644 index 0000000..d1f5c4b --- /dev/null +++ b/src/main/java/edu/project1/SingleWordDictionary.java @@ -0,0 +1,12 @@ +package edu.project1; + +import org.jetbrains.annotations.NotNull; + +@SuppressWarnings("unused") +public record SingleWordDictionary(String word) implements Dictionary { + + @Override + public @NotNull String getWord() { + return word; + } +}