Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5기]3주차 Wordle 과제 제출 - 싸무엘 #36

Open
wants to merge 59 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
8ab95e6
docs: 기능 구현 task 목록 작성
samkim-jn Jun 6, 2024
5c69323
docs: 1일차 회고 작성
samkim-jn Jun 6, 2024
0517eb1
docs: 2일차 회고 작성
samkim-jn Jun 9, 2024
334e123
feat: 초기 문구 출력과 정답 입력 구현
samkim-jn Jun 10, 2024
bbc2280
feat: 파일 읽기 로직 구현
samkim-jn Jun 10, 2024
61fae53
feat: 주어진 날짜에 대한 단어를 얻는 로직 구현
samkim-jn Jun 10, 2024
4061d64
docs: 3일차 회고 작성
samkim-jn Jun 11, 2024
742ebd5
feat: 초기 구현
samkim-jn Jun 11, 2024
005e447
refactor: Answer, Result 클래스 추출
samkim-jn Jun 11, 2024
7d2e79f
refactor: Letter 클래스 분리
samkim-jn Jun 11, 2024
eb5ee89
docs: 4일차 회고 작성
SeolYoungKim Jun 15, 2024
d960b50
docs: 싸무엘 4일차 회고 작성
samkim-jn Jun 15, 2024
883e63a
refactor: Input 클래스 분리
samkim-jn Jun 15, 2024
318426a
refactor: WordleValidator 분리
SeolYoungKim Jun 15, 2024
b300bc1
refactor: checkContainsValue 메서드가 Input을 사용하도록 변경
SeolYoungKim Jun 15, 2024
bd4c2cb
refactor: Letters, LetterCounter 분리
SeolYoungKim Jun 15, 2024
22eecf7
refactor: 초록색 타일 만드는 로직 리팩토링
samkim-jn Jun 15, 2024
e51a0a8
docs: 5일차 회고 작성(딱구)
SeolYoungKim Jun 15, 2024
36173d7
docs: 5일차 회고 작성(싸무엘)
samkim-jn Jun 15, 2024
84f1a55
refactor: 노란색 타일 만드는 로직 리팩토링
SeolYoungKim Jun 16, 2024
15baf55
refactor: 회색 타일 로직 리팩토링
samkim-jn Jun 16, 2024
b158817
refactor: 회색 타일로 변환하는 케이스를 추가
SeolYoungKim Jun 16, 2024
07007a6
fix: 초록색 타일이 회색 타일로 출력되는 문제 수정
samkim-jn Jun 16, 2024
aaf2b6e
refactor: Result를 Tiles로 변경하고 게임의 정책을 상수로 추출
SeolYoungKim Jun 16, 2024
7ae7c87
refactor: TileService로 Tiles 생성 로직을 이동
SeolYoungKim Jun 16, 2024
47a549c
refactor: TileStorage 클래스 분리
samkim-jn Jun 16, 2024
7d091de
refactor: 사용하지 않는 클래스 제거 & 의존성을 주입받도록 변경
SeolYoungKim Jun 16, 2024
d3ad606
refactor: 정답 타일 체크로직 리팩토링
SeolYoungKim Jun 16, 2024
fbe067c
test: LetterCounter 테스트 작성
SeolYoungKim Jun 16, 2024
3860bac
test: Letters 테스트 작성
samkim-jn Jun 16, 2024
8cb9ade
docs: 6일차 회고 작성(딱구)
SeolYoungKim Jun 17, 2024
46d72cd
docs: 6일차 회고 작성(싸무엘)
samkim-jn Jun 17, 2024
08fc345
refactor: 결과 출력 부분 메서드 분리
samkim-jn Jun 17, 2024
4fc87cf
refactor: 입력 받는 부분 메서드 분리
SeolYoungKim Jun 17, 2024
1aae120
refactor: IOView 클래스 이름을 Console로 변경 및 메서드 이름 변경
SeolYoungKim Jun 17, 2024
cffb677
refactor: 결과 출력 부분 Console 클래스로 이동
samkim-jn Jun 17, 2024
438f7b0
refactor: WordService 분리
samkim-jn Jun 17, 2024
cdaea0b
refactor: TileService create() 메서드 분리
SeolYoungKim Jun 17, 2024
b3d5b05
refactor: AnswerLetters를 만드는 로직을 메서드로 분리
SeolYoungKim Jun 17, 2024
2273c00
refactor: 게임 종료 여부를 체크하는 로직을 분리
SeolYoungKim Jun 17, 2024
f6f55e1
refactor: 입력값 검증 메서드 분리
samkim-jn Jun 17, 2024
0132097
refactor: Letters를 생성할 때 파라미터를 소문자로 변경
samkim-jn Jun 17, 2024
e071b7f
refactor: 메서드 순서 변경
samkim-jn Jun 17, 2024
bbaa42c
refactor: 패키지 분리
samkim-jn Jun 17, 2024
d62deea
style: 코드 스타일 수정
SeolYoungKim Jun 17, 2024
02d8987
refactor: WORDS_FILE_PATH 상수 추출
SeolYoungKim Jun 17, 2024
bf05504
test: 테스트 코드 리팩토링
SeolYoungKim Jun 17, 2024
4b15342
docs: task 정리
samkim-jn Jun 17, 2024
4f208b2
docs: 7일차 회고 작성(딱구)
SeolYoungKim Jun 17, 2024
518e295
docs: 7일차 회고 작성(싸무엘)
samkim-jn Jun 17, 2024
3ed7bc0
refactor: 기능을 명확하게 표현하기 위한 클래스명 변경
samkimuel Jun 28, 2024
d1dffe5
refactor: 날짜 간격을 Period 클래스를 이용하여 수정
samkimuel Jun 28, 2024
dca9adb
refactor: 값만 일치하는지 판단하는 로직을 Letter 클래스 책임으로 분리
samkimuel Jun 29, 2024
c5bef02
refactor: 테스트 픽스처 메서드로 분리
samkimuel Jun 29, 2024
4f35990
docs: 요구사항 수정
samkimuel Jun 29, 2024
1d3cbef
refactor: 입력 검증 로직 개선
samkimuel Jun 30, 2024
e3b2d12
refactor: Word 관련 로직을 WordLoader 책임으로 분리
samkimuel Jun 30, 2024
28ea8ec
refactor: 미사용 메서드 제거
samkimuel Jun 30, 2024
f73a128
refactor: Tiles, TileService 클래스를 표현력있는 클래스로 변경
samkimuel Jun 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/task.md
samkimuel marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## 기능 구현 Task
- [X] 정답 단어를 고른다.
- 정답은 `매일 바뀌며 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) 번째의 단어`
- [X] 초기 문구를 출력한다.
- `WORDLE을 6번 만에 맞춰 보세요. 시도의 결과는 타일의 색 변화로 나타납니다.`
- [X] `정답을 입력해 주세요.`를 출력한다
- [X] 입력을 받는다.
- 입력한 단어가 5글자 미만인 경우
- `Not enough letters` 문구를 출력하고 입력을 재시도한다.
- `words.txt` 파일에 존재하지 않는 단어를 입력할 경우
- `Not in word list` 문구를 출력하고 입력을 재시도한다.
- [X] 정답을 확인하고 이력을 저장한다. (input -> 각 단어를 체크 -> 타일로 정답을 변환 -> 타일을 이력에 저장)
- 입력한 단어와 정답을 비교한다.
- 글자가 정답 안에 없는 경우 : ⬜
- 글자가 정답 안에 포함됐지만 위치가 다른 경우 : 🟨
- 글자가 정답 안에 포함됐고 위치가 같은 경우 : 🟩
- 단어를 타일로 변환 및 타일을 이력으로 저장한다.
- 입력이 정답이 아닐 경우
- 시도 횟수가 남아있을 경우
- 입력을 다시 받음
- 시도 이력을 모두 출력
- 6번 모두 시도 했을 경우
- x/6 출력
- 시도 이력을 모두 출력
- 입력이 정답일 경우
- 몇번만에 맞췄는지 출력한다 (ex: 4/6)
- 시도 이력을 모두 출력한다.
89 changes: 89 additions & 0 deletions docs/회고.md
samkimuel marked this conversation as resolved.
Show resolved Hide resolved
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

회고를 잘 정리해주셔서 어떤 과정으로 구현했고, 변경했는지 따라가기가 좋았습니다! 💯

samkimuel marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
## 1일차 회고
- 딱구 :
- 제대로된(?) 페어프로그래밍을 처음 해봐서 내가 제대로 못한 것 같아서 아쉽습니다. 글이나 영상을 충분히 보고 왔어야 했던 것 같습니다. 이걸로 이루고자 하는 목적이 무엇인지 파악을 하면 좋을 것 같습니다.
- 싸무엘님의 생각 방식을 알 수 있어서 좋았습니다. 특히 여러 방면에서 다양한 시도를 해보시는 게 좋았는데, 저는 다양한 시도를 할 생각을 잘 못하는 편이라, 짧지만 많은 부분을 배울 수 있었습니다.
- 하지만 구현은 못했죠? ㅠㅠ 생각보다 구현이 많이 어렵네요. 앞으로 어떻게 해나가야 할지 그 방향성에 대해 적극적인 의사소통을 통해 이뤄나가면 좋을 것 같습니다. 카톡방에서도 자주 소통해요!
- 싸무엘
- 기능 구현 목록 정리부터 페어와 함께 진행하는 게 처음인데, 서로의 생각을 맞춰나가고 생각 방식이 어떤지 알아가는 과정이 재밌었습니다.
- 구현 스타일?을 맞춰나가는 과정과 그 과정에서 소통하는 게 정말 중요하다고 생각이 듭니다.
- 결국 구현은 못했지만 앞으로가 기대됩니다. ㄱㅈㅇ~

### 다음에는 무엇을 할까 ?
- 우리의 첫 시도
- 도메인 로직부터 구현하고 UI(view)는 나중에 구현하자
- 커밋을 어떻게 나눌까 ?
- 생각은 페어와 같이 하자 (따로 하지 말자)
- 15분씩 작업, 5분 휴식 하자

## 2일차 회고
- 싸무엘
- 요구사항에 대해 말과 글로만 정리했던 것을 시각적으로 구체화하면서 진행하니 이해가 편해지는 것 같습니다.
- 핵심 로직에 대해 얘기하다보니 요구사항을 구체적으로 정의하고 페어와 얼라인하는게 중요하다고 생각했습니다.
- 같이 생각하는 것, 따로 생각한다음 논의할 때 맞춰나가는 것 - 어느 것이 페어 프로그래밍 목적에 더 알맞는걸까요?
- 딱구
- 피그잼을 이용해서 기능들을 정리 해보고, 알맞은 역할을 할 객체들을 찾아보았습니다. 1일차에서 왜 생각이 막혔었는지를 생각 해보니 객체에 맞지 않는 역할이 부여되어 있음을 깨달았습니다(SRP 위반). 이를 분리하니 더 생각 하기가 수월해졌던 것 같습니다. 시각화를 하는게 중요하구나 도 깨달았습니다.
- 비교로직을 잘 짜보고싶었는데 너무 어려웠고, 엣지 케이스까지 고려하려니 머리가 돌아가지 않았습니다 😓결국에 이로인해 프로그래밍이 너무 막히게 될 것 같아서, 기능 관련 알고리즘을 각자 구현 해보고 해당 내용을 바탕으로 합쳐가면서 기능을 만들어나가기로 결정 했습니다. 기능이 아주 단순하다고 생각했지만 엣지케이스까지 고려하니까 단순하지 않네요.
- 이렇게 구현이 막힐 경우, 어떻게 하는게 좋은지는 아직 잘 모르겠습니다. 페어프로그래밍의 목적을 고려했을 때는 같이 생각하면서 구현 해나가는게 좋을 것 같은데, 아예 생각에 진전이 없을 경우에는 각자 생각 해보고 오는것도 좋을 것 같습니다.

### 다음에는 무엇을 할까 ?
- 핵심 로직 각자 설명, 방향 선택해서 구현

## 3일차 회고

- 싸무엘
- 오프라인 좋아요~
- 어디까지 구현하고 테스트해야할까
- 딱구님 버스 승차감이 좋다.🚌

- 딱구
- 테스트가 쉬운 코드란 무엇일까
- 객체의 역할은 어디까지인가 바운더리를 어떻게 정해야하나
- 기능 구현을 마무리했더니 너무 지저분했다
- 싸무엘님이 다양한 의견을 주셔서 나만의 생각에 매몰되지 않을 수 있었다 todayWord 아이디어가 너무 좋았다
- 그림그려가면서 해보자고 해주신게 좋았다
- 오프라인이 훨씬낫다


## 4일차 회고
- 딱구
- 생각보다 많은걸 했다.
- 분리를 많이 했으나, 더 필요한 것 같다. 테스트 코드도 많이 짜보고싶다
- 싸무엘
- 오늘 역할을 잘 수행하지 못했던 것 같다.
- 드라이버 역할일 때 뇌정지가 많이 왔고 퍼포먼스가 안나온 것 같다. 딱구님이 가이드를 잘 해주셨지만 내가 이해를 잘 못했던 것 같다.
- 네이게이터 역할을 어떻게 더 잘 수행할 수 있을까 고민이 된다. 드라이버가 잘하고 있으면 즐기기만 해도(?) 괜찮을지 모르겠다.
- 딱구님이 배려를 많이 해주신다고 느껴 압도적으로 감사할뿐...


## 5일차 회고
- 딱구
- 제가 설명을 잘 못하는것 같습니다 😓 그래도 어떻게 설명해야 잘 설명할까를 고민하게 되는 시간이 있어서 좋았습니다. 앞으로는 소프트스킬도 업그레이드 시켜야 할것같은데, 어떻게 해야할지 고민해봐야겠습니다 ㅋㅋㅋ
- 리팩토링이 너무 어려운걸 보니, 제가 짠 워들 알고리즘이 별로 안좋은 알고리즘이 아닌가 하는 근본적인 의문이 들더라구요.. ㅋㅋㅋ 역할을 어떻게 가져가야할지, 이를 어떤 클래스로 분리해야 할지가 명확하지 않았는데, 싸무엘님 덕분에 validation을 수행할 클래스와 counterMap을 가진 클래스를 분리할 생각을 할 수 있었습니다. 저는 한가지 생각에 매몰이 잘 되어버리는 편인데, 싸무엘님이 생각의 전환을 빠르게 도와주셔서 큰 도움이 되었습니다. 👍

- 싸무엘
- 지속적으로 리팩토링하고 있는데 어떻게 리팩토링 해야할지 계속 의견을 주고받으면서 진행하니까 내 생각에만 머물러 있지 않아서 좋은 것 같다.
- 딱구님이 생각을 잘 정리해주셔서 빠르게 이해하고 실행할 수 있었던 것 같다.
- 개떡같이 설명해도 찰떡같이 이해해주시니 감사했다.


## 6일차 회고
- 딱구
- 싸무엘님과 함께 객체를 분리 해나가고, 테스트를 작성 하면서 많은 부분들을 개선했습니다. 좋은 방향으로 개선한것인지는 모르겠지만, 어디선가 많이 본 XxxService, XxxRepository와 비슷한 구조가 태어나 버렸습니다 하하.. 7일차에는 프로그래밍 요구사항을 만족시키기 위한 작업을 해야할 것 같습니다.
- 중간에 소통의 오류로 인해 오해했던 부분이 있었는데(결국 서로 같은 말을 했는데 다르게 이해하였음), 역시 온라인보단 오프라인이 좋구나 라는 생각을 하게된 계기가 되었습니다. 제가 말을 좀 못하다 보니, 말을 잘하고 싶어지는 순간들이 많았습니다 ㅋㅋ 싸무엘님이 찰떡같이 이해 해주셔서 감사합니다 😅
- 여전히 설계가 아쉬운 것 같습니다. 복잡한 알고리즘 때문일까? 싶기도 하고... 근본적인 원인이 무엇인지 파악하기가 어렵네요 ㅎㅎ 특히, 역할을 적절한 클래스에 분배하는 것이 가장 어려웠습니다
- 싸무엘
- 페어와 클래스 역할, 네이밍 등을 생각하면서 더 좋은 방향으로 리팩토링 하는 재미가 있다.
- 내가 설명하고자 하는 것을 상대가 잘 이해할 수 있게 조리있게 설명하는 게 참 어렵다고 다시 한 번 느꼈습니다.
- 머리가 너무 안돌아서 큰일이다... 딱구님 해줘!


## 7일차 회고
- 딱구
- 드디어 끝을 보았습니다. 싸무엘님 덕분에 많은 것을 배웠습니다. 특히, 매몰되기 시작한 시점에서 생각을 전환시켜주는 등의 말씀들이 가장 많은 도움이 되었습니다. 그리고, 논리적으로 오류가 생길만한 부분들을 잘 찾아내 주신 덕분에 실수한 부분들이 금방 복구가 되었습니다.
- 페어 프로그래밍이라는 것이 에너지도 많이 소모가 되지만 정말 많은 것을 배워갈 수 있었던 것 같습니다. 그리고, 생각보다 제가 말을 조리있게 잘 못한다는 것과, 생각하시는 중에 말을 걸어서 생각하는 시간을 방해하는 등 안좋은 짓(?)도 많이 한것같습니다 😓
- 싸무엘님과는 한번쯤 같이 일해보고 싶다는 마음이 들정도로 재미있었고 부담되지 않게 잘 해주셔서 잘할 수 있었던 것 같습니다 👍
- 싸무엘
- 끝낼 수 있을까 생각했는데 어떻게 끝내긴 했습니다. 다 딱구님 덕분입니다.
- 딱구님께 많이 배울 수 있어서 좋았습니다. 대화하는 것과 배려하는 태도, 제가 이해 못할 때 설명해주시는 방법 등 개발적인 부분도 배울 점이 많지만 개발 외적인 부분에서 배운 게 많았습니다.
- 혼자 개발할 때는 안일하게 생각하는 부분들과 넘어가는 부분이 많은데, 딱구님이 그런 포인트들을 캐치해주셔서 생각할 수 있는 부분들이 많았습니다.
- 딱구 최고
Empty file removed src/main/java/.gitkeep
Empty file.
12 changes: 12 additions & 0 deletions src/main/java/wordle/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package wordle;

import wordle.model.*;
import wordle.view.Console;

public class Application {

public static void main(String[] args) {
Wordle wordle = new Wordle(new Console(), new WordService(new WordsReader()), new WordleValidator(), new TileService(new TileStorage()));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wordle을 생성하는 시점에 변수를 넘겨서 생성하고 계신데 new Wordle() 로 생성하시고 wordle 안에서 의존성을 관리하는 것은 어떨까요? 🤔
여러 변수를 넘겨받는 생성자는 코드를 실행하는 시점에 동적으로 변수를 변경할 수 있다는 장점이 있지만 해당 소스에서는 동적인 변화가 필요하지 않을 거 같아 생성의 책임을 wordle 안으로 넘긴다면 의존성이 추가될 때 wordle 클래스만 수정해도 되지 않을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀해주신 장점을 생각해 주입 패턴을 사용했는데, 현재 Wordle 에서는 동적으로 바뀌지 않아 Wordle 클래스 내부에서 생성 책임을 가져가도 괜찮을 것 같기도 하네요 🤔
생각해보니 동적으로 바뀌어야할 상황을 가정한다면 추상화를 하는게 좋아보이네요,, 당연하게 생각하고 넘어갔었던 부분인데 상기 시켜주셔서 감사합니다!

wordle.start();
}
}
39 changes: 39 additions & 0 deletions src/main/java/wordle/model/Letter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package wordle.model;

import java.util.Objects;

public class Letter {

private final int position;
private final char value;

public Letter(int position, char value) {
this.position = position;
this.value = value;
}

public int getPosition() {
return position;
}

public char getValue() {
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Letter letter = (Letter) o;
return position == letter.position && value == letter.value;
}

@Override
public int hashCode() {
return Objects.hash(position, value);
}
}
52 changes: 52 additions & 0 deletions src/main/java/wordle/model/LetterCounter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package wordle.model;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LetterCounter {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메소드 배치하실 때 어떤 기준으로 하시는 편인지 궁금합니다!
저도 피드백 받은 부분인데 상수 -> 일반 필드 -> 기본 생성자 -> 인자가 있는 생성자 -> public 메소드 -> private 메소드 -> 오버라이딩한 메소드 순으로 배치하는 것을 추천해 주시더라구요.
이번 기회에 같이 전체적으로 적용해보면 좋을 거 같아요~~ 🙈

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public 메서드, private 메서드는 순서상관없이 연관성 있는 메서드끼리 묶어놓는 편이고, 다른 순서는 동일해요!
public 메서드와 참조하는 private 메서드의 거리가 멀 때 확인이 불편해서 최대한 가깝게 놓는 편이에요.


private final Map<Character, Integer> letterCountMap;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

철자와 위치를 Map으로 사용하셨군요! 흥미롭습니다!! 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

철자와 철자 개수를 각각 Map의 key, value로 만들었어요!


public LetterCounter(Letters letters) {
this.letterCountMap = new HashMap<>();
for (Letter answerLetter : letters.getLetters()) {
char value = answerLetter.getValue();
letterCountMap.put(value, letterCountMap.getOrDefault(value, 0) + 1);
}
}

public void decreaseCount(Letters letters) {
for (Letter letter : letters.getLetters()) {
char value = letter.getValue();
letterCountMap.put(value, letterCountMap.get(value) - 1);
}
}

public Letters filterCanDecreaseCount(Letters letters) {
List<Letter> filteredLetters = letters.getLetters()
.stream()
.filter(this::canDecreaseCount)
.toList();

return new Letters(filteredLetters);
}

private boolean canDecreaseCount(Letter letter) {
char value = letter.getValue();
return letterCountMap.containsKey(value) && letterCountMap.get(value) > 0;
}

public Letters filterCanNotDecreaseCount(Letters letters) {
List<Letter> filteredLetters = letters.getLetters()
.stream()
.filter(this::canNotDecreaseCount)
.toList();

return new Letters(filteredLetters);
}

private boolean canNotDecreaseCount(Letter letter) {
return !canDecreaseCount(letter);
}
}
89 changes: 89 additions & 0 deletions src/main/java/wordle/model/Letters.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package wordle.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class Letters {

private final List<Letter> letters;
samkimuel marked this conversation as resolved.
Show resolved Hide resolved

public Letters(String word) {
String lowerCase = word.toLowerCase();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

소문자로 변환하는 작업이 있어 안정적이네요! 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

대소문자 비교때문에 소문자로 변환해야겠다고 생각해서 추가했는데, 얄뭉님은 대소문자 구분을 어떻게 하셨을까요?

char[] wordArr = lowerCase.toCharArray();

this.letters = new ArrayList<>();
for (int i = 0; i < wordArr.length; i++) {
letters.add(new Letter(i, wordArr[i]));
}
}

public Letters(List<Letter> letters) {
this.letters = letters;
}

public List<Letter> getLetters() {
return letters;
}

public boolean lessThan(int size) {
return letters.size() < size;
}

public boolean higherThan(int size) {
return letters.size() > size;
}

public String combine() {
return letters.stream()
.map(letter -> String.valueOf(letter.getValue()))
.collect(Collectors.joining(""));
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Collectors.joining을 사용해 깔끔하네요! 👍

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 joining을 처음 써봤는데 이번에 딱구님에게 배웠습니다 ㅎㅎ 🚌


public boolean contains(Letter letter) {
return letters.contains(letter);
}

public Letters findSamePositionAndValueLetters(Letters other) {
List<Letter> filteredLetters = letters.stream()
.filter(other::contains)
.toList();

return new Letters(filteredLetters);
}

public Letters findSameValueLetters(Letters other) {
List<Letter> filteredLetters = letters.stream()
.filter(letter -> !other.contains(letter))
.filter(other::isOnlySameValue)
.toList();

return new Letters(filteredLetters);
}

private boolean isOnlySameValue(Letter other) {
return letters.stream()
.anyMatch(letter -> (Objects.equals(letter.getValue(), other.getValue())) && letter.getPosition() != other.getPosition());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

값만 일치하는 경우를 판단하는 메서드가 Letter에 있으면 책임이 분리되어서 좋을거 같아요~🙂

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻 Letter에 책임 부여하는 게 더 좋아보이네요 👍🏻

}

public Letters findNoneMatchingLetters(Letters other) {
Set<Character> otherValues = other.extractValues();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Set을 사용해서 중복을 방지하고 O(1)의 시간 복잡도로 검색 속도가 향상되겠네요!
한 수 배워 갑니다~ 😚

List<Letter> filteredLetters = letters.stream()
.filter(letter -> !otherValues.contains(letter.getValue()))
.toList();

return new Letters(filteredLetters);
}

private Set<Character> extractValues() {
return letters.stream()
.map(Letter::getValue)
.collect(Collectors.toSet());
}

public int size() {
return letters.size();
}
}
55 changes: 55 additions & 0 deletions src/main/java/wordle/model/TileService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package wordle.model;

import java.util.List;

public class TileService {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 클래스명도 다른 도메인처럼 가시적인 클래스명으로 변경하면 더 좋을거 같습니당!🙂

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정답-입력 문자를 비교해서 결과를 도출하는 책임을 어디에 부여하면 좋을까 고민하다가 이 클래스를 만들게 되었어요.
지금 다시 봐도 역할이 참 모호한 것 같네요..ㅋㅋ 리팩토링 포인트로 놓고 고민해볼게요!

Copy link
Author

@samkimuel samkimuel Jun 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TileService -> LetterComparator로 좀 더 가시적?으로 변경했어요. 네이밍 어떠신지요 ㅋㅋ


private static final String ANSWER_TILE = "\uD83D\uDFE9";

private final TileStorage tileStorage;

public TileService(TileStorage tileStorage) {
this.tileStorage = tileStorage;
}

public Tiles create(Letters answerLetters, Letters inputLetters) {
LetterCounter letterCounter = new LetterCounter(answerLetters);
Tiles tiles = new Tiles(answerLetters.size());

processSamePositionAndValueLetters(answerLetters, inputLetters, letterCounter, tiles);
processSameValueLetters(answerLetters, inputLetters, letterCounter, tiles);
processNoneMatchLetters(answerLetters, inputLetters, tiles);

tileStorage.add(tiles);
return tiles;
}

private void processSamePositionAndValueLetters(Letters answerLetters, Letters inputLetters, LetterCounter letterCounter, Tiles tiles) {
Letters samePositionAndValueLetters = inputLetters.findSamePositionAndValueLetters(answerLetters);
letterCounter.decreaseCount(samePositionAndValueLetters);
tiles.addGreenTile(samePositionAndValueLetters);
}

private void processSameValueLetters(Letters answerLetters, Letters inputLetters, LetterCounter letterCounter, Tiles tiles) {
Letters sameValueLetters = inputLetters.findSameValueLetters(answerLetters);
Letters sameValueLettersForGrayTile = letterCounter.filterCanNotDecreaseCount(sameValueLetters);
tiles.addGrayTile(sameValueLettersForGrayTile);

Letters sameValueLettersForYellowTile = letterCounter.filterCanDecreaseCount(sameValueLetters);
letterCounter.decreaseCount(sameValueLettersForYellowTile);
tiles.addYellowTile(sameValueLettersForYellowTile);
}

private void processNoneMatchLetters(Letters answerLetters, Letters inputLetters, Tiles tiles) {
Letters noneMatchingLetters = inputLetters.findNoneMatchingLetters(answerLetters);
tiles.addGrayTile(noneMatchingLetters);
}

public boolean isAnswer(Tiles tiles) {
return tiles.isFilledWith(ANSWER_TILE);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서비스에서는 전체가 정답타일인지 물어보는 메소드를 호출하고, isFilledWith(ANSWER_TILE)를 tiles 안에서 호출하도록 하는 건 어떨까요?
그러면 서비스에서 ANSWER_TILE을 매개변수로 쓰지 않아도 될 거 같아 제안드려 봅니다~

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiles가 정답(ANSWER_TILE)에 대해 알 필요가 있을까 생각해서 해당 책임을 부여하지 않고 파라미터로 넘겼어요.
이름 때문에 관련 기능만 제공해야겠다는 생각을 해서 이렇게 구현했는데, 이 부분도 TileService 와 함께 고민해볼게요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tiles -> Result 클래스로 변경해서 isAnswer() 책임을 Result 클래스로 위임했습니다! 그래서 이 메서드는 삭제되었어요.

}

public List<Tiles> findAll() {
return tileStorage.findAll();
}
}
18 changes: 18 additions & 0 deletions src/main/java/wordle/model/TileStorage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package wordle.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class TileStorage {

private final List<Tiles> storage = new ArrayList<>();

public void add(Tiles tiles) {
storage.add(tiles);
}

public List<Tiles> findAll() {
return Collections.unmodifiableList(storage);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

변경이 불가능하도록 구현하신 부분이 좋네요! 👍

}
Loading