diff --git a/README.md b/README.md index d3179421..903ed09c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # ๋ฏธ์…˜ - ์›Œ๋“ค +## ๐Ÿ™†๐Ÿปโ€โ™€๏ธํŽ˜์–ด ๊ตฌ์„ฑ๐Ÿ™†๐Ÿป +- ์ ํ”„ +- ์–„๋ญ‰ +--- + ## ๐Ÿ” ์ง„ํ–‰ ๋ฐฉ์‹ - ๋ฏธ์…˜์€ **๊ณผ์ œ ์ง„ํ–‰ ์š”๊ตฌ ์‚ฌํ•ญ**, **๊ธฐ๋Šฅ ์š”๊ตฌ ์‚ฌํ•ญ**, **ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ ์‚ฌํ•ญ** ์„ธ ๊ฐ€์ง€๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค. @@ -12,13 +17,16 @@ ์„ ํ’์ ์ธ ์ธ๊ธฐ๋ฅผ ๋Œ์—ˆ๋˜ ์˜์–ด ๋‹จ์–ด ๋งž์ถ”๊ธฐ ๊ฒŒ์ž„์ด๋‹ค. -- 6x5 ๊ฒฉ์ž๋ฅผ ํ†ตํ•ด์„œ 5๊ธ€์ž ๋‹จ์–ด๋ฅผ 6๋ฒˆ ๋งŒ์— ์ถ”์ธกํ•œ๋‹ค. -- ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋‹ต์•ˆ์„ ์ œ์ถœํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ •๋‹ต๊ณผ ์ œ์ถœ๋œ ๋‹จ์–ด์˜ ๊ฐ ์•ŒํŒŒ๋ฒณ ์ข…๋ฅ˜์™€ ์œ„์น˜๋ฅผ ๋น„๊ตํ•ด ํŒ๋ณ„ํ•œ๋‹ค. -- ํŒ๋ณ„ ๊ฒฐ๊ณผ๋Š” ํฐ์ƒ‰์˜ ํƒ€์ผ์ด ์„ธ ๊ฐ€์ง€ ์ƒ‰(์ดˆ๋ก์ƒ‰/๋…ธ๋ž€์ƒ‰/ํšŒ์ƒ‰) ์ค‘ ํ•˜๋‚˜๋กœ ๋ฐ”๋€Œ๋ฉด์„œ ํ‘œํ˜„๋œ๋‹ค. - - ๋งž๋Š” ๊ธ€์ž๋Š” ์ดˆ๋ก์ƒ‰, ์œ„์น˜๊ฐ€ ํ‹€๋ฆฌ๋ฉด ๋…ธ๋ž€์ƒ‰, ์—†์œผ๋ฉด ํšŒ์ƒ‰ +- [x] ๊ฒŒ์ž„ ์ง„ํ–‰ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. +- [x] ๊ฒฉ์ž๋ฅผ ํ†ตํ•ด์„œ 5๊ธ€์ž ๋‹จ์–ด๋ฅผ 6๋ฒˆ ๋งŒ์— ์ถ”์ธกํ•œ๋‹ค. +- [x] ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ๋‹ต์•ˆ์„ ์ œ์ถœํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ •๋‹ต๊ณผ ์ œ์ถœ๋œ ๋‹จ์–ด์˜ ๊ฐ ์•ŒํŒŒ๋ฒณ ์ข…๋ฅ˜์™€ ์œ„์น˜๋ฅผ ๋น„๊ตํ•ด ํŒ๋ณ„ํ•œ๋‹ค. + - [x] ์ž…๋ ฅ ๋‹จ์–ด๋Š” ์˜๋‹จ์–ด์•ผ ํ•œ๋‹ค. + - [x] ๋‹จ์–ด์˜ ์ˆ˜๋Š” 5๊ธ€์ž์—ฌ์•ผ ํ•œ๋‹ค. + - [x] ๋‹จ์–ด๋Š” `words.txt`์— ํฌํ•จ๋œ ๋‹จ์–ด์—ฌ์•ผ ํ•œ๋‹ค. +- [x] ํŒ๋ณ„ ๊ฒฐ๊ณผ๋Š” ํฐ์ƒ‰์˜ ํƒ€์ผ์ด ์„ธ ๊ฐ€์ง€ ์ƒ‰(์ดˆ๋ก์ƒ‰/๋…ธ๋ž€์ƒ‰/ํšŒ์ƒ‰) ์ค‘ ํ•˜๋‚˜๋กœ ๋ฐ”๋€Œ๋ฉด์„œ ํ‘œํ˜„๋œ๋‹ค. + - ๋งž๋Š” ๊ธ€์ž๋Š” ์ดˆ๋ก์ƒ‰(๐ŸŸฉ), ์œ„์น˜๊ฐ€ ํ‹€๋ฆฌ๋ฉด ๋…ธ๋ž€์ƒ‰(๐ŸŸจ), ์—†์œผ๋ฉด ํšŒ์ƒ‰(โฌœ) - ๋‘ ๊ฐœ์˜ ๋™์ผํ•œ ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ๊ทธ์ค‘ ํ•˜๋‚˜๊ฐ€ ํšŒ์ƒ‰์œผ๋กœ ํ‘œ์‹œ๋˜๋ฉด ํ•ด๋‹น ๋ฌธ์ž ์ค‘ ํ•˜๋‚˜๋งŒ ์ตœ์ข… ๋‹จ์–ด์— ๋‚˜ํƒ€๋‚œ๋‹ค. -- ์ •๋‹ต๊ณผ ๋‹ต์•ˆ์€ `words.txt`์— ์กด์žฌํ•˜๋Š” ๋‹จ์–ด์—ฌ์•ผ ํ•œ๋‹ค. -- ์ •๋‹ต์€ ๋งค์ผ ๋ฐ”๋€Œ๋ฉฐ ((ํ˜„์žฌ ๋‚ ์งœ - 2021๋…„ 6์›” 19์ผ) % ๋ฐฐ์—ด์˜ ํฌ๊ธฐ) ๋ฒˆ์งธ์˜ ๋‹จ์–ด์ด๋‹ค. +- [x] ์ •๋‹ต์€ ๋งค์ผ ๋ฐ”๋€Œ๋ฉฐ ((ํ˜„์žฌ ๋‚ ์งœ - 2021๋…„ 6์›” 19์ผ) % ๋ฐฐ์—ด์˜ ํฌ๊ธฐ) ๋ฒˆ์งธ์˜ ๋‹จ์–ด์ด๋‹ค. ### ์ž…์ถœ๋ ฅ ์š”๊ตฌ ์‚ฌํ•ญ @@ -87,3 +95,36 @@ spill - ๋„๋ฉ”์ธ ๋กœ์ง์— ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋‹จ, UI(System.out, System.in, Scanner) ๋กœ์ง์€ ์ œ์™ธํ•œ๋‹ค. - ํ•ต์‹ฌ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๋Š” ์ฝ”๋“œ์™€ UI๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ๋กœ์ง์„ ๋ถ„๋ฆฌํ•ด ๊ตฌํ˜„ํ•œ๋‹ค. - ํžŒํŠธ: MVC ํŒจํ„ด ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„ํ•œ ํ›„, View์™€ Controller๋ฅผ ์ œ์™ธํ•œ Model์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€์— ์ง‘์ค‘ํ•œ๋‹ค. +--- +### ๊ตฌํ˜„ ๋ชฉ๋ก +- ๋‹จ์–ด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ +- ๋งค์ผ ๋ฐ”๋€Œ๋Š” ์ •๋‹ต๋‹จ์–ด ์„ ํƒ +- ๋‹จ์–ด ์ž…๋ ฅ + - ์ž…๋ ฅ์‹œ ๋‹จ์–ด๋ชฉ๋ก์— ์žˆ๋‚˜ ๊ฒ€์ฆ +- ๋น„๊ต ๋กœ์ง + - ๊ฐ™์„๋•Œ, ์žˆ์„๋–„, ์—†์„๋•Œ ๋”ฐ๋ฅธ ๋น„๊ต๊ฒฐ๊ณผ +- ๊ฒŒ์ž„๋กœ์ง + - 6ํšŒ ์ดˆ๊ณผ์‹œ ๊ฒŒ์ž„์˜ค๋ฒ„ + - ์ •๋‹ต์‹œ ๊ฒŒ์ž„ํด๋ฆฌ์–ด +- ui + - ๋น„๊ต ๊ฒฐ๊ณผ, ๋ผ์šด๋“œ ์ถœ๋ ฅ + +--- +### ๋ฆฌํŒฉํ„ฐ๋ง ํฌ์ธํŠธ +- [x] final ๋ถ™ํ˜€์ฃผ๊ธฐ +- [x] Inputword ์— availableWords ์ƒํƒœ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ์„ ํ•„์š”๋Š” ์—†๋‹ค. +- [x] InputWord์™€ Answer๋ฅผ ํ•ฉ์น˜๊ธฐ? +- [x] match ์— for ๋ฌธ์•ˆ ํ•จ์ˆ˜๋กœ ๋ฐœ๋ผ๋‚ด๊ธฐ +- [x] isEndGame ํ”Œ๋ž˜๊ทธ ๋ณ€์ˆ˜ ๋„ค์ด๋ฐ ๋ณ€๊ฒฝ + - [x] ๊ฒ€์ฆ + - [x] 5๊ธ€์ž ๊ฒ€์ฆ +- [x] ์˜๋‹จ์–ด ๊ฒ€์ฆ +- [x] ์˜ˆ์™ธ try catch +- [x] GameManager์— ์žˆ๋Š” List ์˜ ๋ณ€์ˆ˜๋ช… ๋ณ€๊ฒฝ +- [x] HintView์— 3depth ์ค„์ด๊ธฐ +- [x] InputWord์˜ ๋งˆ์ง€๋ง‰ ํ…Œ์ŠคํŠธํ•จ์ˆ˜ ์ด๋ฆ„ +- [x] MatchResult์— inputChar๊ฐ€ ์“ฐ์ด์ง€ ์•Š๊ณ  ์žˆ์–ด์„œ ํด๋ž˜์Šค ์ž์ฒด๋ฅผ ์ง€์šฐ๊ณ  ๊ทธ๋ƒฅ Hint๋งŒ ์“ฐ๊ธฐ +- ~~- ๊ตฌ์กฐ ๋ณ€๊ฒฝ~~ + - ~~- GameManager์˜ ์˜์กด์„ฑ ์ค„์—ฌ๋‘๊ธฐ~~ + - ~~-String ๋ง๊ณ  char ๋ฐฐ์—ด๋กœ ์“ธ์ง€? -> ์ข€ ๋” ๊ณ ๋ฏผํ•ด๋ณด๊ธฐ~~ + - ~~-๋ถ„๋ฆฌ๋œ view ๋ถ€๋ถ„ ํ•ฉ์น ์ง€?~~ diff --git a/src/main/java/WordleApplication.java b/src/main/java/WordleApplication.java new file mode 100644 index 00000000..6bfdff82 --- /dev/null +++ b/src/main/java/WordleApplication.java @@ -0,0 +1,15 @@ +import config.FileConfig; +import controller.GameManager; +import infra.WordLoader; + +import java.util.List; + +public class WordleApplication { + public static void main(String[] args) { + + List words = WordLoader.read(FileConfig.FILE_PATH); + GameManager gameManager = new GameManager(words); + gameManager.start(); + } + +} diff --git a/src/main/java/config/FileConfig.java b/src/main/java/config/FileConfig.java new file mode 100644 index 00000000..9eebf506 --- /dev/null +++ b/src/main/java/config/FileConfig.java @@ -0,0 +1,8 @@ +package config; + +public class FileConfig { + + protected FileConfig() { + } + public static final String FILE_PATH = "src/main/resources/words.txt"; +} diff --git a/src/main/java/controller/GameManager.java b/src/main/java/controller/GameManager.java new file mode 100644 index 00000000..9ce6b27f --- /dev/null +++ b/src/main/java/controller/GameManager.java @@ -0,0 +1,86 @@ +package controller; + +import domain.MatchResult; +import domain.MatchResults; +import domain.Round; +import domain.Word; +import ui.GuideTextView; +import ui.HintView; +import ui.InputView; +import ui.RoundView; + +import java.time.LocalDate; +import java.util.List; + +public class GameManager { + + private final static int LIMIT = 6; + private final static int CURRENT = 1; + private final Round round; + private final MatchResults matchResults; + private final Word answer; + private final GuideTextView guideTextView; + private final InputView inputView; + private final HintView hintView; + private final RoundView roundView; + private final List availableWords; + private boolean isWinning = false; + + public GameManager(List availableWords) { + this.answer = Word.createAnswer(LocalDate.now(), availableWords); + this.availableWords = availableWords; + this.round = new Round(LIMIT, CURRENT); + this.matchResults = new MatchResults(); + this.guideTextView = new GuideTextView(); + this.inputView = new InputView(); + this.hintView = new HintView(); + this.roundView = new RoundView(); + } + public void start() { + guideTextView.render(); + while(!this.isWinning && round.isNotFinalRound()) { + startRound(); + } + } + + private void startRound() { + Word inputWord = null; + boolean canCreateInputWord = false; + + while (!canCreateInputWord) { + String input = inputView.input(); + inputWord = Word.createInput(input, this.availableWords); + canCreateInputWord = inputWord.getAvailableWord(); + } + + checkAnswer(inputWord); + renderResult(); + round.goNext(); + } + + private void renderResult() { + checkRenderRound(); + hintView.render(matchResults); + checkFinalRound(); + } + + private void checkRenderRound() { + if(this.isWinning || !round.isNotFinalRound()) { + roundView.render(round.getCurrent(),round.getLimit()); + } + } + + private void checkFinalRound() { + if(!this.isWinning && round.isFinalRound()) { + roundView.render(round.getCurrent(),round.getLimit()); + roundView.renderLoseGame();; + } + } + + private void checkAnswer(Word inputWord) { + MatchResult matchResultOfInput = answer.match(inputWord); + this.matchResults.add(matchResultOfInput); + this.isWinning = matchResultOfInput.isEndGame(); + } + +} diff --git a/src/main/java/domain/Hint.java b/src/main/java/domain/Hint.java new file mode 100644 index 00000000..71565059 --- /dev/null +++ b/src/main/java/domain/Hint.java @@ -0,0 +1,20 @@ +package domain; + +public enum Hint { + CORRECT("๐ŸŸฉ"), // \uD83D\uDFE9 + EXIST("๐ŸŸจ"), // \uD83D\uDFE8 + NOT_EXIST("โฌœ"); + private final String tile; + + Hint(String tile) { + this.tile = tile; + } + + public String getTile() { + return tile; + } + + public static boolean isCorrect(Hint hint) { + return Hint.CORRECT.equals(hint); + } +} diff --git a/src/main/java/domain/HintLetter.java b/src/main/java/domain/HintLetter.java new file mode 100644 index 00000000..fc4a131f --- /dev/null +++ b/src/main/java/domain/HintLetter.java @@ -0,0 +1,44 @@ +package domain; + +import java.util.List; +import java.util.Objects; + +public class HintLetter { + private final Character letter; + + private Hint hint; + + public HintLetter(Character letter, Hint hint) { + this.letter = letter; + this.hint = hint; + } + + public void changeCorrectToNotExist(List correctedChar) { + if(correctedChar.contains(letter) && !isCorrectHint()) { + this.hint = Hint.NOT_EXIST; + } + } + + public boolean isCorrectHint() { + return Hint.isCorrect(hint); + } + + public String getHintTile() { + return hint.getTile(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HintLetter that = (HintLetter) o; + return Objects.equals(letter, that.letter) && hint == that.hint; + } + + @Override + public int hashCode() { + return Objects.hash(letter, hint); + } +} + + diff --git a/src/main/java/domain/MatchResult.java b/src/main/java/domain/MatchResult.java new file mode 100644 index 00000000..a848a04e --- /dev/null +++ b/src/main/java/domain/MatchResult.java @@ -0,0 +1,42 @@ +package domain; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class MatchResult { + private final List hints; + public MatchResult(List hints) { + this.hints = hints; + } + + public boolean isEndGame() { + return hints.stream() + .allMatch(HintLetter::isCorrectHint); + } + public void add(HintLetter hintLetter) { + hints.add(hintLetter); + } + + public String getHintTiles() { + return hints.stream() + .map(HintLetter::getHintTile) + .collect(Collectors.joining()); + } + + @Override + public boolean equals(Object o) { + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MatchResult that = (MatchResult) o; + return Objects.equals(hints, that.hints); + } + + @Override + public int hashCode() { + return Objects.hashCode(hints); + } +} + + diff --git a/src/main/java/domain/MatchResults.java b/src/main/java/domain/MatchResults.java new file mode 100644 index 00000000..ad14cbfc --- /dev/null +++ b/src/main/java/domain/MatchResults.java @@ -0,0 +1,19 @@ +package domain; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class MatchResults implements Iterable { + private final List results; + public MatchResults() { + this.results = new ArrayList<>(); + } + public void add(MatchResult matchResultOfInput) { + this.results.add(matchResultOfInput); + } + @Override + public Iterator iterator() { + return this.results.iterator(); + } +} diff --git a/src/main/java/domain/Round.java b/src/main/java/domain/Round.java new file mode 100644 index 00000000..668e2512 --- /dev/null +++ b/src/main/java/domain/Round.java @@ -0,0 +1,31 @@ +package domain; + +public class Round { + private final int limit; + private int current; + + public Round(int limit, int current) { + this.limit = limit; + this.current = current; + } + + public void goNext() { + this.current++; + } + + public int getLimit() { + return limit; + } + + public int getCurrent() { + return current; + } + + public boolean isNotFinalRound() { + return current <= limit; + } + + public boolean isFinalRound() { + return current == limit; + } +} diff --git a/src/main/java/domain/Word.java b/src/main/java/domain/Word.java new file mode 100644 index 00000000..970a76b0 --- /dev/null +++ b/src/main/java/domain/Word.java @@ -0,0 +1,141 @@ +package domain; + +import java.time.LocalDate; +import java.time.Period; +import java.util.*; +import java.util.stream.Stream; + +public class Word { + private final static int MAX_LENGTH = 5; + private final String value; + private final boolean availableWord; + + public Word(String value) { + this.value = value; + this.availableWord = true; + } + + public Word(String value, boolean availableWord) { + this.value = value; + this.availableWord = availableWord; + } + + public static Word createAnswer(LocalDate currentDate, List availableWords) { + LocalDate fixedDate = LocalDate.of(2021, 6, 19); + int diffDay = Period.between(fixedDate, currentDate).getDays(); + int index = diffDay % availableWords.size(); + + return new Word(availableWords.get(index)); + } + + public static Word createInput(String value, List availableWords) { + boolean availableWord = isValidate(value, availableWords); + return new Word(value, availableWord); + } + + public MatchResult match(Word word) { + List correctedChar = new ArrayList<>(); + + List hintLetters = getHintLetters(word, correctedChar); + hintLetters.forEach(hintLetter -> hintLetter.changeCorrectToNotExist(correctedChar)); + + return new MatchResult(hintLetters); + } + + public boolean getAvailableWord() { + return availableWord; + } + + private List getHintLetters(Word word, List correctedChar) { + return Stream.iterate(0, i -> i + 1) + .limit(value.length()) + .map(i -> getHintLetter(word, i, correctedChar)) + .toList(); + } + + + private HintLetter getHintLetter(Word word, Integer i, List correctedChar) { + Hint hint = getHint(word, i); + + if (Hint.isCorrect(hint)) { + correctedChar.add(word.getChar(i)); + } + + return new HintLetter(word.getChar(i), hint); + } + + + private Character getChar(int i) { + return value.charAt(i); + } + + private Hint getHint(Word word, int index) { + char inputChar = word.getChar(index); + + if (isCorrect(index, inputChar)) { + return Hint.CORRECT; + } + + if (exists(inputChar)) { + return Hint.EXIST; + } + return Hint.NOT_EXIST; + } + + private boolean exists(char inputChar) { + return value.indexOf(inputChar) != -1; + } + + private boolean isCorrect(int index, char inputChar) { + return value.charAt(index) == inputChar; + } + + private static boolean isValidate(String input, List availableWords) { + if(isWrongLength(input)) { + return false; + } + + if(notOnlyEnglish(input)) { + return false; + } + + return !isNotContain(input, availableWords); + } + + public static boolean notOnlyEnglish(String input) { + if (!input.matches("^[a-zA-Z]+$")) { + System.out.println("์˜๋‹จ์–ด๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”. [" + input + "]"); + return true; + } + return false; + } + + public static boolean isWrongLength(String input) { + if (input.length() != MAX_LENGTH) { + System.out.println(MAX_LENGTH + "์ž๋ฆฌ์˜ ๋‹จ์–ด๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."); + return true; + } + return false; + } + + public static boolean isNotContain(String input, List availableWords) { + if (!availableWords.contains(input)) { + System.out.println("์ž…๋ ฅ ๋ถˆ๊ฐ€๋Šฅํ•œ ๋‹จ์–ด์ž…๋‹ˆ๋‹ค."); + return true; + } + return false; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Word word)) return false; + return getAvailableWord() == word.getAvailableWord() && Objects.equals(value, word.value); + } + + @Override + public int hashCode() { + return Objects.hash(value, getAvailableWord()); + } +} diff --git a/src/main/java/infra/WordLoader.java b/src/main/java/infra/WordLoader.java new file mode 100644 index 00000000..1fdf55d6 --- /dev/null +++ b/src/main/java/infra/WordLoader.java @@ -0,0 +1,19 @@ +package infra; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class WordLoader { + protected WordLoader() { + } + + public static List read(String filePath) { + try { + return Files.readAllLines(Paths.get(filePath)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/ui/GuideTextView.java b/src/main/java/ui/GuideTextView.java new file mode 100644 index 00000000..3c6ef5a2 --- /dev/null +++ b/src/main/java/ui/GuideTextView.java @@ -0,0 +1,8 @@ +package ui; + +public class GuideTextView { + public void render() { + System.out.println("WORDLE์„ 6๋ฒˆ ๋งŒ์— ๋งž์ถฐ ๋ณด์„ธ์š”."); + System.out.println("์‹œ๋„์˜ ๊ฒฐ๊ณผ๋Š” ํƒ€์ผ์˜ ์ƒ‰ ๋ณ€ํ™”๋กœ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค."); + } +} diff --git a/src/main/java/ui/HintView.java b/src/main/java/ui/HintView.java new file mode 100644 index 00000000..23f492ee --- /dev/null +++ b/src/main/java/ui/HintView.java @@ -0,0 +1,15 @@ +package ui; + +import domain.MatchResult; +import domain.MatchResults; + +public class HintView { + public void render(MatchResults matchResults) { + matchResults.forEach(HintView::drawTiles); + } + + private static void drawTiles(MatchResult matchResultEachRound) { + System.out.print(matchResultEachRound.getHintTiles()); + System.out.println(); + } +} diff --git a/src/main/java/ui/InputView.java b/src/main/java/ui/InputView.java new file mode 100644 index 00000000..f5e8e011 --- /dev/null +++ b/src/main/java/ui/InputView.java @@ -0,0 +1,13 @@ +package ui; + +import java.util.Scanner; + +public class InputView { + private final Scanner scanner = new Scanner(System.in); + public String input() { + System.out.println("์ •๋‹ต์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”."); + + return scanner.nextLine(); + } + +} diff --git a/src/main/java/ui/RoundView.java b/src/main/java/ui/RoundView.java new file mode 100644 index 00000000..936e8e12 --- /dev/null +++ b/src/main/java/ui/RoundView.java @@ -0,0 +1,11 @@ +package ui; + +public class RoundView { + public void render(int current, int max) { + System.out.printf("%d/%d%n", current, max); + } + + public void renderLoseGame() { + System.out.print("์‹œ๋„ ๊ฐ€๋Šฅ ํšŸ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."); + } +} diff --git a/src/test/java/domain/AnswerTest.java b/src/test/java/domain/AnswerTest.java new file mode 100644 index 00000000..01ebaa71 --- /dev/null +++ b/src/test/java/domain/AnswerTest.java @@ -0,0 +1,103 @@ +package domain; + +import infra.WordLoader; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; + +class AnswerTest { + private final List words = getWordList(); + Word answer = Word.createAnswer(LocalDate.of(2021, 6, 20), words); + + + @ParameterizedTest + @ValueSource(strings = {"serve"}) + @DisplayName("์ •๋‹ต์€ ๋งค์ผ ๋ฐ”๋€Œ๋ฉฐ ((ํ˜„์žฌ ๋‚ ์งœ - 2021๋…„ 6์›” 19์ผ) % ๋ฐฐ์—ด์˜ ํฌ๊ธฐ) ๋ฒˆ์งธ์˜ ๋‹จ์–ด์ด๋‹ค") + void answerSelectTest(String input) { + assertThat(answer).isEqualTo(new Word(input)); + } + + + @ParameterizedTest + @MethodSource("provideInputAnswer") + @DisplayName("์ž…๋ ฅ๋‹จ์–ด์™€ ์ •๋‹ต ๋น„๊ต") + void matchTest(String input, List hintLetters) { + Word inputWord = Word.createInput(input, words); + MatchResult matchResults = answer.match(inputWord); + + MatchResult expected = new MatchResult(hintLetters); + assertThat(matchResults).isEqualTo(expected); + } + + + @ParameterizedTest + @MethodSource("provideLocationAnswer") + @DisplayName("์ž…๋ ฅ๋‹จ์–ด์™€ ์ค‘๋ณต ๋‹จ์–ด ์œ„์น˜ ํ™•์ธ ํ…Œ์ŠคํŠธ") + void matchLocationTest(String input, List hintLetters) { + Word inputWord = Word.createInput(input, words); + MatchResult matchResults = answer.match(inputWord); + + MatchResult expected = new MatchResult(hintLetters); + assertThat(matchResults).isEqualTo(expected); + } + + + private static List getWordList() { + return WordLoader.read("src/test/resources/words.txt"); + } + + + public static Stream provideInputAnswer() { + return Stream.of( + new Object[]{"serve", List.of(new HintLetter('s', Hint.CORRECT), + new HintLetter('e', Hint.CORRECT), + new HintLetter('r', Hint.CORRECT), + new HintLetter('v', Hint.CORRECT), + new HintLetter('e', Hint.CORRECT))}, + new Object[]{"sssss", List.of(new HintLetter('s', Hint.CORRECT), + new HintLetter('s', Hint.NOT_EXIST), + new HintLetter('s', Hint.NOT_EXIST), + new HintLetter('s', Hint.NOT_EXIST), + new HintLetter('s', Hint.NOT_EXIST))}, + new Object[]{"eeeee", List.of(new HintLetter('e', Hint.NOT_EXIST), + new HintLetter('e', Hint.CORRECT), + new HintLetter('e', Hint.NOT_EXIST), + new HintLetter('e', Hint.NOT_EXIST), + new HintLetter('e', Hint.CORRECT))}, + new Object[]{"grade", List.of(new HintLetter('g', Hint.NOT_EXIST), + new HintLetter('r', Hint.EXIST), + new HintLetter('a', Hint.NOT_EXIST), + new HintLetter('d', Hint.NOT_EXIST), + new HintLetter('e', Hint.CORRECT))} + ); + } + + public static Stream provideLocationAnswer() { + return Stream.of( + new Object[]{"cigar", List.of(new HintLetter('c', Hint.NOT_EXIST), + new HintLetter('i', Hint.NOT_EXIST), + new HintLetter('g', Hint.NOT_EXIST), + new HintLetter('a', Hint.NOT_EXIST), + new HintLetter('r', Hint.EXIST))}, + new Object[]{"sissy", List.of(new HintLetter('s', Hint.CORRECT), + new HintLetter('i', Hint.NOT_EXIST), + new HintLetter('s', Hint.NOT_EXIST), + new HintLetter('s', Hint.NOT_EXIST), + new HintLetter('y', Hint.NOT_EXIST))}, + new Object[]{"naval", List.of(new HintLetter('n', Hint.NOT_EXIST), + new HintLetter('a', Hint.NOT_EXIST), + new HintLetter('v', Hint.EXIST), + new HintLetter('a', Hint.NOT_EXIST), + new HintLetter('l', Hint.NOT_EXIST))} + ); + } +} diff --git a/src/test/java/domain/InputWordTest.java b/src/test/java/domain/InputWordTest.java new file mode 100644 index 00000000..26de85e0 --- /dev/null +++ b/src/test/java/domain/InputWordTest.java @@ -0,0 +1,67 @@ +package domain; + +import infra.WordLoader; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +class InputWordTest { + private final List words = getWordList(); + + @ParameterizedTest + @DisplayName("์ž…๋ ฅ๋‹จ์–ด ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์„ฑ๊ณต ํ…Œ์ŠคํŠธ") + @MethodSource("provideContainedInputWords") + void validateSuccessInputWord(String input) { + assertTrue(words.contains(input)); + } + + @ParameterizedTest + @DisplayName("์ž…๋ ฅ๋‹จ์–ด ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์‹คํŒจ ํ…Œ์ŠคํŠธ") + @ValueSource(strings = {"banana", "hello", "test", "world"}) + void validateFailInputWord(String input) { + Word word = Word.createInput(input, words); + assertFalse(word.getAvailableWord()); + } + + @ParameterizedTest + @ValueSource(strings = {"people"}) + @DisplayName("์ž…๋ ฅ๋‹จ์–ด ๊ธ€์ž์ˆ˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์‹คํŒจ ํ…Œ์ŠคํŠธ") + void validateInputWordLength(String input) { + assertTrue(Word.isWrongLength(input)); + } + + @ParameterizedTest + @DisplayName("์ž…๋ ฅ๋‹จ์–ด ์˜๋‹จ์–ด ์œ ํšจ์„ฑ ๊ฒ€์ฆ ์‹คํŒจ ํ…Œ์ŠคํŠธ") + @MethodSource("provideWordsWithLength") + void validateInputWordOnlyEnglish(String input, boolean isRightWord) { + if (!isRightWord) { + Word word = Word.createInput(input, words); + assertFalse(word.getAvailableWord()); + } else { + assertFalse(Word.notOnlyEnglish(input)); + } + } + + private static List getWordList() { + return WordLoader.read("src/test/resources/words.txt"); + } + private static Stream provideContainedInputWords() { + return Stream.of("serve", "sssss", "eeeee", "naval"); + } + + public static Stream provideWordsWithLength() { + return Stream.of( + new Object[]{"์•ˆ๋…•ํ•˜์„ธ์š”", false}, + new Object[]{"12345", false}, + new Object[]{"serve", true} + ); + } +} diff --git a/src/test/java/infra/WordLoaderTest.java b/src/test/java/infra/WordLoaderTest.java new file mode 100644 index 00000000..7705c7f9 --- /dev/null +++ b/src/test/java/infra/WordLoaderTest.java @@ -0,0 +1,17 @@ +package infra; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class WordLoaderTest { + @Test + @DisplayName("๋‹จ์–ด๋ชฉ๋กํŒŒ์ผ ์ฝ๊ธฐ") + void loadWordsFromFile(){ + List words = WordLoader.read("src/test/resources/words.txt"); + assertThat(words).hasSize(18); + } +} diff --git a/src/test/resources/words.txt b/src/test/resources/words.txt new file mode 100644 index 00000000..eecd8ac1 --- /dev/null +++ b/src/test/resources/words.txt @@ -0,0 +1,18 @@ +cigar +serve +sissy +humph +awake +blush +focal +evade +naval +serve +heath +grade +model +rebut +sssss +eeeee +people +์•ˆ๋…•ํ•˜์„ธ์š”