-
Notifications
You must be signed in to change notification settings - Fork 43
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
[4기][3주차] Wordle 과제 제출 - John #14
base: main
Are you sure you want to change the base?
Changes from all commits
7431331
cddc800
5a41792
4b2c9fe
5200abd
7f00a79
5bf80e8
6ae85d3
3a257c3
d3232df
e12d323
77e7800
6c630fa
ad73d76
0a3754d
494ccc1
5f6a416
b5bdd40
a715736
e8d81be
814e83a
d8d5866
fdc1f97
0825f39
5eb81ea
f9c5bf3
317fb84
87fd347
4940f8d
3619c3a
767ffff
0b8c2d9
ea030d0
1726d2b
3df7130
f73b636
4431957
e903ca9
a1f3738
a28a8ce
8348de1
4aade01
4076859
6b830c9
d0fbdc1
a92bfe5
a322978
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# 기능 설명 | ||
|
||
### controller | ||
1. GameHost | ||
- GameService를 통해 게임을 실행한다. | ||
|
||
### service | ||
1. GameService | ||
- 여러 Backend / UI Serice를 사용하여 게임을 실행한다. | ||
|
||
### backend | ||
1. InputManager | ||
- 사용자의 입력을 Word 객체로 전달 받는다 | ||
2. InputViewManger | ||
- ViewManger을 주입받는다. | ||
- 단어 입력 전 / 후 출력을 관리하고, InputManager을 통해 단어를 받는다. | ||
3. WordsGenerator | ||
- 날짜에 따라 오늘의 정답 단어를 AnswerWord로 추출한다 | ||
|
||
### ui | ||
1. ViewManger | ||
- 사용자에게 출력하는 모든 로직을 담당한다 | ||
|
||
### domain | ||
1. Word | ||
- 입력받은 단어에 대해 저장 및 검증 | ||
2. AnswerWord | ||
- Word를 상속받아, 다른 Word와의 비교 결과를 산출 | ||
3. Result | ||
- 사용자의 입력 하나에 대한 게임 결과를 저장 | ||
4. TileColor | ||
- Enum으로써, TileColor 별 표시 할 데이터를 저장 | ||
5. Coin | ||
- 문자 입력 가능 횟수를 의미 | ||
- 최초 코인 개수를 통해 생성 | ||
- 문자 입력시 코인 개수 감소 | ||
- 코인이 남아있는지 여부 확인 | ||
6. User | ||
- Coin을 가지고 게임을 수행한다. | ||
7. GameHost | ||
- AnswerWord를 초기화 한다 | ||
- 사용자의 입력에 대해 정답과 비교하여, 결과를 출력한다. | ||
|
||
### utils | ||
1. FileUtils | ||
- 파일 경로를 받아 Stream<String>을 반환 | ||
2. LocalDateTimeUtils | ||
- 입력받은 2개의 날짜 차이를 반환 | ||
3. StringUtils | ||
- 입력받은 문자에 대해 5개의 소문자로 구성된 문자인지 검증 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# 기능 명세 | ||
|
||
### 정답 단어 추출하기 | ||
1. 파일로부터 String데이터를 읽어와야 한다. | ||
2. 파일로부터 읽어온 데이터중, (2021-6-19 과 오늘 날짜의 차이) % (파일로부터 읽어온 String 개수) 의 위치에 있는 단어를 정답 단어로 선출한다. | ||
|
||
### 단어 입력받기 | ||
1. 사용자로부터 단어를 입력을 받는다. 단, 소문자 5개로 구성된 단어야만 한다. | ||
2. 정상적이지 않은 입력이 발생했을때, 다시 입력을 받아야 한다. | ||
|
||
### 정답 단어와 사용자가 입력한 단어 비교하기 | ||
1. 정답 단어와 사용자의 단어를 비교했을때, 위치까지 똑같은 Spelling과 위치는 다르나 정답 단어에 존재하는 Spelling 그리고 아예 관계없는 Spelling을 구분한 결과값이 있어야 한다. | ||
|
||
### 게임 결과를 출력하기 | ||
1. 정답 단어와 사용자의 단어 비교 결과를 색깔 박스를 통해 표시를 해주어야 한다. | ||
2. 결과 출력시, 이전 결과도 함께 출력 해 주어야 한다. | ||
3. 유저의 게임 성공, 실패에 대한 결과 출력 및 실패시 엔 오늘의 단어도 같이 출력 | ||
|
||
### 게임 횟수 제한하기 | ||
1. 사용자가 최대 6번까지 입력 받을 수 있게 제한. 6번 이내에 클리어 시 게임 종료. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# 페어프로그래밍 룰 | ||
|
||
### 네비게이터 | ||
1. 오류를 너무 빨리 체크하지 말자 | ||
2. 높은 추상화 수준의 지시를 하자(큰 그림을 제안하자) | ||
3. 자신의 키보드를 사용하자 | ||
|
||
### 드라이버 | ||
1. 천천히 코딩하자. 네비게이터와 항상 말을 하면서 코딩하자 | ||
2. 네비게이터가 말이 없다면 동기화가 안된것. 동기화를 다시 하고 드라이빙하자 | ||
3. 휴식하자. | ||
4. 경청하자. 네비게이터가 제안할때는 키보드에서 손을 떼자. | ||
|
||
|
||
### 네비게이터 & 드라이버 | ||
1. 시작하기 전에 모든 알림을 끄자. (필요한 어플만 켜놓자) | ||
2. 자주 역할을 전환하자. (시간을 정해두고) | ||
3. 항상 설계를 합의하고 시작하자. | ||
--- | ||
- [codeStyle](https://github.com/google/styleguide/blob/gh-pages/intellij-java-google-style.xml) | ||
- 페어그래밍 툴 : Intellij Code With Me | ||
- 각자 20분 코딩 & 10분회고 & 10분 휴식 | ||
- 회고 10분이 넘어가면 다시 처음부터 회고 | ||
- 자바 코드 컨벤션을 지키면서 프로그래밍한다. | ||
- 기본적으로 Google Java Style Guide을 원칙으로 한다. | ||
- 단, 들여쓰기는 '2 spaces'가 아닌 '4 spaces'로 한다. | ||
- indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다. | ||
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. | ||
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. | ||
- 3항 연산자를 쓰지 않는다. | ||
- 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다. | ||
- 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다. | ||
- else 예약어를 쓰지 않는다. | ||
- 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다. | ||
- else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import com.wodle.controller.GameHost; | ||
import com.wodle.backend.InputManagerImpl; | ||
import com.wodle.backend.InputMangerProxy; | ||
import com.wodle.ui.ViewManagerImpl; | ||
import com.wodle.backend.WordGeneratorImpl; | ||
|
||
public class Application { | ||
|
||
public static void main(String[] args) { | ||
ViewManagerImpl viewManager = new ViewManagerImpl(); | ||
InputManagerImpl inputMangerProxy = new InputMangerProxy(viewManager); | ||
WordGeneratorImpl wordGenerator = new WordGeneratorImpl(); | ||
GameHost host = new GameHost( | ||
inputMangerProxy, | ||
viewManager, | ||
wordGenerator | ||
); | ||
|
||
host.play(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.wodle.backend; | ||
|
||
import com.wodle.domain.Word; | ||
|
||
public interface InputManager { | ||
Word inputWord(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.wodle.backend; | ||
|
||
import camp.nextstep.edu.missionutils.Console; | ||
import com.wodle.domain.Word; | ||
import java.util.NoSuchElementException; | ||
|
||
public class InputManagerImpl implements InputManager{ | ||
|
||
public Word inputWord() { | ||
try { | ||
String userInput = Console.readLine(); | ||
return new Word(userInput); | ||
} catch (IllegalArgumentException e) { | ||
throw e; | ||
} catch (NoSuchElementException e) { | ||
throw new NoSuchElementException("No such line"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.wodle.backend; | ||
|
||
import com.wodle.domain.Word; | ||
import com.wodle.ui.ViewManagerImpl; | ||
|
||
public class InputMangerProxy extends InputManagerImpl { | ||
|
||
private final ViewManagerImpl viewManager; | ||
|
||
public InputMangerProxy(ViewManagerImpl viewManager) { | ||
this.viewManager = viewManager; | ||
} | ||
|
||
@Override | ||
public Word inputWord() { | ||
try { | ||
viewManager.printRequestWordInput(); | ||
return super.inputWord(); | ||
} catch (Exception e) { | ||
viewManager.notifyInvalidInputWord(); | ||
return this.inputWord(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.wodle.backend; | ||
|
||
import com.wodle.domain.AnswerWord; | ||
|
||
public interface WordGenerator { | ||
AnswerWord getTodayWord(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.wodle.backend; | ||
|
||
import com.wodle.domain.AnswerWord; | ||
import com.wodle.utils.FileUtils; | ||
import com.wodle.utils.LocalDateTimeUtils; | ||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
public class WordGeneratorImpl implements WordGenerator{ | ||
|
||
private static final String FILE_PATH = "words.txt"; | ||
|
||
public AnswerWord getTodayWord() { | ||
try (Stream<String> stream = FileUtils.getInstance().getStreamByFileName(FILE_PATH)) { | ||
List<String> wordList = stream.collect(Collectors.toList()); | ||
long fileMaxLines = wordList.size(); | ||
int wordIndex = getTodayWordIndex(fileMaxLines); | ||
|
||
String todayWord = wordList.get(wordIndex); | ||
return new AnswerWord(todayWord); | ||
} catch (RuntimeException e) { | ||
throw new RuntimeException("can not setting word", e); | ||
} | ||
} | ||
|
||
private int getTodayWordIndex(long totalCount) { | ||
LocalDateTime base = LocalDate.of(2021, 6, 19) | ||
.atStartOfDay(); | ||
LocalDateTime now = LocalDateTime.now(); | ||
|
||
long betweenDays = LocalDateTimeUtils.getInstance().getBetweenDays(base, now); | ||
|
||
return (int) (betweenDays % totalCount); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.wodle.controller; | ||
|
||
import com.wodle.service.GameService; | ||
import com.wodle.backend.InputManagerImpl; | ||
import com.wodle.ui.ViewManager; | ||
import com.wodle.backend.WordGenerator; | ||
|
||
public class GameHost { | ||
|
||
private final GameService gameService; | ||
public GameHost(InputManagerImpl inputManagerProxy, ViewManager viewManager, | ||
WordGenerator wordGenerator) { | ||
this.gameService = new GameService( | ||
wordGenerator, viewManager, inputManagerProxy | ||
); | ||
} | ||
|
||
public void play() { | ||
gameService.play(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package com.wodle.domain; | ||
|
||
import java.util.Arrays; | ||
import java.util.LinkedList; | ||
import java.util.List; | ||
|
||
public class AnswerWord extends Word { | ||
|
||
private final boolean[] alphabetExistInfoStore = new boolean[26]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이렇게 정답 체크를 해결하셨군요ㅎㅎ |
||
|
||
public AnswerWord(String word) { | ||
super(word); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super 클래스인
위와 같은 메서드를 호출하는데 단순히 전체적으로 생성자에서 메서드를 호출하는 클래스를 상속하면 객체 생성시 ex) 누군가가 Word의 이 경우에
위와 같이 인터페이스로 사용해보는 건 어떨까요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AnswerWord가 Word를 상속받는 이유는 Word가 제공하는 검증 기능과 AnswerWord가 가지고있는 정답 추론 기능을 함께 사용하기 위함입니다. 그리고 말씀하신 것처럼 Word의 생성자에 validate()를 제거해야한다면... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
ㅠ경험이 부족해 어떤 방법이 최선의 방법인지는 잘 모르겠습니다ㅠ |
||
Arrays.fill(alphabetExistInfoStore, false); | ||
|
||
char[] words = word.toCharArray(); | ||
|
||
for (char c : words) { | ||
alphabetExistInfoStore[c - 'a'] = true; | ||
} | ||
} | ||
|
||
public Result compare(Word target) { | ||
char[] sourceWordArray = this.getWordArray(); | ||
char[] targetWordArray = target.getWordArray(); | ||
List<TileColor> matchResult = new LinkedList<>(); | ||
|
||
for (int i = 0; i < sourceWordArray.length; i++) { | ||
matchResult.add(match(sourceWordArray, targetWordArray, i)); | ||
} | ||
|
||
return new Result(matchResult); | ||
} | ||
|
||
private TileColor match(char[] source, char[] target, int index) { | ||
if (source[index] == target[index]) { | ||
return TileColor.GREEN; | ||
} | ||
|
||
if (alphabetExistInfoStore[target[index] - 'a']) { | ||
return TileColor.YELLOW; | ||
} | ||
|
||
return TileColor.GREY; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.wodle.domain; | ||
|
||
public class Coins { | ||
|
||
private int coin; | ||
|
||
public Coins(int availableCoin) { | ||
validate(availableCoin); | ||
|
||
this.coin = availableCoin; | ||
} | ||
|
||
public void use() { | ||
int tempCoin = this.coin - 1; | ||
validate(tempCoin); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분은 정말 궁금하네요ㅎ int 변수를 생성하신 이유가 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만약 this.coin이 0일때, this.coin = this.coin -1; validate(this.coin); 그래서 this.coin을 변경하기 전에 검증 용도로 임시 변수를 만들어 둔 것 입니다! |
||
this.coin = tempCoin; | ||
} | ||
|
||
private void validate(int availableCoin) { | ||
if (availableCoin < 0) { | ||
throw new IllegalArgumentException("Coin can be set under 0"); | ||
} | ||
} | ||
|
||
|
||
public boolean isEmpty() { | ||
return this.coin == 0; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.wodle.domain; | ||
|
||
public class GameMachine { | ||
|
||
private final AnswerWord word; | ||
private boolean gameEnd = false; | ||
|
||
public GameMachine(AnswerWord word) { | ||
this.word = word; | ||
} | ||
|
||
public boolean isGameNotEnd() { | ||
return !gameEnd; | ||
} | ||
|
||
public Result compareWord(Word inputWord) { | ||
Result result = this.word.compare(inputWord); | ||
this.gameEnd = result.isGameEnd(); | ||
return result; | ||
} | ||
|
||
public AnswerWord getWord() { | ||
return word; | ||
} | ||
|
||
public boolean getGameEnd() { | ||
return gameEnd; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
위의 변수들의 타입이 구체화된 타입으로 선언되어 있네요!
구체적인 타입으로 변수를 선언하기 보다는 추상화한 인터페이스의 타입으로 변수를 선언하는게 재사용성과 다형성에 이점이 있다고 생각하는데 John님은 어떻게 생각하시나요??