From f41c990435a14e70052827c0f7c990bf92087e1c Mon Sep 17 00:00:00 2001 From: Jongmin Yoon Date: Sat, 8 Jun 2024 11:48:14 +0900 Subject: [PATCH 01/60] =?UTF-8?q?test:=20=ED=86=B5=ED=95=A9=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20-=20=EC=84=B1=EA=B3=B5=EC=BC=80=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/Application.java | 7 +++ src/test/java/wordle/ApplicationTest.java | 38 ++++++++++++++ .../java/wordle/ConsoleIntegrationTest.java | 51 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/main/java/wordle/Application.java create mode 100644 src/test/java/wordle/ApplicationTest.java create mode 100644 src/test/java/wordle/ConsoleIntegrationTest.java diff --git a/src/main/java/wordle/Application.java b/src/main/java/wordle/Application.java new file mode 100644 index 00000000..13b664cb --- /dev/null +++ b/src/main/java/wordle/Application.java @@ -0,0 +1,7 @@ +package wordle; + +public class Application { + public static void main(String[] args) { + // TODO: 프로그램 구현 + } +} diff --git a/src/test/java/wordle/ApplicationTest.java b/src/test/java/wordle/ApplicationTest.java new file mode 100644 index 00000000..0f811401 --- /dev/null +++ b/src/test/java/wordle/ApplicationTest.java @@ -0,0 +1,38 @@ +package wordle; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ApplicationTest extends ConsoleIntegrationTest { + + @Test + void 게임_정상_진행_테스트() { + run("hello", "label", "spell", "spill"); + assertThat(output()).contains( + """ + ⬜⬜🟨🟩⬜ + """, + """ + ⬜⬜🟨🟩⬜ + 🟨⬜⬜⬜🟩 + """, + """ + ⬜⬜🟨🟩⬜ + 🟨⬜⬜⬜🟩 + 🟩🟩⬜🟩🟩 + """, + """ + ⬜⬜🟨🟩⬜ + 🟨⬜⬜⬜🟩 + 🟩🟩⬜🟩🟩 + 🟩🟩🟩🟩🟩 + """ + ); + } + + @Override + public void runMain() { + Application.main(new String[]{}); + } +} diff --git a/src/test/java/wordle/ConsoleIntegrationTest.java b/src/test/java/wordle/ConsoleIntegrationTest.java new file mode 100644 index 00000000..bbe78caa --- /dev/null +++ b/src/test/java/wordle/ConsoleIntegrationTest.java @@ -0,0 +1,51 @@ +package wordle; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.NoSuchElementException; + +public abstract class ConsoleIntegrationTest { + private PrintStream standardOut; + private OutputStream captor; + + @BeforeEach + protected final void init() { + standardOut = System.out; + captor = new ByteArrayOutputStream(); + System.setOut(new PrintStream(captor)); + } + + @AfterEach + protected final void printOutput() { + System.setOut(standardOut); + System.out.println(output()); + } + + protected final String output() { + return captor.toString().trim(); + } + + protected final void run(final String... args) { + command(args); + runMain(); + } + + protected final void runException(final String... args) { + try { + run(args); + } catch (final NoSuchElementException ignore) { + } + } + + private void command(final String... args) { + final byte[] buf = String.join("\n", args).getBytes(); + System.setIn(new ByteArrayInputStream(buf)); + } + + protected abstract void runMain(); +} From ecce4622f2807fbefbf0314a8ff0de50d7288a7e Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 8 Jun 2024 14:57:01 +0900 Subject: [PATCH 02/60] =?UTF-8?q?docs(README):=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=EC=A7=84=ED=96=89=EC=88=9C=EC=84=9C,=20=EC=9A=A9=EC=96=B4?= =?UTF-8?q?=EC=82=AC=EC=A0=84=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/README.md diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..85436a2a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,51 @@ +# 미션 - 워들 + +## 게임 진행 순서 + +- 단어장(`words.txt`)에 있는 단어를 읽어들인다. +- 읽어들인 단어들에서 정답인 단어를 정한다. + - 정답은 매일 바뀌며 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) 번째의 단어이다. +- 문자 5개를 입력한다. + - 5개가 아닌 경우 재입력을 받는다. + - 단어장에 존재하지 않는 단어인 경우 재입력을 받는다. + - 알파벳이 아닌 경우 재입력을 받는다. +- 입력받은 문자와 정답을 비교한다. +- 비교 결과는 타일이 초록색/노란색/회색 중 하나로 바뀌면서 표현된다. + - 맞는 글자는 초록색, 위치가 틀리면 노란색, 없으면 회색 + - 같은 문자가 2개 입력되었을 때, 해당 문자가 정답에 하나만 존재하지만 위치가 틀린 경우 첫번 째 문자만 노란색으로 표시된다. + - 정답: lurid, 입력: hello, 결과: ⬜⬜🟨⬜⬜ +- 6번 안에 맞추면 게임을 종료한다. +- 6번 안에 맞추지 못하면 그래도 종료한다. + +## 용어 사전 + +| 한글명 | 영문명 | 설명 | +|--------|----------------|-----------------------------------------------| +| 워들 | Wordle | 5글자 영어 단어 맞추기 게임 | +| 단어장 | Word Book | 이 게임에서 사용될 수 있는 단어 모음 | +| 입력 단어 | Input Word | 플레이어가 입력하는 5글자 단어 | +| 정답 단어 | Answer Word | 오늘 게임의 정답인 5글자 단어 | +| 글자 | Letter | 단어를 구성하는 알파벳 | +| 위치 | Position | 단어를 구성하는 글자의 위치 | +| 플레이어 | Player | 게임에 참여하는 사용자 | +| 결과 | Result | 입력단어와 정답단어를 비교해서 표현되는 타일모음 | +| 비교 | Compare | 입력단어와 정답단어의 글자와 위치를 비교하는 행위 | +| 초록색 타일 | Green Tile | 글자와 위치가 동일한 경우 표현되는 타일 | +| 노란색 타일 | Yellow Tile | 글자는 포함되지만 위치가 다른 경우 표현되는 타일 | +| 회색 타일 | Gray Tile | 글자와 위치가 모두 다른 경우 표현되는 타일 | +| 라운드 | Round | 플레이어가 단어를 입력하는 횟수(6회) | +| 결과모음 | Results | 라운드가 진행될 때 마다 누적된 결과모음 | +| 기준일 | Base Date | 오늘의 정답 단어를 계산하는 기준일(2021년 6월 19일) | +| 정답 공식 | Answer Formula | 오늘의 정답 단어를 계산하는 공식 `(현재 날짜 - 기준일) % 단어장의 단어 수` | +| 시작 | Start | 플레이어가 워들을 시작하는 행위 | +| 종료 | End | 워들이 종료되는 행위(라운드가 전부 끝났거나, 그 전에 정답을 맞추면 종료된다) | + + +## 🚀 세부 요구 사항 +- 6x5 격자를 통해서 5글자 단어를 6번 만에 추측한다. +- 플레이어가 답안을 제출하면 프로그램이 정답과 제출된 단어의 각 알파벳 종류와 위치를 비교해 판별한다. +- 판별 결과는 흰색의 타일이 세 가지 색(초록색/노란색/회색) 중 하나로 바뀌면서 표현된다. + - 맞는 글자는 초록색, 위치가 틀리면 노란색, 없으면 회색 + - 두 개의 동일한 문자를 입력하고 그중 하나가 회색으로 표시되면 해당 문자 중 하나만 최종 단어에 나타난다. +- 정답과 답안은 `words.txt`에 존재하는 단어여야 한다. +- 정답은 매일 바뀌며 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) 번째의 단어이다. \ No newline at end of file From 68be1917c6aebc6de6e11e91a3e0a89304a9af63 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 8 Jun 2024 17:31:06 +0900 Subject: [PATCH 03/60] =?UTF-8?q?docs(README):=20=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=EB=A7=81(=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=8B=A4=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=EA=B7=B8=EB=9E=A8)=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 85436a2a..e1460310 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,6 +40,60 @@ | 시작 | Start | 플레이어가 워들을 시작하는 행위 | | 종료 | End | 워들이 종료되는 행위(라운드가 전부 끝났거나, 그 전에 정답을 맞추면 종료된다) | +## 모델링 +### 클래스 다이어그램 +```mermaid +--- +title: Wordle +--- +classDiagram + class Word { + -List letters + +compare(Word word) Results + -compare(Letter letter) Result + } + class Letter{ + -char alphabet + -Position position + +equals(Letter letter) boolean + +isSameAlphabetDifferentPosition(Letter letter) boolean + } + class Results { + -Result[] results + +add(Result result) void + +isCheckedPosition(Position position) boolean + } + class Result { + -Tile tile + -Position poistion + } + class IWordComparable { + +compare(Word word) Results + } + class ETile { + -TileType type + } + class AnswerFormula{ + -Date baseDate + +calculate() + } + class Wordle { + -WordBook wordBook + -Results results + -Round round + +start() + } + class WordBook { + -List wordBook + +pick(AnswerFormula formula) Word + +exist(Word inputWord) boolean + } + class Round { + -final int ROUND = 6; + -int curruntRound; + +isEnd() boolean + } +``` ## 🚀 세부 요구 사항 - 6x5 격자를 통해서 5글자 단어를 6번 만에 추측한다. @@ -48,4 +102,4 @@ - 맞는 글자는 초록색, 위치가 틀리면 노란색, 없으면 회색 - 두 개의 동일한 문자를 입력하고 그중 하나가 회색으로 표시되면 해당 문자 중 하나만 최종 단어에 나타난다. - 정답과 답안은 `words.txt`에 존재하는 단어여야 한다. -- 정답은 매일 바뀌며 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) 번째의 단어이다. \ No newline at end of file +- 정답은 매일 바뀌며 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) 번째의 단어이다. From 9664220663706892c4978f48ffe851a053430627 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 8 Jun 2024 17:44:22 +0900 Subject: [PATCH 04/60] =?UTF-8?q?feat(Position):=20Position=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 위치에 대한 책임을 가진 클래스 --- src/main/java/wordle/domain/Position.java | 29 +++++++++++++++++++ src/test/java/wordle/domain/PositionTest.java | 26 +++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/main/java/wordle/domain/Position.java create mode 100644 src/test/java/wordle/domain/PositionTest.java diff --git a/src/main/java/wordle/domain/Position.java b/src/main/java/wordle/domain/Position.java new file mode 100644 index 00000000..4218ce1d --- /dev/null +++ b/src/main/java/wordle/domain/Position.java @@ -0,0 +1,29 @@ +package wordle.domain; + +import java.util.Objects; + +public class Position { + + private final int position; + + public Position(int position) { + this.position = position; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Position position1 = (Position) o; + return position == position1.position; + } + + @Override + public int hashCode() { + return Objects.hash(position); + } +} diff --git a/src/test/java/wordle/domain/PositionTest.java b/src/test/java/wordle/domain/PositionTest.java new file mode 100644 index 00000000..54275182 --- /dev/null +++ b/src/test/java/wordle/domain/PositionTest.java @@ -0,0 +1,26 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +public class PositionTest { + + @Test + void Position이_같으면_동등한_객체이다(){ + Position position = createPosition(0); + + assertThat(position).isEqualTo(createPosition(0)); + } + + @Test + void Position이_다르면_동등하지않은_객체이다(){ + Position position = createPosition(0); + + assertThat(position).isNotEqualTo(createPosition(1)); + } + + private static Position createPosition(int position1) { + return new Position(position1); + } +} From d225a842800715bdeedf3226c772f71635f78bb4 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 8 Jun 2024 17:59:05 +0900 Subject: [PATCH 05/60] =?UTF-8?q?feat(Letter):=20Letter=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 알파벳과 위치를 가진 클래스 --- src/main/java/wordle/domain/Letter.java | 38 ++++++++++++++++++++ src/main/java/wordle/domain/Position.java | 4 +++ src/test/java/wordle/domain/LetterTest.java | 40 +++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 src/main/java/wordle/domain/Letter.java create mode 100644 src/test/java/wordle/domain/LetterTest.java diff --git a/src/main/java/wordle/domain/Letter.java b/src/main/java/wordle/domain/Letter.java new file mode 100644 index 00000000..c9161443 --- /dev/null +++ b/src/main/java/wordle/domain/Letter.java @@ -0,0 +1,38 @@ +package wordle.domain; + +import java.util.Objects; + +public class Letter { + + private char alphabet; + private Position position; + + public Letter(char alphabet, int position) { + this.alphabet = alphabet; + this.position = new Position(position); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Letter letter = (Letter) o; + return alphabet == letter.alphabet && Objects.equals(position, letter.position); + } + + @Override + public int hashCode() { + return Objects.hash(alphabet, position); + } + + public boolean isSameAlphabetDifferentPosition(Letter letter) { + if (letter.alphabet != this.alphabet) { + return false; + } + return letter.position.notEquals(this.position); + } +} diff --git a/src/main/java/wordle/domain/Position.java b/src/main/java/wordle/domain/Position.java index 4218ce1d..8966746b 100644 --- a/src/main/java/wordle/domain/Position.java +++ b/src/main/java/wordle/domain/Position.java @@ -26,4 +26,8 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(position); } + + public boolean notEquals(Position position) { + return !equals(position); + } } diff --git a/src/test/java/wordle/domain/LetterTest.java b/src/test/java/wordle/domain/LetterTest.java new file mode 100644 index 00000000..9ab15847 --- /dev/null +++ b/src/test/java/wordle/domain/LetterTest.java @@ -0,0 +1,40 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +public class LetterTest { + + @Test + void Letter를_생성한다() { + assertDoesNotThrow(() -> new Letter('a', 0)); + } + @Test + void 알파벳과_위치가_같으면_동등한_객체이다() { + Letter letter = new Letter('a', 0); + + assertThat(letter).isEqualTo(new Letter('a', 0)); + } + @Test + void 알파벳과이_다르면_동등하지_않은_객체이다() { + Letter letter = new Letter('a', 0); + + assertThat(letter).isNotEqualTo(new Letter('b', 0)); + } + + @Test + void 위치가_다르면_동등하지_않은_객체이다() { + Letter letter = new Letter('a', 0); + + assertThat(letter).isNotEqualTo(new Letter('a', 1)); + } + + @Test + void 알파벳은_같지만_포지션이_다른경우를_확인할_수_있다() { + Letter letter = new Letter('a', 0); + + assertThat(letter.isSameAlphabetDifferentPosition(new Letter('a', 1))).isTrue(); + } +} From b8ece65c3a2557daf3e539d559b8b47594400640 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 8 Jun 2024 18:10:06 +0900 Subject: [PATCH 06/60] =?UTF-8?q?feat(Word):=20Word=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - List 를 가지는 클래스 --- .../exception/WordInputNotValidException.java | 5 ++++ src/test/java/wordle/domain/Word.java | 23 +++++++++++++++++ src/test/java/wordle/domain/WordTest.java | 25 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 src/main/java/wordle/exception/WordInputNotValidException.java create mode 100644 src/test/java/wordle/domain/Word.java create mode 100644 src/test/java/wordle/domain/WordTest.java diff --git a/src/main/java/wordle/exception/WordInputNotValidException.java b/src/main/java/wordle/exception/WordInputNotValidException.java new file mode 100644 index 00000000..0a064d50 --- /dev/null +++ b/src/main/java/wordle/exception/WordInputNotValidException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class WordInputNotValidException extends IllegalArgumentException { + +} diff --git a/src/test/java/wordle/domain/Word.java b/src/test/java/wordle/domain/Word.java new file mode 100644 index 00000000..1e36ccc7 --- /dev/null +++ b/src/test/java/wordle/domain/Word.java @@ -0,0 +1,23 @@ +package wordle.domain; + +import java.util.ArrayList; +import java.util.List; +import wordle.exception.WordInputNotValidException; + +public class Word { + + public static final int WORD_LENGTH = 5; + private List letters; + + public Word(String input) { + if (input.length() != WORD_LENGTH) { + throw new WordInputNotValidException(); + } + + this.letters = new ArrayList<>(); + for (int i = 0; i < input.length(); i++) { + Letter letter = new Letter(input.charAt(i), i); + this.letters.add(letter); + } + } +} diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java new file mode 100644 index 00000000..a768fa25 --- /dev/null +++ b/src/test/java/wordle/domain/WordTest.java @@ -0,0 +1,25 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import wordle.exception.WordInputNotValidException; + +public class WordTest { + + @Test + void Word를_생성한다() { + assertDoesNotThrow(() -> new Word("apple")); + } + + @ParameterizedTest + @ValueSource(strings = {"test", "testss"}) + void Word를_생성할_때_다섯글자가_아니면_실패한다(String input) { + assertThatThrownBy(() -> new Word(input)) + .isInstanceOf(WordInputNotValidException.class); + } + +} From 76fdedf01d172f6907e27da08e579895ad7ac4c6 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 8 Jun 2024 18:17:42 +0900 Subject: [PATCH 07/60] =?UTF-8?q?feat(Result):=20Result=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Tile, Position 을 가지는 클래스 --- src/main/java/wordle/domain/Result.java | 11 +++++++++++ src/main/java/wordle/domain/Tile.java | 5 +++++ src/test/java/wordle/domain/ResultTest.java | 12 ++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 src/main/java/wordle/domain/Result.java create mode 100644 src/main/java/wordle/domain/Tile.java create mode 100644 src/test/java/wordle/domain/ResultTest.java diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java new file mode 100644 index 00000000..f00989bc --- /dev/null +++ b/src/main/java/wordle/domain/Result.java @@ -0,0 +1,11 @@ +package wordle.domain; + +public class Result { + private final Tile tile; + private final Position position; + + public Result(Tile tile, int position) { + this.tile = tile; + this.position = new Position(position); + } +} diff --git a/src/main/java/wordle/domain/Tile.java b/src/main/java/wordle/domain/Tile.java new file mode 100644 index 00000000..5f0c14f8 --- /dev/null +++ b/src/main/java/wordle/domain/Tile.java @@ -0,0 +1,5 @@ +package wordle.domain; + +public enum Tile { + GREEN, YELLOW, GRAY +} diff --git a/src/test/java/wordle/domain/ResultTest.java b/src/test/java/wordle/domain/ResultTest.java new file mode 100644 index 00000000..9433a0c0 --- /dev/null +++ b/src/test/java/wordle/domain/ResultTest.java @@ -0,0 +1,12 @@ +package wordle.domain; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +public class ResultTest { + @Test + void Result_생성_테스트() { + assertDoesNotThrow(()->new Result(Tile.GREEN, 0)); + } +} From d97c0c2f21368960322c522f1e0e28d040d61f9f Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 11:01:28 +0900 Subject: [PATCH 08/60] =?UTF-8?q?refactor(Letter):=20isSameAlphabetDiffere?= =?UTF-8?q?ntPosition=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - isSameAlphabet로 간결하게 변경 - 해당 메서드가 너무 많은 컨텍스트를 알고있음 --- src/main/java/wordle/domain/Letter.java | 7 ++----- src/test/java/wordle/domain/LetterTest.java | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/wordle/domain/Letter.java b/src/main/java/wordle/domain/Letter.java index c9161443..02d37b6e 100644 --- a/src/main/java/wordle/domain/Letter.java +++ b/src/main/java/wordle/domain/Letter.java @@ -29,10 +29,7 @@ public int hashCode() { return Objects.hash(alphabet, position); } - public boolean isSameAlphabetDifferentPosition(Letter letter) { - if (letter.alphabet != this.alphabet) { - return false; - } - return letter.position.notEquals(this.position); + public boolean isSameAlphabet(Letter letter) { + return letter.alphabet == this.alphabet; } } diff --git a/src/test/java/wordle/domain/LetterTest.java b/src/test/java/wordle/domain/LetterTest.java index 9ab15847..12bc4130 100644 --- a/src/test/java/wordle/domain/LetterTest.java +++ b/src/test/java/wordle/domain/LetterTest.java @@ -32,9 +32,9 @@ public class LetterTest { } @Test - void 알파벳은_같지만_포지션이_다른경우를_확인할_수_있다() { + void 알파벳은_같은지_확인할_수_있다() { Letter letter = new Letter('a', 0); - assertThat(letter.isSameAlphabetDifferentPosition(new Letter('a', 1))).isTrue(); + assertThat(letter.isSameAlphabet(new Letter('a', 1))).isTrue(); } } From 846ec026a3126fb63eca82e4d299e18f0b0c0360 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 11:18:48 +0900 Subject: [PATCH 09/60] =?UTF-8?q?fix(Result):=20equals=20hashCode=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Result.java | 19 +++++++++++++++++++ src/test/java/wordle/domain/ResultTest.java | 8 ++++++++ 2 files changed, 27 insertions(+) diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java index f00989bc..38fd6f05 100644 --- a/src/main/java/wordle/domain/Result.java +++ b/src/main/java/wordle/domain/Result.java @@ -1,5 +1,7 @@ package wordle.domain; +import java.util.Objects; + public class Result { private final Tile tile; private final Position position; @@ -8,4 +10,21 @@ public Result(Tile tile, int position) { this.tile = tile; this.position = new Position(position); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Result result = (Result) o; + return tile == result.tile && Objects.equals(position, result.position); + } + + @Override + public int hashCode() { + return Objects.hash(tile, position); + } } diff --git a/src/test/java/wordle/domain/ResultTest.java b/src/test/java/wordle/domain/ResultTest.java index 9433a0c0..5553b5cb 100644 --- a/src/test/java/wordle/domain/ResultTest.java +++ b/src/test/java/wordle/domain/ResultTest.java @@ -1,5 +1,6 @@ package wordle.domain; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import org.junit.jupiter.api.Test; @@ -9,4 +10,11 @@ public class ResultTest { void Result_생성_테스트() { assertDoesNotThrow(()->new Result(Tile.GREEN, 0)); } + + @Test + void 타일과_위치가_같으면_동등한_객체이다() { + Result result = new Result(Tile.GREEN, 0); + + assertThat(result).isEqualTo(new Result(Tile.GREEN, 0)); + } } From 7fdb063e35c297b223806744216bc2dc9d549e91 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 11:32:34 +0900 Subject: [PATCH 10/60] =?UTF-8?q?feat(Result):=20Results=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Result 일급컬렉션 클래스 --- src/main/java/wordle/domain/Results.java | 18 +++++++++++ src/test/java/wordle/domain/ResultsTest.java | 34 ++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 src/main/java/wordle/domain/Results.java create mode 100644 src/test/java/wordle/domain/ResultsTest.java diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java new file mode 100644 index 00000000..18de2428 --- /dev/null +++ b/src/main/java/wordle/domain/Results.java @@ -0,0 +1,18 @@ +package wordle.domain; + +import java.util.Arrays; +import java.util.Iterator; + +public class Results implements Iterable { + + private final Result[] results; + + public Results(Result[] results) { + this.results = results; + } + + @Override + public Iterator iterator() { + return Arrays.stream(results).iterator(); + } +} diff --git a/src/test/java/wordle/domain/ResultsTest.java b/src/test/java/wordle/domain/ResultsTest.java new file mode 100644 index 00000000..f1de1b35 --- /dev/null +++ b/src/test/java/wordle/domain/ResultsTest.java @@ -0,0 +1,34 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import org.junit.jupiter.api.Test; + +class ResultsTest { + + @Test + void Results_생성테스트(){ + Result[] results = createGreenResults(5); + + assertThat(new Results(results)).containsExactly( + createGreenResult(0), + createGreenResult(1), + createGreenResult(2), + createGreenResult(3), + createGreenResult(4)); + } + + private static Result[] createGreenResults(int count) { + return IntStream.range(0, count) + .mapToObj(ResultsTest::createGreenResult) + .toArray(Result[]::new); + } + + + private static Result createGreenResult(int position) { + return new Result(Tile.GREEN, position); + } + +} \ No newline at end of file From d03c4b44a100d2946072395304de44a0caf5f534 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 11:36:06 +0900 Subject: [PATCH 11/60] =?UTF-8?q?test(Result):=20Result=20Fixture=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/wordle/domain/ResultsTest.java | 27 +++++-------------- .../java/wordle/fixture/ResultFixture.java | 18 +++++++++++++ 2 files changed, 25 insertions(+), 20 deletions(-) create mode 100644 src/test/java/wordle/fixture/ResultFixture.java diff --git a/src/test/java/wordle/domain/ResultsTest.java b/src/test/java/wordle/domain/ResultsTest.java index f1de1b35..9aa79c62 100644 --- a/src/test/java/wordle/domain/ResultsTest.java +++ b/src/test/java/wordle/domain/ResultsTest.java @@ -2,33 +2,20 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.stream.Collectors; -import java.util.stream.IntStream; import org.junit.jupiter.api.Test; +import wordle.fixture.ResultFixture; class ResultsTest { @Test void Results_생성테스트(){ - Result[] results = createGreenResults(5); + Result[] results = ResultFixture.createGreenResults(5); assertThat(new Results(results)).containsExactly( - createGreenResult(0), - createGreenResult(1), - createGreenResult(2), - createGreenResult(3), - createGreenResult(4)); + ResultFixture.createGreenResult(0), + ResultFixture.createGreenResult(1), + ResultFixture.createGreenResult(2), + ResultFixture.createGreenResult(3), + ResultFixture.createGreenResult(4)); } - - private static Result[] createGreenResults(int count) { - return IntStream.range(0, count) - .mapToObj(ResultsTest::createGreenResult) - .toArray(Result[]::new); - } - - - private static Result createGreenResult(int position) { - return new Result(Tile.GREEN, position); - } - } \ No newline at end of file diff --git a/src/test/java/wordle/fixture/ResultFixture.java b/src/test/java/wordle/fixture/ResultFixture.java new file mode 100644 index 00000000..d6dbe031 --- /dev/null +++ b/src/test/java/wordle/fixture/ResultFixture.java @@ -0,0 +1,18 @@ +package wordle.fixture; + +import java.util.stream.IntStream; +import wordle.domain.Result; +import wordle.domain.Tile; + +public class ResultFixture { + + public static Result[] createGreenResults(int count) { + return IntStream.range(0, count) + .mapToObj(ResultFixture::createGreenResult) + .toArray(Result[]::new); + } + + public static Result createGreenResult(int position) { + return new Result(Tile.GREEN, position); + } +} From 34c23331177b86a19b1ad42744ee7872687ed5c4 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 11:37:14 +0900 Subject: [PATCH 12/60] =?UTF-8?q?feat(Word):=20compare=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Letter.java | 4 ++ src/main/java/wordle/domain/Result.java | 6 ++- src/main/java/wordle/domain/Results.java | 1 + src/main/java/wordle/domain/Word.java | 61 +++++++++++++++++++++++ src/test/java/wordle/domain/Word.java | 23 --------- src/test/java/wordle/domain/WordTest.java | 16 ++++++ 6 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 src/main/java/wordle/domain/Word.java delete mode 100644 src/test/java/wordle/domain/Word.java diff --git a/src/main/java/wordle/domain/Letter.java b/src/main/java/wordle/domain/Letter.java index 02d37b6e..f799afdf 100644 --- a/src/main/java/wordle/domain/Letter.java +++ b/src/main/java/wordle/domain/Letter.java @@ -32,4 +32,8 @@ public int hashCode() { public boolean isSameAlphabet(Letter letter) { return letter.alphabet == this.alphabet; } + + public Position getPosition() { + return position; + } } diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java index 38fd6f05..26d2e3a8 100644 --- a/src/main/java/wordle/domain/Result.java +++ b/src/main/java/wordle/domain/Result.java @@ -7,8 +7,12 @@ public class Result { private final Position position; public Result(Tile tile, int position) { + this(tile, new Position(position)); + } + + public Result(Tile tile, Position position) { this.tile = tile; - this.position = new Position(position); + this.position = position; } @Override diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java index 18de2428..866a1510 100644 --- a/src/main/java/wordle/domain/Results.java +++ b/src/main/java/wordle/domain/Results.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.Iterator; +import java.util.stream.IntStream; public class Results implements Iterable { diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java new file mode 100644 index 00000000..b25df8a4 --- /dev/null +++ b/src/main/java/wordle/domain/Word.java @@ -0,0 +1,61 @@ +package wordle.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import wordle.exception.WordInputNotValidException; + +public class Word { + + public static final int WORD_LENGTH = 5; + private List letters; + + public Word(String input) { + if (input.length() != WORD_LENGTH) { + throw new WordInputNotValidException(); + } + + this.letters = new ArrayList<>(); + for (int i = 0; i < input.length(); i++) { + Letter letter = new Letter(input.charAt(i), i); + this.letters.add(letter); + } + } + + public Results compare(Word targetWord) { + Result[] results = new Result[WORD_LENGTH]; + for (int i = 0; i < WORD_LENGTH; i++) { + Letter letter = letters.get(i); + results[i] = targetWord.compare(letter); + } + return new Results(results); + } + + private Result compare(Letter targetLetter){ + for (int i = 0; i < this.letters.size(); i++) { + Letter letter = this.letters.get(i); + if(letter.equals(targetLetter)){ + return new Result(Tile.GREEN, targetLetter.getPosition()); + } + } + + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Word word = (Word) o; + return Objects.equals(letters, word.letters); + } + + @Override + public int hashCode() { + return Objects.hash(letters); + } +} diff --git a/src/test/java/wordle/domain/Word.java b/src/test/java/wordle/domain/Word.java deleted file mode 100644 index 1e36ccc7..00000000 --- a/src/test/java/wordle/domain/Word.java +++ /dev/null @@ -1,23 +0,0 @@ -package wordle.domain; - -import java.util.ArrayList; -import java.util.List; -import wordle.exception.WordInputNotValidException; - -public class Word { - - public static final int WORD_LENGTH = 5; - private List letters; - - public Word(String input) { - if (input.length() != WORD_LENGTH) { - throw new WordInputNotValidException(); - } - - this.letters = new ArrayList<>(); - for (int i = 0; i < input.length(); i++) { - Letter letter = new Letter(input.charAt(i), i); - this.letters.add(letter); - } - } -} diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java index a768fa25..e46795ad 100644 --- a/src/test/java/wordle/domain/WordTest.java +++ b/src/test/java/wordle/domain/WordTest.java @@ -1,5 +1,6 @@ package wordle.domain; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -7,6 +8,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import wordle.exception.WordInputNotValidException; +import wordle.fixture.ResultFixture; public class WordTest { @@ -22,4 +24,18 @@ public class WordTest { .isInstanceOf(WordInputNotValidException.class); } + @Test + void 같은_Word를_비교하면_초록_결과들을_반환한다(){ + Word baseWord = new Word("abcde"); + Word targetWord = new Word("abcde"); + + Results results = baseWord.compare(targetWord); + + assertThat(results).containsExactly( + ResultFixture.createGreenResult(0), + ResultFixture.createGreenResult(1), + ResultFixture.createGreenResult(2), + ResultFixture.createGreenResult(3), + ResultFixture.createGreenResult(4)); + } } From 60ca6a9ce08658812e137ffc7f0cae06f1b529d9 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 14:12:47 +0900 Subject: [PATCH 13/60] =?UTF-8?q?fix(Word):=20compare=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EC=97=90=20=EB=85=B8=EB=9E=91=ED=83=80=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Word.java | 7 +++++++ src/test/java/wordle/domain/WordTest.java | 14 ++++++++++++++ src/test/java/wordle/fixture/ResultFixture.java | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index b25df8a4..75af83f3 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -39,6 +39,13 @@ private Result compare(Letter targetLetter){ } } + for (int i = 0; i < this.letters.size(); i++) { + Letter letter = this.letters.get(i); + if(letter.isSameAlphabet(targetLetter)){ + return new Result(Tile.YELLOW, targetLetter.getPosition()); + } + } + return null; } diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java index e46795ad..eba1f584 100644 --- a/src/test/java/wordle/domain/WordTest.java +++ b/src/test/java/wordle/domain/WordTest.java @@ -38,4 +38,18 @@ public class WordTest { ResultFixture.createGreenResult(3), ResultFixture.createGreenResult(4)); } + @Test + void 글자는_같지만_위치가_전부_다른_Word를_비교하면_노란_결과들을_반환한다(){ + Word baseWord = new Word("abcde"); + Word targetWord = new Word("edbac"); + + Results results = baseWord.compare(targetWord); + + assertThat(results).containsExactly( + ResultFixture.createYellowResult(0), + ResultFixture.createYellowResult(1), + ResultFixture.createYellowResult(2), + ResultFixture.createYellowResult(3), + ResultFixture.createYellowResult(4)); + } } diff --git a/src/test/java/wordle/fixture/ResultFixture.java b/src/test/java/wordle/fixture/ResultFixture.java index d6dbe031..14897eae 100644 --- a/src/test/java/wordle/fixture/ResultFixture.java +++ b/src/test/java/wordle/fixture/ResultFixture.java @@ -15,4 +15,8 @@ public static Result[] createGreenResults(int count) { public static Result createGreenResult(int position) { return new Result(Tile.GREEN, position); } + + public static Result createYellowResult(int position) { + return new Result(Tile.YELLOW, position); + } } From e3a595d4ce2c77a885d38d34fff2656d1e01b372 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 14:19:08 +0900 Subject: [PATCH 14/60] =?UTF-8?q?test(Word):=20=EA=B8=80=EC=9E=90=EC=99=80?= =?UTF-8?q?=20=EC=9C=84=EC=B9=98=EA=B0=80=20=EC=9D=BC=EB=B6=80=EA=B0=80=20?= =?UTF-8?q?=EA=B0=99=EC=9D=80=20=EA=B2=BD=EC=9A=B0=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/wordle/domain/WordTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java index eba1f584..d9443150 100644 --- a/src/test/java/wordle/domain/WordTest.java +++ b/src/test/java/wordle/domain/WordTest.java @@ -38,6 +38,7 @@ public class WordTest { ResultFixture.createGreenResult(3), ResultFixture.createGreenResult(4)); } + @Test void 글자는_같지만_위치가_전부_다른_Word를_비교하면_노란_결과들을_반환한다(){ Word baseWord = new Word("abcde"); @@ -52,4 +53,19 @@ public class WordTest { ResultFixture.createYellowResult(3), ResultFixture.createYellowResult(4)); } + + @Test + void 글자와_위치가_일부가_같은_Word를_비교하면_초록_노란_결과들을_반환한다(){ + Word baseWord = new Word("abcde"); + Word targetWord = new Word("edcba"); + + Results results = baseWord.compare(targetWord); + + assertThat(results).containsExactly( + ResultFixture.createYellowResult(0), + ResultFixture.createYellowResult(1), + ResultFixture.createGreenResult(2), + ResultFixture.createYellowResult(3), + ResultFixture.createYellowResult(4)); + } } From 0a66559bd8bd64c16db8e4548af0e9d6aed61537 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 14:21:05 +0900 Subject: [PATCH 15/60] =?UTF-8?q?test(Word):=20=EA=B8=80=EC=9E=90=EC=99=80?= =?UTF-8?q?=20=EC=9C=84=EC=B9=98=EA=B0=80=20=EC=A0=84=EB=B6=80=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EA=B2=BD=EC=9A=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Word.java | 2 +- src/test/java/wordle/domain/WordTest.java | 15 +++++++++++++++ src/test/java/wordle/fixture/ResultFixture.java | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index 75af83f3..979aee48 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -46,7 +46,7 @@ private Result compare(Letter targetLetter){ } } - return null; + return new Result(Tile.GRAY, targetLetter.getPosition()); } @Override diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java index d9443150..b6800574 100644 --- a/src/test/java/wordle/domain/WordTest.java +++ b/src/test/java/wordle/domain/WordTest.java @@ -68,4 +68,19 @@ public class WordTest { ResultFixture.createYellowResult(3), ResultFixture.createYellowResult(4)); } + + @Test + void 글자와_위치가_전부_다른_Word를_비교하면_회색_결과들을_반환한다(){ + Word baseWord = new Word("abcde"); + Word targetWord = new Word("fghij"); + + Results results = baseWord.compare(targetWord); + + assertThat(results).containsExactly( + ResultFixture.createGrayResult(0), + ResultFixture.createGrayResult(1), + ResultFixture.createGrayResult(2), + ResultFixture.createGrayResult(3), + ResultFixture.createGrayResult(4)); + } } diff --git a/src/test/java/wordle/fixture/ResultFixture.java b/src/test/java/wordle/fixture/ResultFixture.java index 14897eae..7ad3985b 100644 --- a/src/test/java/wordle/fixture/ResultFixture.java +++ b/src/test/java/wordle/fixture/ResultFixture.java @@ -19,4 +19,8 @@ public static Result createGreenResult(int position) { public static Result createYellowResult(int position) { return new Result(Tile.YELLOW, position); } + + public static Result createGrayResult(int position) { + return new Result(Tile.GRAY, position); + } } From aa7292315c04bbe04067ca2b97166dcf34c07557 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 14:57:13 +0900 Subject: [PATCH 16/60] =?UTF-8?q?fix(Results):=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EB=B0=B0=EC=97=B4=EC=97=90=EC=84=9C=20List=20=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Results.java | 17 ++++++++++------- src/test/java/wordle/domain/ResultsTest.java | 4 ++-- src/test/java/wordle/fixture/ResultFixture.java | 9 ++++++--- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java index 866a1510..bce9397e 100644 --- a/src/main/java/wordle/domain/Results.java +++ b/src/main/java/wordle/domain/Results.java @@ -1,19 +1,22 @@ package wordle.domain; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Iterator; -import java.util.stream.IntStream; +import java.util.List; public class Results implements Iterable { - private final Result[] results; - - public Results(Result[] results) { - this.results = results; + private final List results; + public Results() { + this.results = new ArrayList<>(); } @Override public Iterator iterator() { - return Arrays.stream(results).iterator(); + return results.iterator(); + } + + public void add(Result result) { + results.add(result); } } diff --git a/src/test/java/wordle/domain/ResultsTest.java b/src/test/java/wordle/domain/ResultsTest.java index 9aa79c62..76392b81 100644 --- a/src/test/java/wordle/domain/ResultsTest.java +++ b/src/test/java/wordle/domain/ResultsTest.java @@ -9,9 +9,9 @@ class ResultsTest { @Test void Results_생성테스트(){ - Result[] results = ResultFixture.createGreenResults(5); + Results results = ResultFixture.createGreenResults(5); - assertThat(new Results(results)).containsExactly( + assertThat(results).containsExactly( ResultFixture.createGreenResult(0), ResultFixture.createGreenResult(1), ResultFixture.createGreenResult(2), diff --git a/src/test/java/wordle/fixture/ResultFixture.java b/src/test/java/wordle/fixture/ResultFixture.java index 7ad3985b..54f179f8 100644 --- a/src/test/java/wordle/fixture/ResultFixture.java +++ b/src/test/java/wordle/fixture/ResultFixture.java @@ -2,14 +2,17 @@ import java.util.stream.IntStream; import wordle.domain.Result; +import wordle.domain.Results; import wordle.domain.Tile; public class ResultFixture { - public static Result[] createGreenResults(int count) { - return IntStream.range(0, count) + public static Results createGreenResults(int count) { + Results results = new Results(); + IntStream.range(0, count) .mapToObj(ResultFixture::createGreenResult) - .toArray(Result[]::new); + .forEach(results::add); + return results; } public static Result createGreenResult(int position) { From 20cf46476f717d847543e9d49baf8f2dcbf2350c Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 16:00:08 +0900 Subject: [PATCH 17/60] =?UTF-8?q?refactor(Results):=20=ED=95=84=EB=93=9C?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=EC=B2=B4=20SortedSet=20=EC=9C=BC=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Position.java | 6 ++- src/main/java/wordle/domain/Result.java | 19 ++++++++- src/main/java/wordle/domain/Results.java | 19 +++++++-- src/main/java/wordle/domain/Word.java | 52 +++++++++++++++++------ 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/main/java/wordle/domain/Position.java b/src/main/java/wordle/domain/Position.java index 8966746b..b70c7c2b 100644 --- a/src/main/java/wordle/domain/Position.java +++ b/src/main/java/wordle/domain/Position.java @@ -2,7 +2,7 @@ import java.util.Objects; -public class Position { +public class Position implements Comparable { private final int position; @@ -30,4 +30,8 @@ public int hashCode() { public boolean notEquals(Position position) { return !equals(position); } + + public int compareTo(Position position) { + return Integer.compare(this.position, position.position); + } } diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java index 26d2e3a8..bffebbd0 100644 --- a/src/main/java/wordle/domain/Result.java +++ b/src/main/java/wordle/domain/Result.java @@ -2,7 +2,7 @@ import java.util.Objects; -public class Result { +public class Result implements Comparable { private final Tile tile; private final Position position; @@ -31,4 +31,21 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(tile, position); } + + @Override + public String toString() { + return "Result{" + + "tile=" + tile + + ", position=" + position + + '}'; + } + + public boolean isSamePosition(Position position) { + return this.position.equals(position); + } + + @Override + public int compareTo(Result o) { + return position.compareTo(o.position); + } } diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java index bce9397e..43d76c89 100644 --- a/src/main/java/wordle/domain/Results.java +++ b/src/main/java/wordle/domain/Results.java @@ -1,14 +1,15 @@ package wordle.domain; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; public class Results implements Iterable { - private final List results; + private final SortedSet results; + public Results() { - this.results = new ArrayList<>(); + this.results = new TreeSet<>(); } @Override @@ -19,4 +20,14 @@ public Iterator iterator() { public void add(Result result) { results.add(result); } + + public boolean isCheckedPosition(Position position) { + for (Result result : results) { + if (result.isSamePosition(position)) { + return true; + } + } + + return false; + } } diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index 979aee48..725f8e2e 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -1,11 +1,12 @@ package wordle.domain; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.Objects; import wordle.exception.WordInputNotValidException; -public class Word { +public class Word implements Iterable { public static final int WORD_LENGTH = 5; private List letters; @@ -22,31 +23,49 @@ public Word(String input) { } } - public Results compare(Word targetWord) { - Result[] results = new Result[WORD_LENGTH]; - for (int i = 0; i < WORD_LENGTH; i++) { - Letter letter = letters.get(i); - results[i] = targetWord.compare(letter); + public Results compare(Word inputWord) { + Results results = new Results(); + for (Letter letter : inputWord) { + Result green = findGreen(letter); + if (green != null) { + results.add(green); + } + } + + for (Letter letter : inputWord) { + if (results.isCheckedPosition(letter.getPosition())) { + continue; + } + + Result yellow = findYellow(letter); + if (yellow != null) { + results.add(yellow); + } else { + results.add(new Result(Tile.GRAY, letter.getPosition())); + } } - return new Results(results); + + return results; } - private Result compare(Letter targetLetter){ + private Result findYellow(Letter targetLetter) { for (int i = 0; i < this.letters.size(); i++) { Letter letter = this.letters.get(i); - if(letter.equals(targetLetter)){ - return new Result(Tile.GREEN, targetLetter.getPosition()); + if (letter.isSameAlphabet(targetLetter)) { + return new Result(Tile.YELLOW, targetLetter.getPosition()); } } + return null; + } + private Result findGreen(Letter targetLetter) { for (int i = 0; i < this.letters.size(); i++) { Letter letter = this.letters.get(i); - if(letter.isSameAlphabet(targetLetter)){ - return new Result(Tile.YELLOW, targetLetter.getPosition()); + if (letter.equals(targetLetter)) { + return new Result(Tile.GREEN, targetLetter.getPosition()); } } - - return new Result(Tile.GRAY, targetLetter.getPosition()); + return null; } @Override @@ -65,4 +84,9 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(letters); } + + @Override + public Iterator iterator() { + return this.letters.iterator(); + } } From 151e2ad25385434649b17f88bf7bdb35053baef0 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 9 Jun 2024 16:19:12 +0900 Subject: [PATCH 18/60] =?UTF-8?q?fix(Word):=20=EA=B0=99=EC=9D=80=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EA=B0=80=202=EA=B0=9C=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=90=98=EC=97=88=EC=9D=84=20=EB=95=8C,=20=ED=95=B4=EB=8B=B9?= =?UTF-8?q?=20=EB=AC=B8=EC=9E=90=EA=B0=80=20=EC=A0=95=EB=8B=B5=EC=97=90=20?= =?UTF-8?q?=ED=95=98=EB=82=98=EB=A7=8C=20=EC=A1=B4=EC=9E=AC=ED=95=98?= =?UTF-8?q?=EC=A7=80=EB=A7=8C=20=EC=9C=84=EC=B9=98=EA=B0=80=20=ED=8B=80?= =?UTF-8?q?=EB=A6=B0=20=EA=B2=BD=EC=9A=B0=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Word.java | 19 ++++++++------ src/test/java/wordle/domain/WordTest.java | 30 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index 725f8e2e..8da351a3 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -24,20 +24,18 @@ public Word(String input) { } public Results compare(Word inputWord) { + boolean[] visit = new boolean[WORD_LENGTH]; + Results results = new Results(); for (Letter letter : inputWord) { - Result green = findGreen(letter); + Result green = findGreen(letter, visit); if (green != null) { results.add(green); } } for (Letter letter : inputWord) { - if (results.isCheckedPosition(letter.getPosition())) { - continue; - } - - Result yellow = findYellow(letter); + Result yellow = findYellow(letter, visit); if (yellow != null) { results.add(yellow); } else { @@ -48,20 +46,25 @@ public Results compare(Word inputWord) { return results; } - private Result findYellow(Letter targetLetter) { + private Result findYellow(Letter targetLetter, boolean[] visit) { for (int i = 0; i < this.letters.size(); i++) { Letter letter = this.letters.get(i); + if(visit[i]){ + continue; + } if (letter.isSameAlphabet(targetLetter)) { + visit[i] = true; return new Result(Tile.YELLOW, targetLetter.getPosition()); } } return null; } - private Result findGreen(Letter targetLetter) { + private Result findGreen(Letter targetLetter, boolean[] visit) { for (int i = 0; i < this.letters.size(); i++) { Letter letter = this.letters.get(i); if (letter.equals(targetLetter)) { + visit[i] = true; return new Result(Tile.GREEN, targetLetter.getPosition()); } } diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java index b6800574..31b3f819 100644 --- a/src/test/java/wordle/domain/WordTest.java +++ b/src/test/java/wordle/domain/WordTest.java @@ -83,4 +83,34 @@ public class WordTest { ResultFixture.createGrayResult(3), ResultFixture.createGrayResult(4)); } + + @Test + void 글자와_위치가_전부_같은게_두개_위치만_다른게_한개_전부_다른게_두개인_Word를_비교하면_결과들을_반환한다(){ + Word answerWord = new Word("abcde"); // 정답 + Word inputWord = new Word("abejk"); // input + + Results results = answerWord.compare(inputWord); + + assertThat(results).containsExactly( + ResultFixture.createGreenResult(0), + ResultFixture.createGreenResult(1), + ResultFixture.createYellowResult(2), + ResultFixture.createGrayResult(3), + ResultFixture.createGrayResult(4)); + } + + @Test + void 같은_문자가_2개_입력되었을_때_해당_문자가_정답에_하나만_존재하지만_위치가_틀린_경우_첫번째_문자만_노란색으로_반환된다(){ + Word answerWord = new Word("lurid"); // 정답 + Word inputWord = new Word("hello"); // input + + Results results = answerWord.compare(inputWord); + + assertThat(results).containsExactly( + ResultFixture.createGrayResult(0), + ResultFixture.createGrayResult(1), + ResultFixture.createYellowResult(2), + ResultFixture.createGrayResult(3), + ResultFixture.createGrayResult(4)); + } } From e14a0851005b3cbd976594ad76e382db6c18197e Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 12 Jun 2024 21:41:06 +0900 Subject: [PATCH 19/60] =?UTF-8?q?test(Time):=20LocalDate=20=EB=AA=A8?= =?UTF-8?q?=ED=82=B9=20=EC=9C=A0=ED=8B=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + src/test/java/wordle/TimeTestSupporter.java | 20 +++++++++++++++++ src/test/java/wordle/study/TimeTest.java | 25 +++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/test/java/wordle/TimeTestSupporter.java create mode 100644 src/test/java/wordle/study/TimeTest.java diff --git a/build.gradle b/build.gradle index 0b3a9762..b12b2426 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ repositories { } dependencies { + testImplementation 'org.mockito:mockito-inline:3.12.0' testImplementation 'org.junit.jupiter:junit-jupiter:5.10.2' testImplementation 'org.assertj:assertj-core:3.25.3' } diff --git a/src/test/java/wordle/TimeTestSupporter.java b/src/test/java/wordle/TimeTestSupporter.java new file mode 100644 index 00000000..b191196e --- /dev/null +++ b/src/test/java/wordle/TimeTestSupporter.java @@ -0,0 +1,20 @@ +package wordle; + +import static org.mockito.Mockito.mockStatic; + +import java.time.LocalDate; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +public class TimeTestSupporter { + + public static void runWithMock(final LocalDate mockDate, final Runnable runnable) { + try (MockedStatic localDateMockedStatic = mockStatic(LocalDate.class, + Mockito.CALLS_REAL_METHODS)) { + localDateMockedStatic.when(LocalDate::now).thenReturn(mockDate); + runnable.run(); + } catch (final Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/test/java/wordle/study/TimeTest.java b/src/test/java/wordle/study/TimeTest.java new file mode 100644 index 00000000..69209680 --- /dev/null +++ b/src/test/java/wordle/study/TimeTest.java @@ -0,0 +1,25 @@ +package wordle.study; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import wordle.TimeTestSupporter; + +public class TimeTest { + + private static final LocalDate mockedDate = LocalDate.of(2024, 6, 12); + + // test(Time): LocalDate 모킹 유틸 추가 + @Test + void LocalDate를_mocking_할_수_있다() { + TimeTestSupporter.runWithMock(mockedDate, () -> { + LocalDate now = LocalDate.now(); + LocalDate base = LocalDate.of(2021, 6, 19); + + long ans = ChronoUnit.DAYS.between(base, now); + + Assertions.assertThat(ans).isEqualTo(1089); + }); + } +} From b201c59edf9ff7d4b894cdef8eb884ef1aa9c826 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 12 Jun 2024 21:54:48 +0900 Subject: [PATCH 20/60] =?UTF-8?q?feat(AnswerFormula):=20AnswerFormula=20ca?= =?UTF-8?q?lculate=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/wordle/domain/AnswerFormula.java | 7 ++++++ .../java/wordle/domain/BaseAnswerFormula.java | 13 ++++++++++ .../wordle/domain/BaseAnswerFormulaTest.java | 25 +++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/main/java/wordle/domain/AnswerFormula.java create mode 100644 src/main/java/wordle/domain/BaseAnswerFormula.java create mode 100644 src/test/java/wordle/domain/BaseAnswerFormulaTest.java diff --git a/src/main/java/wordle/domain/AnswerFormula.java b/src/main/java/wordle/domain/AnswerFormula.java new file mode 100644 index 00000000..c0990ec0 --- /dev/null +++ b/src/main/java/wordle/domain/AnswerFormula.java @@ -0,0 +1,7 @@ +package wordle.domain; + +@FunctionalInterface +public interface AnswerFormula { + + long calculate(int wordCount); +} diff --git a/src/main/java/wordle/domain/BaseAnswerFormula.java b/src/main/java/wordle/domain/BaseAnswerFormula.java new file mode 100644 index 00000000..9c8dc560 --- /dev/null +++ b/src/main/java/wordle/domain/BaseAnswerFormula.java @@ -0,0 +1,13 @@ +package wordle.domain; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; + +public class BaseAnswerFormula implements AnswerFormula { + + private final static LocalDate BASE = LocalDate.of(2021, 6, 19); + + public long calculate(int wordCount) { + return ChronoUnit.DAYS.between(BASE, LocalDate.now()) % wordCount; + } +} diff --git a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java new file mode 100644 index 00000000..ba173c72 --- /dev/null +++ b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java @@ -0,0 +1,25 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import wordle.TimeTestSupporter; + +public class BaseAnswerFormulaTest { + + private static final LocalDate mockedDate = LocalDate.of(2024, 6, 12); + + @ParameterizedTest + @CsvSource(value = {"10:9", "100:89", "10000:1089"}, delimiter = ':') + void 오늘의_정답_공식을_생성할_수_있다(int wordCount, long expected) { + TimeTestSupporter.runWithMock(mockedDate, () -> { + BaseAnswerFormula answerFormula = new BaseAnswerFormula(); + + long index = answerFormula.calculate(wordCount); + + assertThat(index).isEqualTo(expected); + }); + } +} From f161544c9e44acad9f99c16ab12c4fffb662403b Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 12 Jun 2024 22:40:55 +0900 Subject: [PATCH 21/60] =?UTF-8?q?feat(FileReader):=20FileReader=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resource 밑에 있는 파일을 읽어온다 --- .../exception/FileReadFailException.java | 5 +++ src/main/java/wordle/infra/FileReader.java | 29 +++++++++++++++++ .../java/wordle/infra/FileReaderTest.java | 32 +++++++++++++++++++ src/test/resources/words.txt | 5 +++ 4 files changed, 71 insertions(+) create mode 100644 src/main/java/wordle/exception/FileReadFailException.java create mode 100644 src/main/java/wordle/infra/FileReader.java create mode 100644 src/test/java/wordle/infra/FileReaderTest.java create mode 100644 src/test/resources/words.txt diff --git a/src/main/java/wordle/exception/FileReadFailException.java b/src/main/java/wordle/exception/FileReadFailException.java new file mode 100644 index 00000000..3df46a99 --- /dev/null +++ b/src/main/java/wordle/exception/FileReadFailException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class FileReadFailException extends RuntimeException { + +} diff --git a/src/main/java/wordle/infra/FileReader.java b/src/main/java/wordle/infra/FileReader.java new file mode 100644 index 00000000..b90a0b3b --- /dev/null +++ b/src/main/java/wordle/infra/FileReader.java @@ -0,0 +1,29 @@ +package wordle.infra; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import wordle.exception.FileReadFailException; + +public class FileReader { + + public List readByLine(String filePath) { + try { + URL systemResource = getUrl(filePath); + return Files.lines(Path.of(systemResource.toURI())).toList(); + } catch (IOException | URISyntaxException e) { + throw new FileReadFailException(); + } + } + + private URL getUrl(String filePath) { + URL systemResource = ClassLoader.getSystemResource(filePath); + if (systemResource == null) { + throw new FileReadFailException(); + } + return systemResource; + } +} diff --git a/src/test/java/wordle/infra/FileReaderTest.java b/src/test/java/wordle/infra/FileReaderTest.java new file mode 100644 index 00000000..347f63cf --- /dev/null +++ b/src/test/java/wordle/infra/FileReaderTest.java @@ -0,0 +1,32 @@ +package wordle.infra; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import wordle.exception.FileReadFailException; + +public class FileReaderTest { + + private FileReader fileReader; + + @BeforeEach + public void setUp() { + fileReader = new FileReader(); + } + + @Test + void FileReader로_텍스트파일을_읽어온다() { + List textList = fileReader.readByLine("words.txt"); + + assertThat(textList).hasSize(5); + } + + @Test + void FileReader로_없는_파일을_읽어오면_예외를_던진다() { + assertThatThrownBy(() -> fileReader.readByLine("noExist.txt")) + .isInstanceOf(FileReadFailException.class); + } +} diff --git a/src/test/resources/words.txt b/src/test/resources/words.txt new file mode 100644 index 00000000..b880e6bf --- /dev/null +++ b/src/test/resources/words.txt @@ -0,0 +1,5 @@ +apple +hello +abcde +spike +happy \ No newline at end of file From 5c08e858d26309b6524a4ac5b35e1d4391ac85b4 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Wed, 12 Jun 2024 22:40:55 +0900 Subject: [PATCH 22/60] =?UTF-8?q?feat(FileReader):=20FileReader=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resource 밑에 있는 파일을 읽어온다 --- .../exception/FileReadFailException.java | 5 +++ src/main/java/wordle/infra/FileReader.java | 33 +++++++++++++++++ .../java/wordle/infra/FileReaderTest.java | 37 +++++++++++++++++++ src/test/resources/words.txt | 5 +++ 4 files changed, 80 insertions(+) create mode 100644 src/main/java/wordle/exception/FileReadFailException.java create mode 100644 src/main/java/wordle/infra/FileReader.java create mode 100644 src/test/java/wordle/infra/FileReaderTest.java create mode 100644 src/test/resources/words.txt diff --git a/src/main/java/wordle/exception/FileReadFailException.java b/src/main/java/wordle/exception/FileReadFailException.java new file mode 100644 index 00000000..3df46a99 --- /dev/null +++ b/src/main/java/wordle/exception/FileReadFailException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class FileReadFailException extends RuntimeException { + +} diff --git a/src/main/java/wordle/infra/FileReader.java b/src/main/java/wordle/infra/FileReader.java new file mode 100644 index 00000000..acd52c97 --- /dev/null +++ b/src/main/java/wordle/infra/FileReader.java @@ -0,0 +1,33 @@ +package wordle.infra; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import wordle.exception.FileReadFailException; + +public class FileReader { + + public List readByLine(String filePath) { + if (filePath == null || filePath.isBlank()) { + throw new FileReadFailException(); + } + + try { + URL systemResource = getUrl(filePath); + return Files.lines(Path.of(systemResource.toURI())).toList(); + } catch (IOException | URISyntaxException e) { + throw new FileReadFailException(); + } + } + + private URL getUrl(String filePath) { + URL systemResource = ClassLoader.getSystemResource(filePath); + if (systemResource == null) { + throw new FileReadFailException(); + } + return systemResource; + } +} diff --git a/src/test/java/wordle/infra/FileReaderTest.java b/src/test/java/wordle/infra/FileReaderTest.java new file mode 100644 index 00000000..86183747 --- /dev/null +++ b/src/test/java/wordle/infra/FileReaderTest.java @@ -0,0 +1,37 @@ +package wordle.infra; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.ValueSource; +import wordle.exception.FileReadFailException; + +public class FileReaderTest { + + private FileReader fileReader; + + @BeforeEach + public void setUp() { + fileReader = new FileReader(); + } + + @Test + void FileReader로_텍스트파일을_읽어온다() { + List textList = fileReader.readByLine("words.txt"); + + assertThat(textList).containsExactly("apple","hello","abcde","spike","happy"); + } + + @ParameterizedTest + @NullAndEmptySource + @ValueSource(strings = {"noExist.txt"}) + void FileReader로_없는_파일을_읽어오면_예외를_던진다(final String input) { + assertThatThrownBy(() -> fileReader.readByLine(input)) + .isInstanceOf(FileReadFailException.class); + } +} diff --git a/src/test/resources/words.txt b/src/test/resources/words.txt new file mode 100644 index 00000000..b880e6bf --- /dev/null +++ b/src/test/resources/words.txt @@ -0,0 +1,5 @@ +apple +hello +abcde +spike +happy \ No newline at end of file From bb6eb4f096a1e765e08448a3f2d25f0ef0725c48 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Thu, 13 Jun 2024 20:41:31 +0900 Subject: [PATCH 23/60] =?UTF-8?q?fix(AnswerFormula):=20calculate=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B0=98=ED=99=98=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20int=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - index로 사용되는 용도이므로 변경 --- src/main/java/wordle/domain/AnswerFormula.java | 2 +- src/main/java/wordle/domain/BaseAnswerFormula.java | 4 ++-- src/test/java/wordle/domain/BaseAnswerFormulaTest.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/wordle/domain/AnswerFormula.java b/src/main/java/wordle/domain/AnswerFormula.java index c0990ec0..fb4f8d35 100644 --- a/src/main/java/wordle/domain/AnswerFormula.java +++ b/src/main/java/wordle/domain/AnswerFormula.java @@ -3,5 +3,5 @@ @FunctionalInterface public interface AnswerFormula { - long calculate(int wordCount); + int calculate(int wordCount); } diff --git a/src/main/java/wordle/domain/BaseAnswerFormula.java b/src/main/java/wordle/domain/BaseAnswerFormula.java index 9c8dc560..5fbde209 100644 --- a/src/main/java/wordle/domain/BaseAnswerFormula.java +++ b/src/main/java/wordle/domain/BaseAnswerFormula.java @@ -7,7 +7,7 @@ public class BaseAnswerFormula implements AnswerFormula { private final static LocalDate BASE = LocalDate.of(2021, 6, 19); - public long calculate(int wordCount) { - return ChronoUnit.DAYS.between(BASE, LocalDate.now()) % wordCount; + public int calculate(int wordCount) { + return (int) ChronoUnit.DAYS.between(BASE, LocalDate.now()) % wordCount; } } diff --git a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java index ba173c72..7ce95c44 100644 --- a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java +++ b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java @@ -17,7 +17,7 @@ public class BaseAnswerFormulaTest { TimeTestSupporter.runWithMock(mockedDate, () -> { BaseAnswerFormula answerFormula = new BaseAnswerFormula(); - long index = answerFormula.calculate(wordCount); + int index = answerFormula.calculate(wordCount); assertThat(index).isEqualTo(expected); }); From e52073e041f9d935761f5c50638a40960df5b7d7 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Thu, 13 Jun 2024 20:58:49 +0900 Subject: [PATCH 24/60] =?UTF-8?q?fix(AnswerFormula):=20calculate=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/wordle/domain/BaseAnswerFormula.java | 8 +++++++- .../exception/AnswerFormulaException.java | 5 +++++ src/test/java/wordle/TimeTestSupporter.java | 2 ++ .../wordle/domain/BaseAnswerFormulaTest.java | 17 +++++++++++++---- 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 src/main/java/wordle/exception/AnswerFormulaException.java diff --git a/src/main/java/wordle/domain/BaseAnswerFormula.java b/src/main/java/wordle/domain/BaseAnswerFormula.java index 5fbde209..f130e190 100644 --- a/src/main/java/wordle/domain/BaseAnswerFormula.java +++ b/src/main/java/wordle/domain/BaseAnswerFormula.java @@ -2,12 +2,18 @@ import java.time.LocalDate; import java.time.temporal.ChronoUnit; +import wordle.exception.AnswerFormulaException; public class BaseAnswerFormula implements AnswerFormula { - private final static LocalDate BASE = LocalDate.of(2021, 6, 19); + private static final LocalDate BASE = LocalDate.of(2021, 6, 19); + private static final int MIN_WORD_COUNT = 1; public int calculate(int wordCount) { + if (wordCount < MIN_WORD_COUNT) { + throw new AnswerFormulaException(); + } + return (int) ChronoUnit.DAYS.between(BASE, LocalDate.now()) % wordCount; } } diff --git a/src/main/java/wordle/exception/AnswerFormulaException.java b/src/main/java/wordle/exception/AnswerFormulaException.java new file mode 100644 index 00000000..680f2b42 --- /dev/null +++ b/src/main/java/wordle/exception/AnswerFormulaException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class AnswerFormulaException extends IllegalArgumentException { + +} diff --git a/src/test/java/wordle/TimeTestSupporter.java b/src/test/java/wordle/TimeTestSupporter.java index b191196e..869861d3 100644 --- a/src/test/java/wordle/TimeTestSupporter.java +++ b/src/test/java/wordle/TimeTestSupporter.java @@ -8,6 +8,8 @@ public class TimeTestSupporter { + public static final LocalDate mockedDate = LocalDate.of(2024, 6, 12); + public static void runWithMock(final LocalDate mockDate, final Runnable runnable) { try (MockedStatic localDateMockedStatic = mockStatic(LocalDate.class, Mockito.CALLS_REAL_METHODS)) { diff --git a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java index 7ce95c44..5db7ac17 100644 --- a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java +++ b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java @@ -1,20 +1,20 @@ package wordle.domain; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.time.LocalDate; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; import wordle.TimeTestSupporter; +import wordle.exception.AnswerFormulaException; public class BaseAnswerFormulaTest { - private static final LocalDate mockedDate = LocalDate.of(2024, 6, 12); - @ParameterizedTest @CsvSource(value = {"10:9", "100:89", "10000:1089"}, delimiter = ':') void 오늘의_정답_공식을_생성할_수_있다(int wordCount, long expected) { - TimeTestSupporter.runWithMock(mockedDate, () -> { + TimeTestSupporter.runWithMock(TimeTestSupporter.mockedDate, () -> { BaseAnswerFormula answerFormula = new BaseAnswerFormula(); int index = answerFormula.calculate(wordCount); @@ -22,4 +22,13 @@ public class BaseAnswerFormulaTest { assertThat(index).isEqualTo(expected); }); } + + @ParameterizedTest + @ValueSource(ints = {0, -1}) + void 파라미터는_1보다_작을_수_없다(int wordCount) { + BaseAnswerFormula answerFormula = new BaseAnswerFormula(); + + assertThatThrownBy(() -> answerFormula.calculate(wordCount)) + .isInstanceOf(AnswerFormulaException.class); + } } From b64703567dab1fd576c3fdc3c6264d026e2292ea Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Thu, 13 Jun 2024 21:05:21 +0900 Subject: [PATCH 25/60] =?UTF-8?q?feat(WordBook):=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20WordBook=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 단어장 책임을 가진 클래스 --- src/main/java/wordle/domain/FileWordBook.java | 27 ++++++++++++ src/main/java/wordle/domain/WordBook.java | 8 ++++ .../java/wordle/domain/FileWordBookTest.java | 44 +++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 src/main/java/wordle/domain/FileWordBook.java create mode 100644 src/main/java/wordle/domain/WordBook.java create mode 100644 src/test/java/wordle/domain/FileWordBookTest.java diff --git a/src/main/java/wordle/domain/FileWordBook.java b/src/main/java/wordle/domain/FileWordBook.java new file mode 100644 index 00000000..5e364c89 --- /dev/null +++ b/src/main/java/wordle/domain/FileWordBook.java @@ -0,0 +1,27 @@ +package wordle.domain; + +import java.util.List; +import wordle.infra.FileReader; + +public class FileWordBook implements WordBook { + + private final List words; + + public FileWordBook(FileReader fileReader) { + this.words = fileReader.readByLine("words.txt") + .stream() + .map(Word::new) + .toList(); + } + + @Override + public Word pick(AnswerFormula answerFormula) { + int index = answerFormula.calculate(words.size()); + return words.get(index); + } + + @Override + public boolean exist(Word word) { + return words.contains(word); + } +} diff --git a/src/main/java/wordle/domain/WordBook.java b/src/main/java/wordle/domain/WordBook.java new file mode 100644 index 00000000..41ae2042 --- /dev/null +++ b/src/main/java/wordle/domain/WordBook.java @@ -0,0 +1,8 @@ +package wordle.domain; + +public interface WordBook { + + Word pick(AnswerFormula answerFormula); + + boolean exist(Word word); +} diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java new file mode 100644 index 00000000..b73ee4a0 --- /dev/null +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -0,0 +1,44 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import wordle.TimeTestSupporter; +import wordle.infra.FileReader; + +public class FileWordBookTest { + + private WordBook wordBook; + + @BeforeEach + void setUp() { + wordBook = new FileWordBook(new FileReader()); + } + + @ParameterizedTest + @CsvSource(value = {"hello:true", "exist:false"}, delimiter = ':') + void WordBook에_단어가_존재하는지_확인_할_수있다(String input, boolean expected) { + final boolean actual = wordBook.exist(new Word(input)); + + assertThat(actual).isEqualTo(expected); + } + + @ParameterizedTest + @CsvSource(value = { + "2024-06-08:apple", + "2024-06-09:hello", + "2024-06-10:abcde", + "2024-06-11:spike", + "2024-06-12:happy" + }, delimiter = ':') + void WordBook에서_공식을_통해_오늘의_정답_단어를_뽑는다(LocalDate mockDate, String expected) { + TimeTestSupporter.runWithMock(mockDate, () -> { + Word actual = wordBook.pick(new BaseAnswerFormula()); + + assertThat(actual).isEqualTo(new Word(expected)); + }); + } +} From 74acae5eb650e66412c931b018253439a50136be Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Thu, 13 Jun 2024 21:20:50 +0900 Subject: [PATCH 26/60] =?UTF-8?q?feat(Alphabet):=20Alphabet=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 알파벳을 소문자로 저장하는 클래스 --- src/main/java/wordle/domain/Alphabet.java | 35 +++++++++++++++++++ .../exception/InvalidAlphabetException.java | 5 +++ src/test/java/wordle/domain/AlphabetTest.java | 26 ++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 src/main/java/wordle/domain/Alphabet.java create mode 100644 src/main/java/wordle/exception/InvalidAlphabetException.java create mode 100644 src/test/java/wordle/domain/AlphabetTest.java diff --git a/src/main/java/wordle/domain/Alphabet.java b/src/main/java/wordle/domain/Alphabet.java new file mode 100644 index 00000000..8cb3b00b --- /dev/null +++ b/src/main/java/wordle/domain/Alphabet.java @@ -0,0 +1,35 @@ +package wordle.domain; + +import java.util.Objects; +import wordle.exception.InvalidAlphabetException; + +public class Alphabet { + + private final char alphabet; + + public Alphabet(char alphabet) { + char lowerAlphabet = Character.toLowerCase(alphabet); + if (lowerAlphabet < 'a' || lowerAlphabet > 'z') { + throw new InvalidAlphabetException(); + } + + this.alphabet = alphabet; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Alphabet alphabet1 = (Alphabet) o; + return alphabet == alphabet1.alphabet; + } + + @Override + public int hashCode() { + return Objects.hash(alphabet); + } +} diff --git a/src/main/java/wordle/exception/InvalidAlphabetException.java b/src/main/java/wordle/exception/InvalidAlphabetException.java new file mode 100644 index 00000000..e05814bf --- /dev/null +++ b/src/main/java/wordle/exception/InvalidAlphabetException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class InvalidAlphabetException extends IllegalArgumentException { + +} diff --git a/src/test/java/wordle/domain/AlphabetTest.java b/src/test/java/wordle/domain/AlphabetTest.java new file mode 100644 index 00000000..bc9b6df8 --- /dev/null +++ b/src/test/java/wordle/domain/AlphabetTest.java @@ -0,0 +1,26 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import wordle.exception.InvalidAlphabetException; + +public class AlphabetTest { + + @Test + void 알파벳이_같으면_동등한_객체이다() { + final Alphabet alphabetA = new Alphabet('a'); + + assertThat(alphabetA).isEqualTo(new Alphabet('a')); + } + + @ParameterizedTest + @ValueSource(chars = {'1', 'ㄱ', ' ', '!', '.'}) + void 알파벳이_아니면_예외가_발생한다(final char input) { + assertThatThrownBy(() -> new Alphabet(input)) + .isInstanceOf(InvalidAlphabetException.class); + } +} From 7c56c0a9246fcf44916b617d93efdf3daea894af Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Thu, 13 Jun 2024 21:36:40 +0900 Subject: [PATCH 27/60] =?UTF-8?q?refactor(Letter):=20Alphabet=EC=9D=84=20?= =?UTF-8?q?=EA=B0=92=EA=B0=9D=EC=B2=B4(VO)=EB=A1=9C=20=EA=B0=96=EB=8A=94?= =?UTF-8?q?=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Letter.java | 27 +++++++++++---------- src/test/java/wordle/domain/LetterTest.java | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/main/java/wordle/domain/Letter.java b/src/main/java/wordle/domain/Letter.java index f799afdf..28e35445 100644 --- a/src/main/java/wordle/domain/Letter.java +++ b/src/main/java/wordle/domain/Letter.java @@ -4,14 +4,22 @@ public class Letter { - private char alphabet; - private Position position; + private final Alphabet alphabet; + private final Position position; - public Letter(char alphabet, int position) { - this.alphabet = alphabet; + public Letter(final char alphabet, final int position) { + this.alphabet = new Alphabet(alphabet); this.position = new Position(position); } + public boolean isSameAlphabet(Letter letter) { + return letter.alphabet.equals(this.alphabet); + } + + public Position getPosition() { + return position; + } + @Override public boolean equals(Object o) { if (this == o) { @@ -21,19 +29,12 @@ public boolean equals(Object o) { return false; } Letter letter = (Letter) o; - return alphabet == letter.alphabet && Objects.equals(position, letter.position); + return Objects.equals(alphabet, letter.alphabet) && Objects.equals(position, + letter.position); } @Override public int hashCode() { return Objects.hash(alphabet, position); } - - public boolean isSameAlphabet(Letter letter) { - return letter.alphabet == this.alphabet; - } - - public Position getPosition() { - return position; - } } diff --git a/src/test/java/wordle/domain/LetterTest.java b/src/test/java/wordle/domain/LetterTest.java index 12bc4130..b91e63fc 100644 --- a/src/test/java/wordle/domain/LetterTest.java +++ b/src/test/java/wordle/domain/LetterTest.java @@ -32,7 +32,7 @@ public class LetterTest { } @Test - void 알파벳은_같은지_확인할_수_있다() { + void 알파벳이_같은지_확인할_수_있다() { Letter letter = new Letter('a', 0); assertThat(letter.isSameAlphabet(new Letter('a', 1))).isTrue(); From db4f022463722ff9622e49e775c7c9aeefebd47a Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 14:16:38 +0900 Subject: [PATCH 28/60] =?UTF-8?q?feat(Record):=20=EB=8B=A8=EC=96=B4=20?= =?UTF-8?q?=EB=B9=84=EA=B5=90=20=EA=B8=B0=EB=A1=9D=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Record.java | 32 +++++++++++++++++++ src/main/java/wordle/domain/Result.java | 4 +++ src/main/java/wordle/domain/Results.java | 4 +++ src/test/java/wordle/domain/RecordTest.java | 30 +++++++++++++++++ .../java/wordle/fixture/ResultFixture.java | 9 ++++++ 5 files changed, 79 insertions(+) create mode 100644 src/main/java/wordle/domain/Record.java create mode 100644 src/test/java/wordle/domain/RecordTest.java diff --git a/src/main/java/wordle/domain/Record.java b/src/main/java/wordle/domain/Record.java new file mode 100644 index 00000000..fa2ba819 --- /dev/null +++ b/src/main/java/wordle/domain/Record.java @@ -0,0 +1,32 @@ +package wordle.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.StreamSupport; + +public class Record { + + public static final int MAX_COUNT = 6; + private final List record; + + public Record() { + this.record = new ArrayList<>(); + } + + public void add(Results results) { + record.add(results); + } + + public boolean isEnd() { + return existAllGreen() || record.size() >= MAX_COUNT; + } + + private boolean existAllGreen() { + if (record.isEmpty()) { + return false; + } + return record + .getLast() + .isAllGreen(); + } +} diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java index bffebbd0..f8a0f935 100644 --- a/src/main/java/wordle/domain/Result.java +++ b/src/main/java/wordle/domain/Result.java @@ -48,4 +48,8 @@ public boolean isSamePosition(Position position) { public int compareTo(Result o) { return position.compareTo(o.position); } + + public boolean isGreen() { + return this.tile == Tile.GREEN; + } } diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java index 43d76c89..0b063b8b 100644 --- a/src/main/java/wordle/domain/Results.java +++ b/src/main/java/wordle/domain/Results.java @@ -30,4 +30,8 @@ public boolean isCheckedPosition(Position position) { return false; } + + public boolean isAllGreen() { + return results.stream().allMatch(Result::isGreen); + } } diff --git a/src/test/java/wordle/domain/RecordTest.java b/src/test/java/wordle/domain/RecordTest.java new file mode 100644 index 00000000..9a175891 --- /dev/null +++ b/src/test/java/wordle/domain/RecordTest.java @@ -0,0 +1,30 @@ +package wordle.domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import wordle.fixture.ResultFixture; + +public class RecordTest { + + @Test + void Record에_초록색타일_5개_인_결과모음이_있으면_종료여부가_true이다() { + Record record = new Record(); + + record.add(ResultFixture.createGreenResults(5)); + + assertThat(record.isEnd()).isTrue(); + } + + @Test + void Record가_결과모음이_6개이상이면_종료여부가_true이다() { + Record record = new Record(); + + for (int i = 0; i < Record.MAX_COUNT; i++) { + record.add(ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.GRAY, + Tile.GRAY)); + } + + assertThat(record.isEnd()).isTrue(); + } +} diff --git a/src/test/java/wordle/fixture/ResultFixture.java b/src/test/java/wordle/fixture/ResultFixture.java index 54f179f8..e8e61366 100644 --- a/src/test/java/wordle/fixture/ResultFixture.java +++ b/src/test/java/wordle/fixture/ResultFixture.java @@ -15,6 +15,15 @@ public static Results createGreenResults(int count) { return results; } + public static Results createResults(Tile tile, Tile... tiles) { + Results results = new Results(); + results.add(new Result(tile, 0)); + IntStream.range(1, tiles.length + 1) + .mapToObj(idx -> new Result(tiles[idx - 1], idx)) + .forEach(results::add); + return results; + } + public static Result createGreenResult(int position) { return new Result(Tile.GREEN, position); } From 553fefca58463f1d38160c05f691da747ef89dfe Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 14:19:59 +0900 Subject: [PATCH 29/60] =?UTF-8?q?test(Result):=20=EC=B4=88=EB=A1=9D?= =?UTF-8?q?=EC=83=89=20=ED=83=80=EC=9D=BC=20=EC=97=AC=EB=B6=80=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/wordle/domain/ResultTest.java | 10 +++++++++- src/test/java/wordle/domain/ResultsTest.java | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/test/java/wordle/domain/ResultTest.java b/src/test/java/wordle/domain/ResultTest.java index 5553b5cb..367455b5 100644 --- a/src/test/java/wordle/domain/ResultTest.java +++ b/src/test/java/wordle/domain/ResultTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import org.junit.jupiter.api.Test; +import wordle.fixture.ResultFixture; public class ResultTest { @Test @@ -13,8 +14,15 @@ public class ResultTest { @Test void 타일과_위치가_같으면_동등한_객체이다() { - Result result = new Result(Tile.GREEN, 0); + Result result = ResultFixture.createGreenResult(0); assertThat(result).isEqualTo(new Result(Tile.GREEN, 0)); } + + @Test + void 타일이_초록색인지_확인할_수_있다() { + Result result = ResultFixture.createGreenResult(0); + + assertThat(result.isGreen()).isTrue(); + } } diff --git a/src/test/java/wordle/domain/ResultsTest.java b/src/test/java/wordle/domain/ResultsTest.java index 76392b81..a933899c 100644 --- a/src/test/java/wordle/domain/ResultsTest.java +++ b/src/test/java/wordle/domain/ResultsTest.java @@ -18,4 +18,11 @@ class ResultsTest { ResultFixture.createGreenResult(3), ResultFixture.createGreenResult(4)); } + + @Test + void Results_가_전부_초록색타일인지_알수있다() { + Results results = ResultFixture.createGreenResults(5); + + assertThat(results.isAllGreen()).isTrue(); + } } \ No newline at end of file From 808df83d6ea3b1fc734483ebf849f53397410fb7 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 14:47:35 +0900 Subject: [PATCH 30/60] =?UTF-8?q?fix(Result):=20=EC=B4=88=EB=A1=9D?= =?UTF-8?q?=EC=83=89,=ED=9A=8C=EC=83=89=20=ED=83=80=EC=9D=BC=20=EC=97=AC?= =?UTF-8?q?=EB=B6=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Result.java | 6 ++++++ src/test/java/wordle/domain/ResultTest.java | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java index f8a0f935..aade37e3 100644 --- a/src/main/java/wordle/domain/Result.java +++ b/src/main/java/wordle/domain/Result.java @@ -52,4 +52,10 @@ public int compareTo(Result o) { public boolean isGreen() { return this.tile == Tile.GREEN; } + public boolean isYellow() { + return this.tile == Tile.YELLOW; + } + public boolean isGray() { + return this.tile == Tile.GRAY; + } } diff --git a/src/test/java/wordle/domain/ResultTest.java b/src/test/java/wordle/domain/ResultTest.java index 367455b5..e7b37062 100644 --- a/src/test/java/wordle/domain/ResultTest.java +++ b/src/test/java/wordle/domain/ResultTest.java @@ -25,4 +25,18 @@ public class ResultTest { assertThat(result.isGreen()).isTrue(); } + + @Test + void 타일이_노란색인지_확인할_수_있다() { + Result result = ResultFixture.createYellowResult(0); + + assertThat(result.isYellow()).isTrue(); + } + + @Test + void 타일이_회색인지_확인할_수_있다() { + Result result = ResultFixture.createGrayResult(0); + + assertThat(result.isGray()).isTrue(); + } } From 65b95af292a92201571afdbda7235cefb3a183ac Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 15:19:29 +0900 Subject: [PATCH 31/60] =?UTF-8?q?feat(InputView):=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=20=EC=9E=85=EB=A0=A5=EC=9D=84=20=EB=B0=9B=EB=8A=94=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/ui/ConsoleInputView.java | 17 +++++++++++++++++ src/main/java/wordle/ui/InputView.java | 7 +++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/wordle/ui/ConsoleInputView.java create mode 100644 src/main/java/wordle/ui/InputView.java diff --git a/src/main/java/wordle/ui/ConsoleInputView.java b/src/main/java/wordle/ui/ConsoleInputView.java new file mode 100644 index 00000000..4af1e068 --- /dev/null +++ b/src/main/java/wordle/ui/ConsoleInputView.java @@ -0,0 +1,17 @@ +package wordle.ui; + +import java.util.Scanner; + +public class ConsoleInputView implements InputView { + + private final Scanner scanner; + + public ConsoleInputView() { + this.scanner = new Scanner(System.in); + } + + @Override + public String input() { + return scanner.nextLine(); + } +} diff --git a/src/main/java/wordle/ui/InputView.java b/src/main/java/wordle/ui/InputView.java new file mode 100644 index 00000000..d0c7c708 --- /dev/null +++ b/src/main/java/wordle/ui/InputView.java @@ -0,0 +1,7 @@ +package wordle.ui; + +public interface InputView { + + String input(); + +} From a9e9e7696838975eee5a31c9290d9bfe1668f922 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 15:20:12 +0900 Subject: [PATCH 32/60] =?UTF-8?q?feat(OutputView):=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Record.java | 13 ++- .../java/wordle/ui/ConsoleOutputView.java | 46 ++++++++++ src/main/java/wordle/ui/OutputView.java | 13 +++ .../java/wordle/fixture/RecordFixture.java | 17 ++++ .../java/wordle/ui/ConsoleOutputViewTest.java | 85 +++++++++++++++++++ 5 files changed, 172 insertions(+), 2 deletions(-) create mode 100644 src/main/java/wordle/ui/ConsoleOutputView.java create mode 100644 src/main/java/wordle/ui/OutputView.java create mode 100644 src/test/java/wordle/fixture/RecordFixture.java create mode 100644 src/test/java/wordle/ui/ConsoleOutputViewTest.java diff --git a/src/main/java/wordle/domain/Record.java b/src/main/java/wordle/domain/Record.java index fa2ba819..3cf57b61 100644 --- a/src/main/java/wordle/domain/Record.java +++ b/src/main/java/wordle/domain/Record.java @@ -1,10 +1,10 @@ package wordle.domain; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; -import java.util.stream.StreamSupport; -public class Record { +public class Record implements Iterable { public static final int MAX_COUNT = 6; private final List record; @@ -29,4 +29,13 @@ private boolean existAllGreen() { .getLast() .isAllGreen(); } + + @Override + public Iterator iterator() { + return record.iterator(); + } + + public int size() { + return record.size(); + } } diff --git a/src/main/java/wordle/ui/ConsoleOutputView.java b/src/main/java/wordle/ui/ConsoleOutputView.java new file mode 100644 index 00000000..061c5ada --- /dev/null +++ b/src/main/java/wordle/ui/ConsoleOutputView.java @@ -0,0 +1,46 @@ +package wordle.ui; + +import wordle.domain.Record; +import wordle.domain.Result; +import wordle.domain.Results; + +public class ConsoleOutputView implements OutputView { + + @Override + public void welcome() { + System.out.printf("WORDLE을 %d번 만에 맞춰 보세요.\n", Record.MAX_COUNT); + System.out.println("시도의 결과는 타일의 색 변화로 나타납니다."); + } + + @Override + public void askAnswer() { + System.out.println("정답을 입력해 주세요."); + } + + @Override + public void showRecord(Record record) { + for (Results results : record) { + for (Result result : results) { + String s = findTile(result); + System.out.print(s); + } + System.out.println(); + } + } + + private static String findTile(Result result) { + if (result.isGreen()) { + return "🟩"; + } + if (result.isYellow()) { + return "🟨"; + } + return "⬜"; + } + + @Override + public void end(Record record) { + System.out.printf("%d/%d\n\n", record.size(), Record.MAX_COUNT); + showRecord(record); + } +} diff --git a/src/main/java/wordle/ui/OutputView.java b/src/main/java/wordle/ui/OutputView.java new file mode 100644 index 00000000..3f1f51ff --- /dev/null +++ b/src/main/java/wordle/ui/OutputView.java @@ -0,0 +1,13 @@ +package wordle.ui; + +import wordle.domain.Record; +public interface OutputView { + + void welcome(); + + void askAnswer(); + + void showRecord(Record record); + + void end(Record record); +} diff --git a/src/test/java/wordle/fixture/RecordFixture.java b/src/test/java/wordle/fixture/RecordFixture.java new file mode 100644 index 00000000..e3d3efa1 --- /dev/null +++ b/src/test/java/wordle/fixture/RecordFixture.java @@ -0,0 +1,17 @@ +package wordle.fixture; + +import wordle.domain.Record; +import wordle.domain.Results; + +public class RecordFixture { + + public static Record create(Results results, Results... resultsList) { + Record record = new Record(); + record.add(results); + for (Results value : resultsList) { + record.add(value); + } + return record; + } + +} diff --git a/src/test/java/wordle/ui/ConsoleOutputViewTest.java b/src/test/java/wordle/ui/ConsoleOutputViewTest.java new file mode 100644 index 00000000..79a6c2d9 --- /dev/null +++ b/src/test/java/wordle/ui/ConsoleOutputViewTest.java @@ -0,0 +1,85 @@ +package wordle.ui; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import wordle.domain.Record; +import wordle.domain.Tile; +import wordle.fixture.RecordFixture; +import wordle.fixture.ResultFixture; + +class ConsoleOutputViewTest { + + private PrintStream standardOut; + private OutputStream captor; + + private ConsoleOutputView consoleOutputView; + + @BeforeEach + protected final void init() { + standardOut = System.out; + captor = new ByteArrayOutputStream(); + consoleOutputView = new ConsoleOutputView(); + System.setOut(new PrintStream(captor)); + } + + @AfterEach + protected final void printOutput() { + System.setOut(standardOut); + } + + @Test + void Record를_출력할_수_있다() { + Record record = createRecordFixture(); + + consoleOutputView.showRecord(record); + + assertThat(captor.toString()).isEqualTo(""" + ⬜🟩⬜🟨⬜ + ⬜⬜⬜🟨⬜ + ⬜🟩🟨🟨⬜ + ⬜🟩⬜🟨⬜ + ⬜⬜⬜⬜⬜ + 🟩🟩🟩🟩🟩 + """); + } + + @Test + void 게임종료를_출력할_수_있다() { + Record record = createRecordFixture(); + + consoleOutputView.end(record); + + assertThat(captor.toString()).isEqualTo(""" + 6/6 + + ⬜🟩⬜🟨⬜ + ⬜⬜⬜🟨⬜ + ⬜🟩🟨🟨⬜ + ⬜🟩⬜🟨⬜ + ⬜⬜⬜⬜⬜ + 🟩🟩🟩🟩🟩 + """); + } + + private static Record createRecordFixture() { + return RecordFixture.create( + ResultFixture.createResults(Tile.GRAY, Tile.GREEN, Tile.GRAY, Tile.YELLOW, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.YELLOW, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GREEN, Tile.YELLOW, Tile.YELLOW, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GREEN, Tile.GRAY, Tile.YELLOW, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.GRAY), + ResultFixture.createResults(Tile.GREEN, Tile.GREEN, Tile.GREEN, Tile.GREEN, + Tile.GREEN) + ); + } +} \ No newline at end of file From e848b10222e421ce441741a4915cd30b906b2dcc Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 15:32:11 +0900 Subject: [PATCH 33/60] =?UTF-8?q?feat(WordBook):=20=EB=8B=A8=EC=96=B4?= =?UTF-8?q?=EB=A5=BC=20=EC=B0=BE=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/FileWordBook.java | 10 ++++++++++ src/main/java/wordle/domain/WordBook.java | 2 ++ .../wordle/exception/WordNotExistException.java | 5 +++++ src/test/java/wordle/domain/FileWordBookTest.java | 14 ++++++++++++++ 4 files changed, 31 insertions(+) create mode 100644 src/main/java/wordle/exception/WordNotExistException.java diff --git a/src/main/java/wordle/domain/FileWordBook.java b/src/main/java/wordle/domain/FileWordBook.java index 5e364c89..465533ae 100644 --- a/src/main/java/wordle/domain/FileWordBook.java +++ b/src/main/java/wordle/domain/FileWordBook.java @@ -1,6 +1,7 @@ package wordle.domain; import java.util.List; +import wordle.exception.WordNotExistException; import wordle.infra.FileReader; public class FileWordBook implements WordBook { @@ -24,4 +25,13 @@ public Word pick(AnswerFormula answerFormula) { public boolean exist(Word word) { return words.contains(word); } + + @Override + public Word find(String target) { + Word targetWord = new Word(target); + return words.stream() + .filter(targetWord::equals) + .findFirst() + .orElseThrow(WordNotExistException::new); + } } diff --git a/src/main/java/wordle/domain/WordBook.java b/src/main/java/wordle/domain/WordBook.java index 41ae2042..136568f4 100644 --- a/src/main/java/wordle/domain/WordBook.java +++ b/src/main/java/wordle/domain/WordBook.java @@ -5,4 +5,6 @@ public interface WordBook { Word pick(AnswerFormula answerFormula); boolean exist(Word word); + + Word find(String word); } diff --git a/src/main/java/wordle/exception/WordNotExistException.java b/src/main/java/wordle/exception/WordNotExistException.java new file mode 100644 index 00000000..275d9465 --- /dev/null +++ b/src/main/java/wordle/exception/WordNotExistException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class WordNotExistException extends RuntimeException { + +} diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java index b73ee4a0..1764a3bc 100644 --- a/src/test/java/wordle/domain/FileWordBookTest.java +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -1,9 +1,11 @@ package wordle.domain; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.LocalDate; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import wordle.TimeTestSupporter; @@ -41,4 +43,16 @@ void setUp() { assertThat(actual).isEqualTo(new Word(expected)); }); } + + @Test + void WordBook에서_단어를_찾을_수_있다() { + Word word = wordBook.find("happy"); + + assertThat(word).isNotNull(); + } + + @Test + void WordBook에_없는_단어를_찾으면_예외를_던진다() { + assertThatThrownBy(() -> wordBook.find("ghost")); + } } From 6ca7944750ef1b57f23f2080163c257880e4e39e Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 15:43:59 +0900 Subject: [PATCH 34/60] =?UTF-8?q?test(WordBook):=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/wordle/domain/FileWordBookTest.java | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java index 1764a3bc..a5d9a7b8 100644 --- a/src/test/java/wordle/domain/FileWordBookTest.java +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -3,12 +3,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import java.time.LocalDate; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import wordle.TimeTestSupporter; import wordle.infra.FileReader; public class FileWordBookTest { @@ -28,20 +26,10 @@ void setUp() { assertThat(actual).isEqualTo(expected); } - @ParameterizedTest - @CsvSource(value = { - "2024-06-08:apple", - "2024-06-09:hello", - "2024-06-10:abcde", - "2024-06-11:spike", - "2024-06-12:happy" - }, delimiter = ':') - void WordBook에서_공식을_통해_오늘의_정답_단어를_뽑는다(LocalDate mockDate, String expected) { - TimeTestSupporter.runWithMock(mockDate, () -> { - Word actual = wordBook.pick(new BaseAnswerFormula()); - - assertThat(actual).isEqualTo(new Word(expected)); - }); + @Test + void WordBook에서_공식을_통해_오늘의_정답_단어를_뽑는다() { + Word actual = wordBook.pick((wordCount) -> 0); + assertThat(actual).isEqualTo(new Word("apple")); } @Test From 4e50c35b3ce3242d6f8a5f76dfbe15ad1a76fc43 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 15:46:42 +0900 Subject: [PATCH 35/60] =?UTF-8?q?fix(Position):=20=EC=9D=8C=EC=88=98=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Position.java | 6 ++++++ .../wordle/exception/InvalidPositionException.java | 5 +++++ src/test/java/wordle/domain/PositionTest.java | 12 ++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/main/java/wordle/exception/InvalidPositionException.java diff --git a/src/main/java/wordle/domain/Position.java b/src/main/java/wordle/domain/Position.java index b70c7c2b..ad4b88f1 100644 --- a/src/main/java/wordle/domain/Position.java +++ b/src/main/java/wordle/domain/Position.java @@ -1,12 +1,18 @@ package wordle.domain; import java.util.Objects; +import wordle.exception.InvalidPositionException; public class Position implements Comparable { + private static final int MIN_POSITION = 0; private final int position; public Position(int position) { + if(position < MIN_POSITION){ + throw new InvalidPositionException(); + } + this.position = position; } diff --git a/src/main/java/wordle/exception/InvalidPositionException.java b/src/main/java/wordle/exception/InvalidPositionException.java new file mode 100644 index 00000000..d3bf0797 --- /dev/null +++ b/src/main/java/wordle/exception/InvalidPositionException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class InvalidPositionException extends IllegalArgumentException { + +} diff --git a/src/test/java/wordle/domain/PositionTest.java b/src/test/java/wordle/domain/PositionTest.java index 54275182..913e444e 100644 --- a/src/test/java/wordle/domain/PositionTest.java +++ b/src/test/java/wordle/domain/PositionTest.java @@ -1,20 +1,28 @@ package wordle.domain; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.Test; +import wordle.exception.InvalidPositionException; public class PositionTest { @Test - void Position이_같으면_동등한_객체이다(){ + void Position은_음수가_될_수_없다() { + assertThatThrownBy(() -> new Position(-1)) + .isInstanceOf(InvalidPositionException.class); + } + + @Test + void Position이_같으면_동등한_객체이다() { Position position = createPosition(0); assertThat(position).isEqualTo(createPosition(0)); } @Test - void Position이_다르면_동등하지않은_객체이다(){ + void Position이_다르면_동등하지않은_객체이다() { Position position = createPosition(0); assertThat(position).isNotEqualTo(createPosition(1)); From bad65f2b31d587f5d1fa1d2a96a5495452875380 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 15:48:26 +0900 Subject: [PATCH 36/60] =?UTF-8?q?fix(Alphabet):=20=EC=95=8C=ED=8C=8C?= =?UTF-8?q?=EB=B2=B3=EC=9D=80=20=EB=8C=80=EC=86=8C=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EB=A5=BC=20=EA=B5=AC=EB=B6=84=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Alphabet.java | 2 +- src/test/java/wordle/domain/AlphabetTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/wordle/domain/Alphabet.java b/src/main/java/wordle/domain/Alphabet.java index 8cb3b00b..3c948c7b 100644 --- a/src/main/java/wordle/domain/Alphabet.java +++ b/src/main/java/wordle/domain/Alphabet.java @@ -13,7 +13,7 @@ public Alphabet(char alphabet) { throw new InvalidAlphabetException(); } - this.alphabet = alphabet; + this.alphabet = lowerAlphabet; } @Override diff --git a/src/test/java/wordle/domain/AlphabetTest.java b/src/test/java/wordle/domain/AlphabetTest.java index bc9b6df8..1544509c 100644 --- a/src/test/java/wordle/domain/AlphabetTest.java +++ b/src/test/java/wordle/domain/AlphabetTest.java @@ -10,6 +10,13 @@ public class AlphabetTest { + @Test + void 알파벳은_대소문자를_구분하지_않는다() { + final Alphabet alphabetA = new Alphabet('a'); + + assertThat(alphabetA).isEqualTo(new Alphabet('A')); + } + @Test void 알파벳이_같으면_동등한_객체이다() { final Alphabet alphabetA = new Alphabet('a'); From f861ed0dc0ac6d5709b56520e33f9b35ec63a8e4 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 16:43:55 +0900 Subject: [PATCH 37/60] =?UTF-8?q?fix(ConsoleOutputView):=20=EC=84=B1?= =?UTF-8?q?=EA=B3=B5,=20=EC=8B=A4=ED=8C=A8=20=EC=A2=85=EB=A3=8C=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/wordle/ui/ConsoleOutputView.java | 16 ++++++- src/main/java/wordle/ui/OutputView.java | 7 ++- .../java/wordle/ui/ConsoleOutputViewTest.java | 48 +++++++++++++++++-- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/main/java/wordle/ui/ConsoleOutputView.java b/src/main/java/wordle/ui/ConsoleOutputView.java index 061c5ada..d7300ae3 100644 --- a/src/main/java/wordle/ui/ConsoleOutputView.java +++ b/src/main/java/wordle/ui/ConsoleOutputView.java @@ -26,6 +26,7 @@ public void showRecord(Record record) { } System.out.println(); } + System.out.println(); } private static String findTile(Result result) { @@ -39,8 +40,19 @@ private static String findTile(Result result) { } @Override - public void end(Record record) { - System.out.printf("%d/%d\n\n", record.size(), Record.MAX_COUNT); + public void successEnd(Record record) { + System.out.printf("\n%d/%d\n\n", record.size(), Record.MAX_COUNT); showRecord(record); } + + @Override + public void failEnd(Record record) { + System.out.printf("\nX/%d\n\n", Record.MAX_COUNT); + showRecord(record); + } + + @Override + public void wrongAnswer() { + System.out.println("존재하지 않는 단어입니다."); + } } diff --git a/src/main/java/wordle/ui/OutputView.java b/src/main/java/wordle/ui/OutputView.java index 3f1f51ff..2a973888 100644 --- a/src/main/java/wordle/ui/OutputView.java +++ b/src/main/java/wordle/ui/OutputView.java @@ -1,6 +1,7 @@ package wordle.ui; import wordle.domain.Record; + public interface OutputView { void welcome(); @@ -9,5 +10,9 @@ public interface OutputView { void showRecord(Record record); - void end(Record record); + void successEnd(Record record); + + void failEnd(Record record); + + void wrongAnswer(); } diff --git a/src/test/java/wordle/ui/ConsoleOutputViewTest.java b/src/test/java/wordle/ui/ConsoleOutputViewTest.java index 79a6c2d9..1c772ea3 100644 --- a/src/test/java/wordle/ui/ConsoleOutputViewTest.java +++ b/src/test/java/wordle/ui/ConsoleOutputViewTest.java @@ -35,7 +35,7 @@ protected final void printOutput() { @Test void Record를_출력할_수_있다() { - Record record = createRecordFixture(); + Record record = createSuccessRecordFixture(); consoleOutputView.showRecord(record); @@ -46,16 +46,18 @@ protected final void printOutput() { ⬜🟩⬜🟨⬜ ⬜⬜⬜⬜⬜ 🟩🟩🟩🟩🟩 + """); } @Test - void 게임종료를_출력할_수_있다() { - Record record = createRecordFixture(); + void 게임_성공종료를_출력할_수_있다() { + Record record = createSuccessRecordFixture(); - consoleOutputView.end(record); + consoleOutputView.successEnd(record); assertThat(captor.toString()).isEqualTo(""" + 6/6 ⬜🟩⬜🟨⬜ @@ -64,10 +66,30 @@ protected final void printOutput() { ⬜🟩⬜🟨⬜ ⬜⬜⬜⬜⬜ 🟩🟩🟩🟩🟩 + + """); + } + @Test + void 게임_실패종료를_출력할_수_있다() { + Record record = createFailureRecordFixture(); + + consoleOutputView.failEnd(record); + + assertThat(captor.toString()).isEqualTo(""" + + X/6 + + ⬜⬜⬜⬜⬜ + ⬜⬜⬜⬜⬜ + ⬜⬜⬜🟨⬜ + ⬜⬜⬜🟨🟨 + ⬜⬜🟨🟨🟨 + 🟩🟨🟨🟨🟨 + """); } - private static Record createRecordFixture() { + private static Record createSuccessRecordFixture() { return RecordFixture.create( ResultFixture.createResults(Tile.GRAY, Tile.GREEN, Tile.GRAY, Tile.YELLOW, Tile.GRAY), @@ -82,4 +104,20 @@ private static Record createRecordFixture() { Tile.GREEN) ); } + + private static Record createFailureRecordFixture() { + return RecordFixture.create( + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.GRAY, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.GRAY, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.YELLOW, + Tile.GRAY), + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.YELLOW, + Tile.YELLOW), + ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.YELLOW, Tile.YELLOW, Tile.YELLOW), + ResultFixture.createResults(Tile.GREEN, Tile.YELLOW, Tile.YELLOW, Tile.YELLOW, + Tile.YELLOW) + ); + } } \ No newline at end of file From 1158a12a369d640c4c0147d8d0ab853dc9ce29a0 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 16:51:53 +0900 Subject: [PATCH 38/60] =?UTF-8?q?fix(Record):=20existAllGreen,=20isCountOv?= =?UTF-8?q?er=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Record.java | 8 +++- src/test/java/wordle/domain/RecordTest.java | 47 +++++++++++++++++---- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/main/java/wordle/domain/Record.java b/src/main/java/wordle/domain/Record.java index 3cf57b61..0e9cf540 100644 --- a/src/main/java/wordle/domain/Record.java +++ b/src/main/java/wordle/domain/Record.java @@ -18,10 +18,14 @@ public void add(Results results) { } public boolean isEnd() { - return existAllGreen() || record.size() >= MAX_COUNT; + return existAllGreen() || isCountOver(); } - private boolean existAllGreen() { + public boolean isCountOver() { + return record.size() >= MAX_COUNT; + } + + public boolean existAllGreen() { if (record.isEmpty()) { return false; } diff --git a/src/test/java/wordle/domain/RecordTest.java b/src/test/java/wordle/domain/RecordTest.java index 9a175891..a0c1e595 100644 --- a/src/test/java/wordle/domain/RecordTest.java +++ b/src/test/java/wordle/domain/RecordTest.java @@ -2,29 +2,60 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import wordle.fixture.ResultFixture; public class RecordTest { @Test void Record에_초록색타일_5개_인_결과모음이_있으면_종료여부가_true이다() { - Record record = new Record(); - - record.add(ResultFixture.createGreenResults(5)); + Record record = createAllGreenRecord(); - assertThat(record.isEnd()).isTrue(); + assertThat(record.existAllGreen()).isTrue(); } @Test void Record가_결과모음이_6개이상이면_종료여부가_true이다() { + Record record = createAllGrayRecord(); + + assertThat(record.isCountOver()).isTrue(); + } + + @ParameterizedTest + @MethodSource("provideRecord") + void Record가_5개_인_결과모음이_있거나_결과모음이_6개이상이면_종료여부가_true이다(Record record) { + assertThat(record.isEnd()).isTrue(); + } + + private static Stream provideRecord() { + return Stream.of( + createAllGreenRecord(), + createAllGrayRecord() + ); + } + + private static Record createAllGreenRecord() { + Record record = new Record(); + + record.add(ResultFixture.createGreenResults(5)); + return record; + } + + private static Record createAllGrayRecord() { Record record = new Record(); for (int i = 0; i < Record.MAX_COUNT; i++) { - record.add(ResultFixture.createResults(Tile.GRAY, Tile.GRAY, Tile.GRAY, Tile.GRAY, - Tile.GRAY)); + record.add(ResultFixture.createResults( + Tile.GRAY, + Tile.GRAY, + Tile.GRAY, + Tile.GRAY, + Tile.GRAY) + ); } - - assertThat(record.isEnd()).isTrue(); + return record; } } From cc4afbf3e1692db9616aff39d54cc276198e5340 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 16:52:15 +0900 Subject: [PATCH 39/60] =?UTF-8?q?feat(Wordle):=20=EA=B2=8C=EC=9E=84?= =?UTF-8?q?=EC=99=84=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/Application.java | 16 ++++- src/main/java/wordle/application/Wordle.java | 68 ++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/main/java/wordle/application/Wordle.java diff --git a/src/main/java/wordle/Application.java b/src/main/java/wordle/Application.java index 13b664cb..96b964a2 100644 --- a/src/main/java/wordle/Application.java +++ b/src/main/java/wordle/Application.java @@ -1,7 +1,21 @@ package wordle; +import wordle.application.Wordle; +import wordle.domain.FileWordBook; +import wordle.domain.WordBook; +import wordle.infra.FileReader; +import wordle.ui.ConsoleInputView; +import wordle.ui.ConsoleOutputView; +import wordle.ui.InputView; +import wordle.ui.OutputView; + public class Application { + public static void main(String[] args) { - // TODO: 프로그램 구현 + WordBook wordBook = new FileWordBook(new FileReader()); + InputView inputView = new ConsoleInputView(); + OutputView outputView = new ConsoleOutputView(); + Wordle wordle = new Wordle(wordBook, inputView, outputView); + wordle.startGame(); } } diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java new file mode 100644 index 00000000..c51b0964 --- /dev/null +++ b/src/main/java/wordle/application/Wordle.java @@ -0,0 +1,68 @@ +package wordle.application; + +import wordle.domain.AnswerFormula; +import wordle.domain.BaseAnswerFormula; +import wordle.domain.Record; +import wordle.domain.Results; +import wordle.domain.Word; +import wordle.domain.WordBook; +import wordle.ui.InputView; +import wordle.ui.OutputView; + +public class Wordle { + + private final WordBook wordBook; + + private final InputView inputView; + + private final OutputView outputView; + + private final Record record; + + private final AnswerFormula answerFormula; + + public Wordle(WordBook wordBook, InputView inputView, OutputView outputView) { + this.wordBook = wordBook; + this.inputView = inputView; + this.outputView = outputView; + this.record = new Record(); + this.answerFormula = new BaseAnswerFormula(); + } + + public void startGame() { + Word answerWord = wordBook.pick(answerFormula); + outputView.welcome(); + runGame(answerWord); + concludeGame(); + } + + private void runGame(Word answerWord) { + while (!record.isEnd()) { + outputView.showRecord(record); + handleWrongAnswer(() -> processTurn(answerWord)); + } + } + + private void processTurn(Word answerWord) { + outputView.askAnswer(); + Word inputWord = wordBook.find(inputView.input()); + Results results = answerWord.compare(inputWord); + record.add(results); + } + + private void concludeGame() { + if (record.existAllGreen()) { + outputView.successEnd(record); + return; + } + outputView.failEnd(record); + } + + private void handleWrongAnswer(Runnable runnable) { + try { + runnable.run(); + } catch (Exception e) { + outputView.wrongAnswer(); + } + } +} From 8e397f01229f64239ef5e973297fb30b977cc735 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 15 Jun 2024 17:01:32 +0900 Subject: [PATCH 40/60] =?UTF-8?q?fix(Exception):=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 게임 비정상적 종료 처리 추가 --- src/main/java/wordle/application/Wordle.java | 6 +++++- src/main/java/wordle/domain/Word.java | 4 ++-- src/main/java/wordle/exception/AnswerFormulaException.java | 2 +- src/main/java/wordle/exception/FileReadFailException.java | 2 +- .../java/wordle/exception/InvalidAlphabetException.java | 2 +- .../java/wordle/exception/InvalidPositionException.java | 2 +- src/main/java/wordle/exception/InvalidWordException.java | 5 +++++ .../java/wordle/exception/WordInputNotValidException.java | 5 ----- src/main/java/wordle/exception/WordNotExistException.java | 2 +- src/main/java/wordle/exception/WordleException.java | 5 +++++ .../java/wordle/exception/WordleInvalidInputException.java | 5 +++++ src/main/java/wordle/ui/ConsoleOutputView.java | 7 ++++++- src/main/java/wordle/ui/OutputView.java | 2 ++ src/test/java/wordle/domain/WordTest.java | 4 ++-- 14 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 src/main/java/wordle/exception/InvalidWordException.java delete mode 100644 src/main/java/wordle/exception/WordInputNotValidException.java create mode 100644 src/main/java/wordle/exception/WordleException.java create mode 100644 src/main/java/wordle/exception/WordleInvalidInputException.java diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index c51b0964..7d0f3eba 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -6,6 +6,8 @@ import wordle.domain.Results; import wordle.domain.Word; import wordle.domain.WordBook; +import wordle.exception.WordleException; +import wordle.exception.WordleInvalidInputException; import wordle.ui.InputView; import wordle.ui.OutputView; @@ -61,8 +63,10 @@ private void concludeGame() { private void handleWrongAnswer(Runnable runnable) { try { runnable.run(); - } catch (Exception e) { + } catch (WordleInvalidInputException e) { outputView.wrongAnswer(); + } catch (WordleException e){ + outputView.unexpectedEnd(); } } } diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index 8da351a3..764799a0 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -4,7 +4,7 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; -import wordle.exception.WordInputNotValidException; +import wordle.exception.InvalidWordException; public class Word implements Iterable { @@ -13,7 +13,7 @@ public class Word implements Iterable { public Word(String input) { if (input.length() != WORD_LENGTH) { - throw new WordInputNotValidException(); + throw new InvalidWordException(); } this.letters = new ArrayList<>(); diff --git a/src/main/java/wordle/exception/AnswerFormulaException.java b/src/main/java/wordle/exception/AnswerFormulaException.java index 680f2b42..e8678668 100644 --- a/src/main/java/wordle/exception/AnswerFormulaException.java +++ b/src/main/java/wordle/exception/AnswerFormulaException.java @@ -1,5 +1,5 @@ package wordle.exception; -public class AnswerFormulaException extends IllegalArgumentException { +public class AnswerFormulaException extends WordleException { } diff --git a/src/main/java/wordle/exception/FileReadFailException.java b/src/main/java/wordle/exception/FileReadFailException.java index 3df46a99..5f19fbfb 100644 --- a/src/main/java/wordle/exception/FileReadFailException.java +++ b/src/main/java/wordle/exception/FileReadFailException.java @@ -1,5 +1,5 @@ package wordle.exception; -public class FileReadFailException extends RuntimeException { +public class FileReadFailException extends WordleException { } diff --git a/src/main/java/wordle/exception/InvalidAlphabetException.java b/src/main/java/wordle/exception/InvalidAlphabetException.java index e05814bf..5e424335 100644 --- a/src/main/java/wordle/exception/InvalidAlphabetException.java +++ b/src/main/java/wordle/exception/InvalidAlphabetException.java @@ -1,5 +1,5 @@ package wordle.exception; -public class InvalidAlphabetException extends IllegalArgumentException { +public class InvalidAlphabetException extends WordleInvalidInputException { } diff --git a/src/main/java/wordle/exception/InvalidPositionException.java b/src/main/java/wordle/exception/InvalidPositionException.java index d3bf0797..893a164f 100644 --- a/src/main/java/wordle/exception/InvalidPositionException.java +++ b/src/main/java/wordle/exception/InvalidPositionException.java @@ -1,5 +1,5 @@ package wordle.exception; -public class InvalidPositionException extends IllegalArgumentException { +public class InvalidPositionException extends WordleInvalidInputException { } diff --git a/src/main/java/wordle/exception/InvalidWordException.java b/src/main/java/wordle/exception/InvalidWordException.java new file mode 100644 index 00000000..326c7eaa --- /dev/null +++ b/src/main/java/wordle/exception/InvalidWordException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class InvalidWordException extends WordleInvalidInputException { + +} diff --git a/src/main/java/wordle/exception/WordInputNotValidException.java b/src/main/java/wordle/exception/WordInputNotValidException.java deleted file mode 100644 index 0a064d50..00000000 --- a/src/main/java/wordle/exception/WordInputNotValidException.java +++ /dev/null @@ -1,5 +0,0 @@ -package wordle.exception; - -public class WordInputNotValidException extends IllegalArgumentException { - -} diff --git a/src/main/java/wordle/exception/WordNotExistException.java b/src/main/java/wordle/exception/WordNotExistException.java index 275d9465..b9e0c9c2 100644 --- a/src/main/java/wordle/exception/WordNotExistException.java +++ b/src/main/java/wordle/exception/WordNotExistException.java @@ -1,5 +1,5 @@ package wordle.exception; -public class WordNotExistException extends RuntimeException { +public class WordNotExistException extends WordleInvalidInputException { } diff --git a/src/main/java/wordle/exception/WordleException.java b/src/main/java/wordle/exception/WordleException.java new file mode 100644 index 00000000..9fded22d --- /dev/null +++ b/src/main/java/wordle/exception/WordleException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class WordleException extends RuntimeException { + +} diff --git a/src/main/java/wordle/exception/WordleInvalidInputException.java b/src/main/java/wordle/exception/WordleInvalidInputException.java new file mode 100644 index 00000000..5c997b2e --- /dev/null +++ b/src/main/java/wordle/exception/WordleInvalidInputException.java @@ -0,0 +1,5 @@ +package wordle.exception; + +public class WordleInvalidInputException extends WordleException{ + +} diff --git a/src/main/java/wordle/ui/ConsoleOutputView.java b/src/main/java/wordle/ui/ConsoleOutputView.java index d7300ae3..84cbac2e 100644 --- a/src/main/java/wordle/ui/ConsoleOutputView.java +++ b/src/main/java/wordle/ui/ConsoleOutputView.java @@ -53,6 +53,11 @@ public void failEnd(Record record) { @Override public void wrongAnswer() { - System.out.println("존재하지 않는 단어입니다."); + System.out.println("올바르지 않은 단어입니다."); + } + + @Override + public void unexpectedEnd() { + System.out.println("비정상적으로 게임이 종료되었습니다."); } } diff --git a/src/main/java/wordle/ui/OutputView.java b/src/main/java/wordle/ui/OutputView.java index 2a973888..acdcd281 100644 --- a/src/main/java/wordle/ui/OutputView.java +++ b/src/main/java/wordle/ui/OutputView.java @@ -15,4 +15,6 @@ public interface OutputView { void failEnd(Record record); void wrongAnswer(); + + void unexpectedEnd(); } diff --git a/src/test/java/wordle/domain/WordTest.java b/src/test/java/wordle/domain/WordTest.java index 31b3f819..f5fb8111 100644 --- a/src/test/java/wordle/domain/WordTest.java +++ b/src/test/java/wordle/domain/WordTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import wordle.exception.WordInputNotValidException; +import wordle.exception.InvalidWordException; import wordle.fixture.ResultFixture; public class WordTest { @@ -21,7 +21,7 @@ public class WordTest { @ValueSource(strings = {"test", "testss"}) void Word를_생성할_때_다섯글자가_아니면_실패한다(String input) { assertThatThrownBy(() -> new Word(input)) - .isInstanceOf(WordInputNotValidException.class); + .isInstanceOf(InvalidWordException.class); } @Test From 5f37a113033c0b5447685cfae1705be62de6ce1e Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 16 Jun 2024 00:04:11 +0900 Subject: [PATCH 41/60] =?UTF-8?q?feat(FileReader):=20FileReader=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resource 밑에 있는 파일을 읽어온다 --- src/main/java/wordle/domain/Word.java | 78 +++++++++++++++------------ 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index 764799a0..c2d4ff16 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -4,12 +4,13 @@ import java.util.Iterator; import java.util.List; import java.util.Objects; +import java.util.function.Predicate; import wordle.exception.InvalidWordException; public class Word implements Iterable { public static final int WORD_LENGTH = 5; - private List letters; + private final List letters; public Word(String input) { if (input.length() != WORD_LENGTH) { @@ -24,51 +25,60 @@ public Word(String input) { } public Results compare(Word inputWord) { - boolean[] visit = new boolean[WORD_LENGTH]; + WordComparator wordComparator = new WordComparator(this.letters); + return wordComparator.compare(inputWord); + } - Results results = new Results(); - for (Letter letter : inputWord) { - Result green = findGreen(letter, visit); - if (green != null) { - results.add(green); - } + static class WordComparator { + + private final List pendingLetters; + private final Results results; + + public WordComparator(List letters) { + this.pendingLetters = new ArrayList<>(letters); + this.results = new Results(); } - for (Letter letter : inputWord) { - Result yellow = findYellow(letter, visit); - if (yellow != null) { - results.add(yellow); - } else { - results.add(new Result(Tile.GRAY, letter.getPosition())); + public Results compare(Word inputWord) { + for (Letter letter : inputWord) { + process(letter, letter::equals, Tile.GREEN); } - } - return results; - } + for (Letter letter : inputWord) { + process(letter, letter::isSameAlphabet, Tile.YELLOW); + } - private Result findYellow(Letter targetLetter, boolean[] visit) { - for (int i = 0; i < this.letters.size(); i++) { - Letter letter = this.letters.get(i); - if(visit[i]){ - continue; + for (Letter letter : inputWord) { + fillEmptyToGray(letter); } - if (letter.isSameAlphabet(targetLetter)) { - visit[i] = true; - return new Result(Tile.YELLOW, targetLetter.getPosition()); + + return results; + } + + private void process(Letter targetLetter, Predicate predicate, Tile tile) { + Position position = targetLetter.getPosition(); + if (results.isCheckedPosition(position)) { + return; } + + pendingLetters.stream() + .filter(predicate) + .findFirst() + .ifPresent(letter -> { + pendingLetters.remove(letter); + results.add(new Result(tile, position)); + }); } - return null; - } - private Result findGreen(Letter targetLetter, boolean[] visit) { - for (int i = 0; i < this.letters.size(); i++) { - Letter letter = this.letters.get(i); - if (letter.equals(targetLetter)) { - visit[i] = true; - return new Result(Tile.GREEN, targetLetter.getPosition()); + private void fillEmptyToGray(Letter targetLetter) { + Position position = targetLetter.getPosition(); + if (results.isCheckedPosition(position)) { + return; } + + pendingLetters.forEach( + letter -> results.add(new Result(Tile.GRAY, position))); } - return null; } @Override From 609a398d8b16793e1ce0d08fa8604d226c0d1ea1 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 17 Jun 2024 21:11:43 +0900 Subject: [PATCH 42/60] =?UTF-8?q?refactor(Word):=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 안쓰는 메서드 정리 및 포맷 맞추기 --- src/main/java/wordle/application/Wordle.java | 2 +- src/main/java/wordle/domain/Position.java | 6 +----- src/main/java/wordle/domain/Result.java | 11 +++-------- src/main/java/wordle/domain/Word.java | 2 +- .../wordle/exception/WordleInvalidInputException.java | 2 +- src/test/java/wordle/ui/ConsoleOutputViewTest.java | 4 ++-- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index 7d0f3eba..0c55e48f 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -65,7 +65,7 @@ private void handleWrongAnswer(Runnable runnable) { runnable.run(); } catch (WordleInvalidInputException e) { outputView.wrongAnswer(); - } catch (WordleException e){ + } catch (WordleException e) { outputView.unexpectedEnd(); } } diff --git a/src/main/java/wordle/domain/Position.java b/src/main/java/wordle/domain/Position.java index ad4b88f1..11c6394e 100644 --- a/src/main/java/wordle/domain/Position.java +++ b/src/main/java/wordle/domain/Position.java @@ -9,7 +9,7 @@ public class Position implements Comparable { private final int position; public Position(int position) { - if(position < MIN_POSITION){ + if (position < MIN_POSITION) { throw new InvalidPositionException(); } @@ -33,10 +33,6 @@ public int hashCode() { return Objects.hash(position); } - public boolean notEquals(Position position) { - return !equals(position); - } - public int compareTo(Position position) { return Integer.compare(this.position, position.position); } diff --git a/src/main/java/wordle/domain/Result.java b/src/main/java/wordle/domain/Result.java index aade37e3..f27600cd 100644 --- a/src/main/java/wordle/domain/Result.java +++ b/src/main/java/wordle/domain/Result.java @@ -3,6 +3,7 @@ import java.util.Objects; public class Result implements Comparable { + private final Tile tile; private final Position position; @@ -32,14 +33,6 @@ public int hashCode() { return Objects.hash(tile, position); } - @Override - public String toString() { - return "Result{" + - "tile=" + tile + - ", position=" + position + - '}'; - } - public boolean isSamePosition(Position position) { return this.position.equals(position); } @@ -52,9 +45,11 @@ public int compareTo(Result o) { public boolean isGreen() { return this.tile == Tile.GREEN; } + public boolean isYellow() { return this.tile == Tile.YELLOW; } + public boolean isGray() { return this.tile == Tile.GRAY; } diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index c2d4ff16..c8dcbaa2 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -54,7 +54,7 @@ public Results compare(Word inputWord) { return results; } - + private void process(Letter targetLetter, Predicate predicate, Tile tile) { Position position = targetLetter.getPosition(); if (results.isCheckedPosition(position)) { diff --git a/src/main/java/wordle/exception/WordleInvalidInputException.java b/src/main/java/wordle/exception/WordleInvalidInputException.java index 5c997b2e..a6608381 100644 --- a/src/main/java/wordle/exception/WordleInvalidInputException.java +++ b/src/main/java/wordle/exception/WordleInvalidInputException.java @@ -1,5 +1,5 @@ package wordle.exception; -public class WordleInvalidInputException extends WordleException{ +public class WordleInvalidInputException extends WordleException { } diff --git a/src/test/java/wordle/ui/ConsoleOutputViewTest.java b/src/test/java/wordle/ui/ConsoleOutputViewTest.java index 1c772ea3..5f7ecc85 100644 --- a/src/test/java/wordle/ui/ConsoleOutputViewTest.java +++ b/src/test/java/wordle/ui/ConsoleOutputViewTest.java @@ -21,7 +21,7 @@ class ConsoleOutputViewTest { private ConsoleOutputView consoleOutputView; @BeforeEach - protected final void init() { + void init() { standardOut = System.out; captor = new ByteArrayOutputStream(); consoleOutputView = new ConsoleOutputView(); @@ -29,7 +29,7 @@ protected final void init() { } @AfterEach - protected final void printOutput() { + void printOutput() { System.setOut(standardOut); } From 7e5879748733b5a10d4d487eaf4c7f8771d8351a Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 17 Jun 2024 21:21:34 +0900 Subject: [PATCH 43/60] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4(word.text)=EB=B0=8F=20=EC=BC=80=EC=9D=B4?= =?UTF-8?q?=EC=8A=A4=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/wordle/domain/FileWordBookTest.java | 4 ++-- src/test/java/wordle/infra/FileReaderTest.java | 2 +- src/test/resources/words.txt | 7 +++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java index a5d9a7b8..ba404f11 100644 --- a/src/test/java/wordle/domain/FileWordBookTest.java +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -29,12 +29,12 @@ void setUp() { @Test void WordBook에서_공식을_통해_오늘의_정답_단어를_뽑는다() { Word actual = wordBook.pick((wordCount) -> 0); - assertThat(actual).isEqualTo(new Word("apple")); + assertThat(actual).isEqualTo(new Word("hello")); } @Test void WordBook에서_단어를_찾을_수_있다() { - Word word = wordBook.find("happy"); + Word word = wordBook.find("spill"); assertThat(word).isNotNull(); } diff --git a/src/test/java/wordle/infra/FileReaderTest.java b/src/test/java/wordle/infra/FileReaderTest.java index 86183747..e66e3203 100644 --- a/src/test/java/wordle/infra/FileReaderTest.java +++ b/src/test/java/wordle/infra/FileReaderTest.java @@ -24,7 +24,7 @@ public void setUp() { void FileReader로_텍스트파일을_읽어온다() { List textList = fileReader.readByLine("words.txt"); - assertThat(textList).containsExactly("apple","hello","abcde","spike","happy"); + assertThat(textList).containsExactly("hello","label","spell","spill"); } @ParameterizedTest diff --git a/src/test/resources/words.txt b/src/test/resources/words.txt index b880e6bf..71650431 100644 --- a/src/test/resources/words.txt +++ b/src/test/resources/words.txt @@ -1,5 +1,4 @@ -apple hello -abcde -spike -happy \ No newline at end of file +label +spell +spill From a678cd3dfa8bb99b14ee50d4289fd6d13719d9fa Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 17 Jun 2024 22:10:40 +0900 Subject: [PATCH 44/60] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - final 변수 생성 및 메서드 정리 --- src/main/java/wordle/domain/Alphabet.java | 4 +++- src/main/java/wordle/domain/FileWordBook.java | 3 ++- src/main/java/wordle/domain/Results.java | 9 ++------- src/main/java/wordle/ui/ConsoleOutputView.java | 11 +++++++---- src/test/java/wordle/domain/FileWordBookTest.java | 4 +++- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/java/wordle/domain/Alphabet.java b/src/main/java/wordle/domain/Alphabet.java index 3c948c7b..716d2a13 100644 --- a/src/main/java/wordle/domain/Alphabet.java +++ b/src/main/java/wordle/domain/Alphabet.java @@ -5,11 +5,13 @@ public class Alphabet { + private static final char MIN_ALPHABET = 'a'; + private static final char MAX_ALPHABET = 'z'; private final char alphabet; public Alphabet(char alphabet) { char lowerAlphabet = Character.toLowerCase(alphabet); - if (lowerAlphabet < 'a' || lowerAlphabet > 'z') { + if (lowerAlphabet < MIN_ALPHABET || lowerAlphabet > MAX_ALPHABET) { throw new InvalidAlphabetException(); } diff --git a/src/main/java/wordle/domain/FileWordBook.java b/src/main/java/wordle/domain/FileWordBook.java index 465533ae..b89439eb 100644 --- a/src/main/java/wordle/domain/FileWordBook.java +++ b/src/main/java/wordle/domain/FileWordBook.java @@ -6,10 +6,11 @@ public class FileWordBook implements WordBook { + public static final String FILE_PATH = "words.txt"; private final List words; public FileWordBook(FileReader fileReader) { - this.words = fileReader.readByLine("words.txt") + this.words = fileReader.readByLine(FILE_PATH) .stream() .map(Word::new) .toList(); diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java index 0b063b8b..c85698dd 100644 --- a/src/main/java/wordle/domain/Results.java +++ b/src/main/java/wordle/domain/Results.java @@ -22,13 +22,8 @@ public void add(Result result) { } public boolean isCheckedPosition(Position position) { - for (Result result : results) { - if (result.isSamePosition(position)) { - return true; - } - } - - return false; + return results.stream() + .anyMatch(result -> result.isSamePosition(position)); } public boolean isAllGreen() { diff --git a/src/main/java/wordle/ui/ConsoleOutputView.java b/src/main/java/wordle/ui/ConsoleOutputView.java index 84cbac2e..3eb4729f 100644 --- a/src/main/java/wordle/ui/ConsoleOutputView.java +++ b/src/main/java/wordle/ui/ConsoleOutputView.java @@ -20,15 +20,18 @@ public void askAnswer() { @Override public void showRecord(Record record) { for (Results results : record) { - for (Result result : results) { - String s = findTile(result); - System.out.print(s); - } + showResults(results); System.out.println(); } System.out.println(); } + private static void showResults(Results results) { + for (Result result : results) { + System.out.print(findTile(result)); + } + } + private static String findTile(Result result) { if (result.isGreen()) { return "🟩"; diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java index ba404f11..5f85d30c 100644 --- a/src/test/java/wordle/domain/FileWordBookTest.java +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; +import wordle.exception.WordNotExistException; import wordle.infra.FileReader; public class FileWordBookTest { @@ -41,6 +42,7 @@ void setUp() { @Test void WordBook에_없는_단어를_찾으면_예외를_던진다() { - assertThatThrownBy(() -> wordBook.find("ghost")); + assertThatThrownBy(() -> wordBook.find("ghost")) + .isInstanceOf(WordNotExistException.class); } } From d170631ae3f0e50ac7e9cb9d43ce98632782cae9 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 17 Jun 2024 22:11:44 +0900 Subject: [PATCH 45/60] =?UTF-8?q?test:=20=EC=BD=98=EC=86=94=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/wordle/ApplicationTest.java | 4 +-- .../java/wordle/ConsoleIntegrationTest.java | 34 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/test/java/wordle/ApplicationTest.java b/src/test/java/wordle/ApplicationTest.java index 0f811401..87894cf0 100644 --- a/src/test/java/wordle/ApplicationTest.java +++ b/src/test/java/wordle/ApplicationTest.java @@ -8,8 +8,8 @@ class ApplicationTest extends ConsoleIntegrationTest { @Test void 게임_정상_진행_테스트() { - run("hello", "label", "spell", "spill"); - assertThat(output()).contains( + run("hello", "12345" ,"label", "spell", "spill"); + assertThat(output()).containsIgnoringWhitespaces( """ ⬜⬜🟨🟩⬜ """, diff --git a/src/test/java/wordle/ConsoleIntegrationTest.java b/src/test/java/wordle/ConsoleIntegrationTest.java index bbe78caa..c5fdec92 100644 --- a/src/test/java/wordle/ConsoleIntegrationTest.java +++ b/src/test/java/wordle/ConsoleIntegrationTest.java @@ -1,15 +1,24 @@ package wordle; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.mockito.Mockito.mockStatic; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.io.PrintStream; -import java.util.NoSuchElementException; +import java.time.Duration; +import java.time.LocalDate; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.function.Executable; +import org.mockito.MockedStatic; +import org.mockito.Mockito; public abstract class ConsoleIntegrationTest { + + private static final LocalDate ANSWER_DATE = LocalDate.parse("2021-06-22"); + public static final long TIME_LIMIT = 10L; private PrintStream standardOut; private OutputStream captor; @@ -31,15 +40,20 @@ protected final String output() { } protected final void run(final String... args) { - command(args); - runMain(); + assertTimeTest(() -> { + try (MockedStatic localDateMockedStatic = mockStatic(LocalDate.class, + Mockito.CALLS_REAL_METHODS)) { + localDateMockedStatic.when(LocalDate::now).thenReturn(ANSWER_DATE); + command(args); + runMain(); + } catch (final Exception e) { + e.printStackTrace(); + } + }); } - protected final void runException(final String... args) { - try { - run(args); - } catch (final NoSuchElementException ignore) { - } + private void assertTimeTest(Executable executable) { + assertTimeoutPreemptively(Duration.ofSeconds(TIME_LIMIT), executable); } private void command(final String... args) { From 261dbd53a00979de1cc309c3c2ca7bbc2587b97e Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 17 Jun 2024 22:12:05 +0900 Subject: [PATCH 46/60] =?UTF-8?q?docs:=20=EB=A6=AC=EB=93=9C=EB=AF=B8=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 용어 사전 수정 및 클래스 다이어그램 수정 --- docs/README.md | 142 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 100 insertions(+), 42 deletions(-) diff --git a/docs/README.md b/docs/README.md index e1460310..912a2dac 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,29 +19,32 @@ ## 용어 사전 -| 한글명 | 영문명 | 설명 | -|--------|----------------|-----------------------------------------------| -| 워들 | Wordle | 5글자 영어 단어 맞추기 게임 | -| 단어장 | Word Book | 이 게임에서 사용될 수 있는 단어 모음 | -| 입력 단어 | Input Word | 플레이어가 입력하는 5글자 단어 | -| 정답 단어 | Answer Word | 오늘 게임의 정답인 5글자 단어 | -| 글자 | Letter | 단어를 구성하는 알파벳 | -| 위치 | Position | 단어를 구성하는 글자의 위치 | -| 플레이어 | Player | 게임에 참여하는 사용자 | -| 결과 | Result | 입력단어와 정답단어를 비교해서 표현되는 타일모음 | -| 비교 | Compare | 입력단어와 정답단어의 글자와 위치를 비교하는 행위 | -| 초록색 타일 | Green Tile | 글자와 위치가 동일한 경우 표현되는 타일 | -| 노란색 타일 | Yellow Tile | 글자는 포함되지만 위치가 다른 경우 표현되는 타일 | -| 회색 타일 | Gray Tile | 글자와 위치가 모두 다른 경우 표현되는 타일 | -| 라운드 | Round | 플레이어가 단어를 입력하는 횟수(6회) | -| 결과모음 | Results | 라운드가 진행될 때 마다 누적된 결과모음 | -| 기준일 | Base Date | 오늘의 정답 단어를 계산하는 기준일(2021년 6월 19일) | +| 한글명 | 영문명 | 설명 | +|--------|----------------|------------------------------------------------| +| 워들 | Wordle | 5글자 영어 단어 맞추기 게임 | +| 단어장 | Word Book | 이 게임에서 사용될 수 있는 단어 모음 | +| 입력 단어 | Input Word | 플레이어가 입력하는 5글자 단어 | +| 정답 단어 | Answer Word | 오늘 게임의 정답인 5글자 단어 | +| 글자 | Letter | 단어를 구성하는 알파벳 | +| 영문 | Alphabet | 글자를 구성하는 최소단위 | +| 위치 | Position | 단어를 구성하는 글자의 위치 | +| 플레이어 | Player | 게임에 참여하는 사용자 | +| 결과 | Result | 입력단어와 정답단어를 비교해서 표현되는 타일모음 | +| 비교 | Compare | 입력단어와 정답단어의 글자와 위치를 비교하는 행위 | +| 초록색 타일 | Green Tile | 글자와 위치가 동일한 경우 표현되는 타일 | +| 노란색 타일 | Yellow Tile | 글자는 포함되지만 위치가 다른 경우 표현되는 타일 | +| 회색 타일 | Gray Tile | 글자와 위치가 모두 다른 경우 표현되는 타일 | +| 결과모음 | Results | 라운드가 진행될 때 마다 누적된 결과모음 | +| 기록모음 | Record | 누적된 결과모음의 기록 | +| 기준일 | Base Date | 오늘의 정답 단어를 계산하는 기준일(2021년 6월 19일) | | 정답 공식 | Answer Formula | 오늘의 정답 단어를 계산하는 공식 `(현재 날짜 - 기준일) % 단어장의 단어 수` | -| 시작 | Start | 플레이어가 워들을 시작하는 행위 | -| 종료 | End | 워들이 종료되는 행위(라운드가 전부 끝났거나, 그 전에 정답을 맞추면 종료된다) | +| 시작 | Start | 플레이어가 워들을 시작하는 행위 | +| 종료 | End | 워들이 종료되는 행위(라운드가 전부 끝났거나, 그 전에 정답을 맞추면 종료된다) | ## 모델링 + ### 클래스 다이어그램 + ```mermaid --- title: Wordle @@ -49,53 +52,108 @@ title: Wordle classDiagram class Word { -List letters - +compare(Word word) Results - -compare(Letter letter) Result + +compare(Word inputWord) Results + +equals(Object o) boolean } - class Letter{ - -char alphabet + + class WordComparator { + -List pendingLetters + -Results results + +WordComparator(letters: List) + +compare(inputWord: Word): Results + -process(targetLetter: Letter, predicate: Predicate, tile: Tile) + -fillEmptyToGray(targetLetter: Letter) + } + + Word --|> WordComparator + + class Letter { + -Alphabet alphabet -Position position - +equals(Letter letter) boolean - +isSameAlphabetDifferentPosition(Letter letter) boolean + +isSameAlphabet(Letter letter) boolean + +getPosition() Position + +equals(Object o) boolean + } + + class Alphabet { + -char alphabet + +equals(Object o) boolean + } + + class Position { + -char position + +compareTo(Position position) boolean + +equals(Object o) boolean + } + + class Record { + -List record + +add(Results results) void + +isEnd() boolean + +isCountOver() boolean + +existAllGreen() boolean + +iterator() Iterator + +size() int } class Results { - -Result[] results + -SortedSet results +add(Result result) void +isCheckedPosition(Position position) boolean + +isAllGreen() boolean } class Result { -Tile tile -Position poistion + +isSamePosition(Position position) boolean + +equals(Object o) boolean + +compareTo(Result result) int + +isGreen() boolean + +isYellow() boolean + +isGray() boolean } - class IWordComparable { - +compare(Word word) Results + class Tile { + <> + +GREEN + +YELLOW + +GRAY } - class ETile { - -TileType type + class AnswerFormula { + <> + +calculate(int wordCount) int } - class AnswerFormula{ - -Date baseDate - +calculate() + class BaseAnswerFormula { + +calculate(int wordCount) int } + BaseAnswerFormula ..|> AnswerFormula class Wordle { -WordBook wordBook - -Results results - -Round round - +start() + -InputView inputView + -OutputView outputView + -Record record + -AnswerFormula answerFormula + +startGame() void + -runGame(Word answerWord) void + -processTurn(Word answerWord) void + -concludeGame() void + -handleWrongAnswer(Runnable runnable) void } class WordBook { - -List wordBook + <> +pick(AnswerFormula formula) Word - +exist(Word inputWord) boolean + +exist(Word word) boolean + +find(String target) Word } - class Round { - -final int ROUND = 6; - -int curruntRound; - +isEnd() boolean + class FileWordBook { + -List words + +pick(AnswerFormula formula) Word + +exist(Word word) boolean + +find(String target) Word } + FileWordBook ..|> WordBook ``` ## 🚀 세부 요구 사항 + - 6x5 격자를 통해서 5글자 단어를 6번 만에 추측한다. - 플레이어가 답안을 제출하면 프로그램이 정답과 제출된 단어의 각 알파벳 종류와 위치를 비교해 판별한다. - 판별 결과는 흰색의 타일이 세 가지 색(초록색/노란색/회색) 중 하나로 바뀌면서 표현된다. From 3d52104a641da38b7b7ae564f7649b400a332820 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 29 Jun 2024 23:26:53 +0900 Subject: [PATCH 47/60] =?UTF-8?q?docs:=20=EA=B2=8C=EC=9E=84=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=20=EC=88=9C=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 같은 문자 2개 -> n개 --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 912a2dac..289ea406 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,7 @@ - 입력받은 문자와 정답을 비교한다. - 비교 결과는 타일이 초록색/노란색/회색 중 하나로 바뀌면서 표현된다. - 맞는 글자는 초록색, 위치가 틀리면 노란색, 없으면 회색 - - 같은 문자가 2개 입력되었을 때, 해당 문자가 정답에 하나만 존재하지만 위치가 틀린 경우 첫번 째 문자만 노란색으로 표시된다. + - 같은 문자가 n개 입력되었을 때, 해당 문자가 정답에 하나만 존재하지만 위치가 틀린 경우 첫번 째 문자만 노란색으로 표시된다. - 정답: lurid, 입력: hello, 결과: ⬜⬜🟨⬜⬜ - 6번 안에 맞추면 게임을 종료한다. - 6번 안에 맞추지 못하면 그래도 종료한다. From f09f3c27187fe3214189d722fd514dcfed6181a8 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 29 Jun 2024 23:48:03 +0900 Subject: [PATCH 48/60] =?UTF-8?q?refactor(Record):=20existAllGreen=20->=20?= =?UTF-8?q?existAnswer=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 뷰에 의존적인 메서드명 수정 --- src/main/java/wordle/domain/Record.java | 7 ++++--- src/test/java/wordle/domain/RecordTest.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/wordle/domain/Record.java b/src/main/java/wordle/domain/Record.java index 0e9cf540..4c43a6dd 100644 --- a/src/main/java/wordle/domain/Record.java +++ b/src/main/java/wordle/domain/Record.java @@ -18,20 +18,21 @@ public void add(Results results) { } public boolean isEnd() { - return existAllGreen() || isCountOver(); + return existAnswer() || isCountOver(); } public boolean isCountOver() { return record.size() >= MAX_COUNT; } - public boolean existAllGreen() { + public boolean existAnswer() { if (record.isEmpty()) { return false; } + return record .getLast() - .isAllGreen(); + .isAnswer(); } @Override diff --git a/src/test/java/wordle/domain/RecordTest.java b/src/test/java/wordle/domain/RecordTest.java index a0c1e595..fe910f2b 100644 --- a/src/test/java/wordle/domain/RecordTest.java +++ b/src/test/java/wordle/domain/RecordTest.java @@ -14,7 +14,7 @@ public class RecordTest { void Record에_초록색타일_5개_인_결과모음이_있으면_종료여부가_true이다() { Record record = createAllGreenRecord(); - assertThat(record.existAllGreen()).isTrue(); + assertThat(record.existAnswer()).isTrue(); } @Test From 55f06094905b9d12f588b5e20cb98ee2a16ce32c Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sat, 29 Jun 2024 23:49:24 +0900 Subject: [PATCH 49/60] =?UTF-8?q?refactor(Results):=20isAllGreen=20->=20is?= =?UTF-8?q?Answer=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 뷰에 의존적인 메서드명 수정 --- src/main/java/wordle/application/Wordle.java | 2 +- src/main/java/wordle/domain/Results.java | 2 +- src/test/java/wordle/domain/ResultsTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index 0c55e48f..bb61678f 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -53,7 +53,7 @@ private void processTurn(Word answerWord) { } private void concludeGame() { - if (record.existAllGreen()) { + if (record.existAnswer()) { outputView.successEnd(record); return; } diff --git a/src/main/java/wordle/domain/Results.java b/src/main/java/wordle/domain/Results.java index c85698dd..49990c9f 100644 --- a/src/main/java/wordle/domain/Results.java +++ b/src/main/java/wordle/domain/Results.java @@ -26,7 +26,7 @@ public boolean isCheckedPosition(Position position) { .anyMatch(result -> result.isSamePosition(position)); } - public boolean isAllGreen() { + public boolean isAnswer() { return results.stream().allMatch(Result::isGreen); } } diff --git a/src/test/java/wordle/domain/ResultsTest.java b/src/test/java/wordle/domain/ResultsTest.java index a933899c..4bb9c29c 100644 --- a/src/test/java/wordle/domain/ResultsTest.java +++ b/src/test/java/wordle/domain/ResultsTest.java @@ -23,6 +23,6 @@ class ResultsTest { void Results_가_전부_초록색타일인지_알수있다() { Results results = ResultFixture.createGreenResults(5); - assertThat(results.isAllGreen()).isTrue(); + assertThat(results.isAnswer()).isTrue(); } } \ No newline at end of file From f8f42c40062b0569c2a63095d79f7fbd7c98e644 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Sun, 30 Jun 2024 02:27:48 +0900 Subject: [PATCH 50/60] =?UTF-8?q?refactor(FileWordBook):=20find=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B0=98=ED=99=98=20Optional?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/application/Wordle.java | 4 +++- src/main/java/wordle/domain/FileWordBook.java | 7 +++---- src/main/java/wordle/domain/WordBook.java | 4 +++- src/test/java/wordle/domain/FileWordBookTest.java | 8 +------- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index bb61678f..34e1dc89 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -6,6 +6,7 @@ import wordle.domain.Results; import wordle.domain.Word; import wordle.domain.WordBook; +import wordle.exception.WordNotExistException; import wordle.exception.WordleException; import wordle.exception.WordleInvalidInputException; import wordle.ui.InputView; @@ -47,7 +48,8 @@ private void runGame(Word answerWord) { private void processTurn(Word answerWord) { outputView.askAnswer(); - Word inputWord = wordBook.find(inputView.input()); + Word inputWord = wordBook.find(inputView.input()) + .orElseThrow(WordNotExistException::new); Results results = answerWord.compare(inputWord); record.add(results); } diff --git a/src/main/java/wordle/domain/FileWordBook.java b/src/main/java/wordle/domain/FileWordBook.java index b89439eb..78245852 100644 --- a/src/main/java/wordle/domain/FileWordBook.java +++ b/src/main/java/wordle/domain/FileWordBook.java @@ -1,7 +1,7 @@ package wordle.domain; import java.util.List; -import wordle.exception.WordNotExistException; +import java.util.Optional; import wordle.infra.FileReader; public class FileWordBook implements WordBook { @@ -28,11 +28,10 @@ public boolean exist(Word word) { } @Override - public Word find(String target) { + public Optional find(String target) { Word targetWord = new Word(target); return words.stream() .filter(targetWord::equals) - .findFirst() - .orElseThrow(WordNotExistException::new); + .findFirst(); } } diff --git a/src/main/java/wordle/domain/WordBook.java b/src/main/java/wordle/domain/WordBook.java index 136568f4..6e3d89f3 100644 --- a/src/main/java/wordle/domain/WordBook.java +++ b/src/main/java/wordle/domain/WordBook.java @@ -1,10 +1,12 @@ package wordle.domain; +import java.util.Optional; + public interface WordBook { Word pick(AnswerFormula answerFormula); boolean exist(Word word); - Word find(String word); + Optional find(String word); } diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java index 5f85d30c..d0c40959 100644 --- a/src/test/java/wordle/domain/FileWordBookTest.java +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -35,14 +35,8 @@ void setUp() { @Test void WordBook에서_단어를_찾을_수_있다() { - Word word = wordBook.find("spill"); + Word word = wordBook.find("spill").get(); assertThat(word).isNotNull(); } - - @Test - void WordBook에_없는_단어를_찾으면_예외를_던진다() { - assertThatThrownBy(() -> wordBook.find("ghost")) - .isInstanceOf(WordNotExistException.class); - } } From 690cae5ce8227ff615d7a1dc1192d08b08b6f7aa Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:04:35 +0900 Subject: [PATCH 51/60] =?UTF-8?q?refactor(Alphabet):=20=EC=95=8C=ED=8C=8C?= =?UTF-8?q?=EB=B2=B3=20=EC=98=88=EC=99=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Alphabet.java | 2 +- src/main/java/wordle/exception/InvalidAlphabetException.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/wordle/domain/Alphabet.java b/src/main/java/wordle/domain/Alphabet.java index 716d2a13..8960e65f 100644 --- a/src/main/java/wordle/domain/Alphabet.java +++ b/src/main/java/wordle/domain/Alphabet.java @@ -12,7 +12,7 @@ public class Alphabet { public Alphabet(char alphabet) { char lowerAlphabet = Character.toLowerCase(alphabet); if (lowerAlphabet < MIN_ALPHABET || lowerAlphabet > MAX_ALPHABET) { - throw new InvalidAlphabetException(); + throw new InvalidAlphabetException("올바르지 않은 알파벳입니다. (" + alphabet + ")"); } this.alphabet = lowerAlphabet; diff --git a/src/main/java/wordle/exception/InvalidAlphabetException.java b/src/main/java/wordle/exception/InvalidAlphabetException.java index 5e424335..2d92d7bf 100644 --- a/src/main/java/wordle/exception/InvalidAlphabetException.java +++ b/src/main/java/wordle/exception/InvalidAlphabetException.java @@ -2,4 +2,7 @@ public class InvalidAlphabetException extends WordleInvalidInputException { + public InvalidAlphabetException(String message) { + super(message); + } } From fc871a14e67f9c52e17089b95adb33c424986f87 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:05:40 +0900 Subject: [PATCH 52/60] =?UTF-8?q?refactor(AnswerFormula):=20=EC=A0=95?= =?UTF-8?q?=EB=8B=B5=20=EA=B3=B5=EC=8B=9D=20=EC=98=88=EC=99=B8=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/BaseAnswerFormula.java | 4 ++-- .../java/wordle/exception/AnswerFormulaException.java | 5 ----- .../wordle/exception/AnswerFormulaWordCountException.java | 8 ++++++++ src/test/java/wordle/domain/BaseAnswerFormulaTest.java | 4 ++-- 4 files changed, 12 insertions(+), 9 deletions(-) delete mode 100644 src/main/java/wordle/exception/AnswerFormulaException.java create mode 100644 src/main/java/wordle/exception/AnswerFormulaWordCountException.java diff --git a/src/main/java/wordle/domain/BaseAnswerFormula.java b/src/main/java/wordle/domain/BaseAnswerFormula.java index f130e190..fe9356f0 100644 --- a/src/main/java/wordle/domain/BaseAnswerFormula.java +++ b/src/main/java/wordle/domain/BaseAnswerFormula.java @@ -2,7 +2,7 @@ import java.time.LocalDate; import java.time.temporal.ChronoUnit; -import wordle.exception.AnswerFormulaException; +import wordle.exception.AnswerFormulaWordCountException; public class BaseAnswerFormula implements AnswerFormula { @@ -11,7 +11,7 @@ public class BaseAnswerFormula implements AnswerFormula { public int calculate(int wordCount) { if (wordCount < MIN_WORD_COUNT) { - throw new AnswerFormulaException(); + throw new AnswerFormulaWordCountException(); } return (int) ChronoUnit.DAYS.between(BASE, LocalDate.now()) % wordCount; diff --git a/src/main/java/wordle/exception/AnswerFormulaException.java b/src/main/java/wordle/exception/AnswerFormulaException.java deleted file mode 100644 index e8678668..00000000 --- a/src/main/java/wordle/exception/AnswerFormulaException.java +++ /dev/null @@ -1,5 +0,0 @@ -package wordle.exception; - -public class AnswerFormulaException extends WordleException { - -} diff --git a/src/main/java/wordle/exception/AnswerFormulaWordCountException.java b/src/main/java/wordle/exception/AnswerFormulaWordCountException.java new file mode 100644 index 00000000..535b4b5a --- /dev/null +++ b/src/main/java/wordle/exception/AnswerFormulaWordCountException.java @@ -0,0 +1,8 @@ +package wordle.exception; + +public class AnswerFormulaWordCountException extends WordleException { + + public AnswerFormulaWordCountException() { + super("계산을 위해서 단어는 1글자 이상이어야 합니다."); + } +} diff --git a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java index 5db7ac17..f2822b8b 100644 --- a/src/test/java/wordle/domain/BaseAnswerFormulaTest.java +++ b/src/test/java/wordle/domain/BaseAnswerFormulaTest.java @@ -7,7 +7,7 @@ import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import wordle.TimeTestSupporter; -import wordle.exception.AnswerFormulaException; +import wordle.exception.AnswerFormulaWordCountException; public class BaseAnswerFormulaTest { @@ -29,6 +29,6 @@ public class BaseAnswerFormulaTest { BaseAnswerFormula answerFormula = new BaseAnswerFormula(); assertThatThrownBy(() -> answerFormula.calculate(wordCount)) - .isInstanceOf(AnswerFormulaException.class); + .isInstanceOf(AnswerFormulaWordCountException.class); } } From 31cf9d0e7e9ae7de49a82fb603cb56e873c470e2 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:19:13 +0900 Subject: [PATCH 53/60] =?UTF-8?q?refactor(FileReader):=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9D=BD=EA=B8=B0=20=EC=8B=A4=ED=8C=A8=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/exception/FileReadFailException.java | 3 +++ src/main/java/wordle/infra/FileReader.java | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/wordle/exception/FileReadFailException.java b/src/main/java/wordle/exception/FileReadFailException.java index 5f19fbfb..6489244c 100644 --- a/src/main/java/wordle/exception/FileReadFailException.java +++ b/src/main/java/wordle/exception/FileReadFailException.java @@ -2,4 +2,7 @@ public class FileReadFailException extends WordleException { + public FileReadFailException(String message) { + super(message); + } } diff --git a/src/main/java/wordle/infra/FileReader.java b/src/main/java/wordle/infra/FileReader.java index acd52c97..7f1d4927 100644 --- a/src/main/java/wordle/infra/FileReader.java +++ b/src/main/java/wordle/infra/FileReader.java @@ -12,21 +12,21 @@ public class FileReader { public List readByLine(String filePath) { if (filePath == null || filePath.isBlank()) { - throw new FileReadFailException(); + throw new FileReadFailException("파일 경로가 비었습니다."); } try { URL systemResource = getUrl(filePath); return Files.lines(Path.of(systemResource.toURI())).toList(); } catch (IOException | URISyntaxException e) { - throw new FileReadFailException(); + throw new FileReadFailException("올바르지 않은 파일입니다. ("+ filePath +")"); } } private URL getUrl(String filePath) { URL systemResource = ClassLoader.getSystemResource(filePath); if (systemResource == null) { - throw new FileReadFailException(); + throw new FileReadFailException("올바르지 않은 파일 경로입니다. (" + filePath + ")"); } return systemResource; } From 5764cded74ea244f5492646139579f134760d848 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:19:37 +0900 Subject: [PATCH 54/60] =?UTF-8?q?refactor(Position):=20=EC=98=AC=EB=B0=94?= =?UTF-8?q?=EB=A5=B4=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Position.java | 2 +- src/main/java/wordle/exception/InvalidPositionException.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/wordle/domain/Position.java b/src/main/java/wordle/domain/Position.java index 11c6394e..cc6d5159 100644 --- a/src/main/java/wordle/domain/Position.java +++ b/src/main/java/wordle/domain/Position.java @@ -10,7 +10,7 @@ public class Position implements Comparable { public Position(int position) { if (position < MIN_POSITION) { - throw new InvalidPositionException(); + throw new InvalidPositionException("0보다 작은 위치는 존재할 수 없습니다."); } this.position = position; diff --git a/src/main/java/wordle/exception/InvalidPositionException.java b/src/main/java/wordle/exception/InvalidPositionException.java index 893a164f..d18f2c4a 100644 --- a/src/main/java/wordle/exception/InvalidPositionException.java +++ b/src/main/java/wordle/exception/InvalidPositionException.java @@ -2,4 +2,7 @@ public class InvalidPositionException extends WordleInvalidInputException { + public InvalidPositionException(String message) { + super(message); + } } From 0f04861437403aaca77f75e46bb74e0732466bff Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:23:02 +0900 Subject: [PATCH 55/60] =?UTF-8?q?refactor(Wordle):=20=EB=8B=A8=EC=96=B4?= =?UTF-8?q?=EC=9E=A5=EC=97=90=20=EB=8B=A8=EC=96=B4=EA=B0=80=20=EC=97=86?= =?UTF-8?q?=EC=9D=84=20=EC=8B=9C=20=EC=98=88=EC=99=B8=EB=A5=BC=20Wordle?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=8D=98=EC=A7=84=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/application/Wordle.java | 2 +- src/main/java/wordle/exception/WordNotExistException.java | 3 +++ src/test/java/wordle/domain/FileWordBookTest.java | 4 +--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index 34e1dc89..987336e5 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -49,7 +49,7 @@ private void runGame(Word answerWord) { private void processTurn(Word answerWord) { outputView.askAnswer(); Word inputWord = wordBook.find(inputView.input()) - .orElseThrow(WordNotExistException::new); + .orElseThrow(() -> new WordNotExistException(inputView.input())); Results results = answerWord.compare(inputWord); record.add(results); } diff --git a/src/main/java/wordle/exception/WordNotExistException.java b/src/main/java/wordle/exception/WordNotExistException.java index b9e0c9c2..7580a929 100644 --- a/src/main/java/wordle/exception/WordNotExistException.java +++ b/src/main/java/wordle/exception/WordNotExistException.java @@ -2,4 +2,7 @@ public class WordNotExistException extends WordleInvalidInputException { + public WordNotExistException(String word) { + super("올바르지 않은 단어입니다. (" + word + ")"); + } } diff --git a/src/test/java/wordle/domain/FileWordBookTest.java b/src/test/java/wordle/domain/FileWordBookTest.java index d0c40959..baab6bfa 100644 --- a/src/test/java/wordle/domain/FileWordBookTest.java +++ b/src/test/java/wordle/domain/FileWordBookTest.java @@ -1,13 +1,11 @@ package wordle.domain; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import wordle.exception.WordNotExistException; import wordle.infra.FileReader; public class FileWordBookTest { @@ -20,7 +18,7 @@ void setUp() { } @ParameterizedTest - @CsvSource(value = {"hello:true", "exist:false"}, delimiter = ':') + @CsvSource(value = {"hello:true", "exist:false" }, delimiter = ':') void WordBook에_단어가_존재하는지_확인_할_수있다(String input, boolean expected) { final boolean actual = wordBook.exist(new Word(input)); From 8c59d10bdf0a6b0890a5b244e06de43e2d3597c3 Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:34:11 +0900 Subject: [PATCH 56/60] =?UTF-8?q?refactor(OutputView):=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EB=A9=94=EC=84=B8=EC=A7=80=EB=A5=BC=20=EB=B0=9B?= =?UTF-8?q?=EC=95=84=EC=84=9C=20=EB=B7=B0=EB=A1=9C=20=EB=B3=B4=EC=97=AC?= =?UTF-8?q?=EC=A4=80=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/application/Wordle.java | 4 +--- src/main/java/wordle/exception/InvalidWordException.java | 3 +++ src/main/java/wordle/exception/WordleException.java | 3 +++ .../wordle/exception/WordleInvalidInputException.java | 3 +++ src/main/java/wordle/ui/ConsoleOutputView.java | 9 ++------- src/main/java/wordle/ui/InputView.java | 1 - src/main/java/wordle/ui/OutputView.java | 4 +--- 7 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index 987336e5..46c88e35 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -65,10 +65,8 @@ private void concludeGame() { private void handleWrongAnswer(Runnable runnable) { try { runnable.run(); - } catch (WordleInvalidInputException e) { - outputView.wrongAnswer(); } catch (WordleException e) { - outputView.unexpectedEnd(); + outputView.unexpectedEnd(e.getMessage()); } } } diff --git a/src/main/java/wordle/exception/InvalidWordException.java b/src/main/java/wordle/exception/InvalidWordException.java index 326c7eaa..2979e5fc 100644 --- a/src/main/java/wordle/exception/InvalidWordException.java +++ b/src/main/java/wordle/exception/InvalidWordException.java @@ -2,4 +2,7 @@ public class InvalidWordException extends WordleInvalidInputException { + public InvalidWordException(String message) { + super(message); + } } diff --git a/src/main/java/wordle/exception/WordleException.java b/src/main/java/wordle/exception/WordleException.java index 9fded22d..a1b03ae4 100644 --- a/src/main/java/wordle/exception/WordleException.java +++ b/src/main/java/wordle/exception/WordleException.java @@ -2,4 +2,7 @@ public class WordleException extends RuntimeException { + public WordleException(String message) { + super(message); + } } diff --git a/src/main/java/wordle/exception/WordleInvalidInputException.java b/src/main/java/wordle/exception/WordleInvalidInputException.java index a6608381..13aa7d21 100644 --- a/src/main/java/wordle/exception/WordleInvalidInputException.java +++ b/src/main/java/wordle/exception/WordleInvalidInputException.java @@ -2,4 +2,7 @@ public class WordleInvalidInputException extends WordleException { + public WordleInvalidInputException(String message) { + super(message); + } } diff --git a/src/main/java/wordle/ui/ConsoleOutputView.java b/src/main/java/wordle/ui/ConsoleOutputView.java index 3eb4729f..22d436bd 100644 --- a/src/main/java/wordle/ui/ConsoleOutputView.java +++ b/src/main/java/wordle/ui/ConsoleOutputView.java @@ -55,12 +55,7 @@ public void failEnd(Record record) { } @Override - public void wrongAnswer() { - System.out.println("올바르지 않은 단어입니다."); - } - - @Override - public void unexpectedEnd() { - System.out.println("비정상적으로 게임이 종료되었습니다."); + public void unexpectedEnd(String message) { + System.out.println(message); } } diff --git a/src/main/java/wordle/ui/InputView.java b/src/main/java/wordle/ui/InputView.java index d0c7c708..45645717 100644 --- a/src/main/java/wordle/ui/InputView.java +++ b/src/main/java/wordle/ui/InputView.java @@ -3,5 +3,4 @@ public interface InputView { String input(); - } diff --git a/src/main/java/wordle/ui/OutputView.java b/src/main/java/wordle/ui/OutputView.java index acdcd281..b105ee71 100644 --- a/src/main/java/wordle/ui/OutputView.java +++ b/src/main/java/wordle/ui/OutputView.java @@ -14,7 +14,5 @@ public interface OutputView { void failEnd(Record record); - void wrongAnswer(); - - void unexpectedEnd(); + void unexpectedEnd(String message); } From 9593935ed4450c09b56dce4c790641174fa5606d Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:54:27 +0900 Subject: [PATCH 57/60] =?UTF-8?q?refactor(Wordle):=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20-=20processT?= =?UTF-8?q?urn=20->=20processRound=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=20-=20isEnd=EB=8C=80=EC=8B=A0=20=EB=AA=85=EC=8B=9C=EC=A0=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20round=EA=B0=80=20=EB=81=9D=EB=82=AC?= =?UTF-8?q?=EB=8B=88=3F=EB=A5=BC=20while=20=EC=A1=B0=EA=B1=B4=EB=AC=B8?= =?UTF-8?q?=EC=97=90=20=EA=B1=B8=EC=96=B4=EC=A4=80=EB=8B=A4.=20-=20while?= =?UTF-8?q?=20=EC=A4=91=EA=B0=84=EC=97=90=20=EC=A0=95=EB=8B=B5=EC=9D=84=20?= =?UTF-8?q?=EB=A7=9E=EC=B6=94=EB=8A=94=20=EA=B2=8C=EC=9E=84=20=EC=84=B1?= =?UTF-8?q?=EA=B3=B5=20=ED=91=9C=EC=8B=9C=EB=A1=9C=20true=EB=A5=BC=20?= =?UTF-8?q?=EB=A6=AC=ED=84=B4=ED=95=98=EC=97=AC=20=EC=84=B1=EA=B3=B5?= =?UTF-8?q?=EC=A2=85=EB=A3=8C=20=EB=A9=94=EC=8B=9C=EC=A7=80=EB=A5=BC=20?= =?UTF-8?q?=EC=BD=98=EC=86=94=EC=97=90=20=EB=B3=B4=EC=97=AC=EC=A4=80?= =?UTF-8?q?=EB=8B=A4.=20-=20while=20=EB=AC=B8=EC=9D=B4=20=EB=81=9D?= =?UTF-8?q?=EB=82=A0=EB=95=8C=EA=B9=8C=EC=A7=80=20=EC=A0=95=EB=8B=B5?= =?UTF-8?q?=EC=9D=84=20=EB=A7=9E=EC=B6=94=EC=A7=80=20=EB=AA=BB=ED=95=98?= =?UTF-8?q?=EB=A9=B4=20false=EB=A5=BC=20=EB=A6=AC=ED=84=B4=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EC=8B=A4=ED=8C=A8=EC=A2=85=EB=A3=8C=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=EB=A5=BC=20=EC=BD=98=EC=86=94=EC=97=90=20?= =?UTF-8?q?=EB=B3=B4=EC=97=AC=EC=A4=80=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/application/Wordle.java | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/wordle/application/Wordle.java b/src/main/java/wordle/application/Wordle.java index 46c88e35..92c5715b 100644 --- a/src/main/java/wordle/application/Wordle.java +++ b/src/main/java/wordle/application/Wordle.java @@ -8,7 +8,6 @@ import wordle.domain.WordBook; import wordle.exception.WordNotExistException; import wordle.exception.WordleException; -import wordle.exception.WordleInvalidInputException; import wordle.ui.InputView; import wordle.ui.OutputView; @@ -35,18 +34,22 @@ public Wordle(WordBook wordBook, InputView inputView, OutputView outputView) { public void startGame() { Word answerWord = wordBook.pick(answerFormula); outputView.welcome(); - runGame(answerWord); - concludeGame(); + concludeGame(runGame(answerWord)); } - private void runGame(Word answerWord) { - while (!record.isEnd()) { + private boolean runGame(Word answerWord) { + while (!record.isCountOver()) { outputView.showRecord(record); - handleWrongAnswer(() -> processTurn(answerWord)); + handleWrongAnswer(() -> processRound(answerWord)); + + if (record.existAnswer()) { + return true; + } } + return false; } - private void processTurn(Word answerWord) { + private void processRound(Word answerWord) { outputView.askAnswer(); Word inputWord = wordBook.find(inputView.input()) .orElseThrow(() -> new WordNotExistException(inputView.input())); @@ -54,14 +57,6 @@ private void processTurn(Word answerWord) { record.add(results); } - private void concludeGame() { - if (record.existAnswer()) { - outputView.successEnd(record); - return; - } - outputView.failEnd(record); - } - private void handleWrongAnswer(Runnable runnable) { try { runnable.run(); @@ -69,4 +64,12 @@ private void handleWrongAnswer(Runnable runnable) { outputView.unexpectedEnd(e.getMessage()); } } + + private void concludeGame(boolean isGameWon) { + if (isGameWon) { + outputView.successEnd(record); + return; + } + outputView.failEnd(record); + } } From 19e3484f1bb7e94a2fdba2324ab9d63632ee55fe Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:55:09 +0900 Subject: [PATCH 58/60] =?UTF-8?q?refactor(Record):=20=EC=95=88=EC=93=B0?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20isEnd=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/wordle/domain/Record.java | 4 ---- src/test/java/wordle/domain/RecordTest.java | 16 ---------------- 2 files changed, 20 deletions(-) diff --git a/src/main/java/wordle/domain/Record.java b/src/main/java/wordle/domain/Record.java index 4c43a6dd..f0f58d74 100644 --- a/src/main/java/wordle/domain/Record.java +++ b/src/main/java/wordle/domain/Record.java @@ -17,10 +17,6 @@ public void add(Results results) { record.add(results); } - public boolean isEnd() { - return existAnswer() || isCountOver(); - } - public boolean isCountOver() { return record.size() >= MAX_COUNT; } diff --git a/src/test/java/wordle/domain/RecordTest.java b/src/test/java/wordle/domain/RecordTest.java index fe910f2b..14e7b4ab 100644 --- a/src/test/java/wordle/domain/RecordTest.java +++ b/src/test/java/wordle/domain/RecordTest.java @@ -2,10 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.stream.Stream; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; import wordle.fixture.ResultFixture; public class RecordTest { @@ -24,19 +21,6 @@ public class RecordTest { assertThat(record.isCountOver()).isTrue(); } - @ParameterizedTest - @MethodSource("provideRecord") - void Record가_5개_인_결과모음이_있거나_결과모음이_6개이상이면_종료여부가_true이다(Record record) { - assertThat(record.isEnd()).isTrue(); - } - - private static Stream provideRecord() { - return Stream.of( - createAllGreenRecord(), - createAllGrayRecord() - ); - } - private static Record createAllGreenRecord() { Record record = new Record(); From cdb969d57cc3075a3c1420bcf983f9905ab71f3a Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 01:57:23 +0900 Subject: [PATCH 59/60] =?UTF-8?q?refactor(Word):=20word=20=ED=8C=8C?= =?UTF-8?q?=EB=9D=BC=EB=AF=B8=ED=84=B0=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Word 클래스에서는 input과 answer를 구분하지 않는다. 따라서 파라미터명을 헷갈리지 않도록 변경한다. - input -> word - inputWord -> targetWord --- src/main/java/wordle/domain/Word.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/wordle/domain/Word.java b/src/main/java/wordle/domain/Word.java index c8dcbaa2..bcbe174d 100644 --- a/src/main/java/wordle/domain/Word.java +++ b/src/main/java/wordle/domain/Word.java @@ -12,21 +12,21 @@ public class Word implements Iterable { public static final int WORD_LENGTH = 5; private final List letters; - public Word(String input) { - if (input.length() != WORD_LENGTH) { - throw new InvalidWordException(); + public Word(String word) { + if (word.length() != WORD_LENGTH) { + throw new InvalidWordException("단어는 5글자여야 합니다. (" + word + ")"); } this.letters = new ArrayList<>(); - for (int i = 0; i < input.length(); i++) { - Letter letter = new Letter(input.charAt(i), i); + for (int i = 0; i < word.length(); i++) { + Letter letter = new Letter(word.charAt(i), i); this.letters.add(letter); } } - public Results compare(Word inputWord) { + public Results compare(Word targetWord) { WordComparator wordComparator = new WordComparator(this.letters); - return wordComparator.compare(inputWord); + return wordComparator.compare(targetWord); } static class WordComparator { @@ -39,16 +39,16 @@ public WordComparator(List letters) { this.results = new Results(); } - public Results compare(Word inputWord) { - for (Letter letter : inputWord) { + public Results compare(Word targetWord) { + for (Letter letter : targetWord) { process(letter, letter::equals, Tile.GREEN); } - for (Letter letter : inputWord) { + for (Letter letter : targetWord) { process(letter, letter::isSameAlphabet, Tile.YELLOW); } - for (Letter letter : inputWord) { + for (Letter letter : targetWord) { fillEmptyToGray(letter); } From 8b9b2b987b7d5ef85def81b2960b8f7ad4b6c34d Mon Sep 17 00:00:00 2001 From: hoa0217 Date: Mon, 1 Jul 2024 02:04:50 +0900 Subject: [PATCH 60/60] =?UTF-8?q?docs:=20=EC=9A=A9=EC=96=B4=20=EC=82=AC?= =?UTF-8?q?=EC=A0=84=20=EB=B0=8F=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=8B=A4?= =?UTF-8?q?=EC=9D=B4=EC=96=B4=EA=B7=B8=EB=9E=A8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/docs/README.md b/docs/README.md index 289ea406..20067e04 100644 --- a/docs/README.md +++ b/docs/README.md @@ -19,27 +19,26 @@ ## 용어 사전 -| 한글명 | 영문명 | 설명 | -|--------|----------------|------------------------------------------------| -| 워들 | Wordle | 5글자 영어 단어 맞추기 게임 | -| 단어장 | Word Book | 이 게임에서 사용될 수 있는 단어 모음 | -| 입력 단어 | Input Word | 플레이어가 입력하는 5글자 단어 | -| 정답 단어 | Answer Word | 오늘 게임의 정답인 5글자 단어 | -| 글자 | Letter | 단어를 구성하는 알파벳 | -| 영문 | Alphabet | 글자를 구성하는 최소단위 | -| 위치 | Position | 단어를 구성하는 글자의 위치 | -| 플레이어 | Player | 게임에 참여하는 사용자 | -| 결과 | Result | 입력단어와 정답단어를 비교해서 표현되는 타일모음 | -| 비교 | Compare | 입력단어와 정답단어의 글자와 위치를 비교하는 행위 | -| 초록색 타일 | Green Tile | 글자와 위치가 동일한 경우 표현되는 타일 | -| 노란색 타일 | Yellow Tile | 글자는 포함되지만 위치가 다른 경우 표현되는 타일 | -| 회색 타일 | Gray Tile | 글자와 위치가 모두 다른 경우 표현되는 타일 | -| 결과모음 | Results | 라운드가 진행될 때 마다 누적된 결과모음 | -| 기록모음 | Record | 누적된 결과모음의 기록 | -| 기준일 | Base Date | 오늘의 정답 단어를 계산하는 기준일(2021년 6월 19일) | -| 정답 공식 | Answer Formula | 오늘의 정답 단어를 계산하는 공식 `(현재 날짜 - 기준일) % 단어장의 단어 수` | -| 시작 | Start | 플레이어가 워들을 시작하는 행위 | -| 종료 | End | 워들이 종료되는 행위(라운드가 전부 끝났거나, 그 전에 정답을 맞추면 종료된다) | +| 한글명 | 영문명 | 설명 | +|--------|----------------|------------------------------------------------------------| +| 워들 | Wordle | 5글자 영어 단어 맞추기 게임 | +| 단어장 | Word Book | 이 게임에서 사용될 수 있는 단어 모음 | +| 단어 | Word | 게임에서 활용되는 5글자 단어. 플레이어가 입력하는 단어가 될 수 있고 오늘 게임의 정답도 될 수 있다. | +| 글자 | Letter | 단어를 구성하는 알파벳 | +| 영문 | Alphabet | 글자를 구성하는 최소단위 | +| 위치 | Position | 단어를 구성하는 글자의 위치 | +| 플레이어 | Player | 게임에 참여하는 사용자 | +| 결과 | Result | 입력단어와 정답단어를 비교해서 표현되는 타일모음 | +| 비교 | Compare | 입력단어와 정답단어의 글자와 위치를 비교하는 행위 | +| 초록색 타일 | Green Tile | 글자와 위치가 동일한 경우 표현되는 타일 | +| 노란색 타일 | Yellow Tile | 글자는 포함되지만 위치가 다른 경우 표현되는 타일 | +| 회색 타일 | Gray Tile | 글자와 위치가 모두 다른 경우 표현되는 타일 | +| 결과모음 | Results | 라운드가 진행될 때 마다 누적된 결과모음 | +| 기록모음 | Record | 누적된 결과모음의 기록 | +| 기준일 | Base Date | 오늘의 정답 단어를 계산하는 기준일(2021년 6월 19일) | +| 정답 공식 | Answer Formula | 오늘의 정답 단어를 계산하는 공식 `(현재 날짜 - 기준일) % 단어장의 단어 수` | +| 시작 | Start | 플레이어가 워들을 시작하는 행위 | +| 종료 | End | 워들이 종료되는 행위(라운드가 전부 끝났거나, 그 전에 정답을 맞추면 종료된다) | ## 모델링 @@ -60,7 +59,7 @@ classDiagram -List pendingLetters -Results results +WordComparator(letters: List) - +compare(inputWord: Word): Results + +compare(targetWord: Word): Results -process(targetLetter: Letter, predicate: Predicate, tile: Tile) -fillEmptyToGray(targetLetter: Letter) } @@ -89,7 +88,6 @@ classDiagram class Record { -List record +add(Results results) void - +isEnd() boolean +isCountOver() boolean +existAllGreen() boolean +iterator() Iterator @@ -99,7 +97,7 @@ classDiagram -SortedSet results +add(Result result) void +isCheckedPosition(Position position) boolean - +isAllGreen() boolean + +isAnswer() boolean } class Result { -Tile tile @@ -133,7 +131,7 @@ classDiagram -AnswerFormula answerFormula +startGame() void -runGame(Word answerWord) void - -processTurn(Word answerWord) void + -processRound(Word answerWord) void -concludeGame() void -handleWrongAnswer(Runnable runnable) void }