diff --git a/README.md b/README.md index b722ac00..ffe85ac2 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ - 6x5 격자를 통해서 5글자 단어를 6번 만에 추측한다. - 플레이어가 답안을 제출하면 프로그램이 정답과 제출된 단어의 각 알파벳 종류와 위치를 비교해 판별한다. - 판별 결과는 흰색의 타일이 세 가지 색(초록색/노란색/회색) 중 하나로 바뀌면서 표현된다. - - 맞는 글자는 초록색, 위치가 틀리면 노란색, 없으면 회색 - - 두 개의 동일한 문자를 입력하고 그중 하나가 회색으로 표시되면 해당 문자 중 하나만 최종 단어에 나타난다. + - 맞는 글자는 초록색, 위치가 틀리면 노란색, 없으면 회색 + - 두 개의 동일한 문자를 입력하고 그중 하나가 회색으로 표시되면 해당 문자 중 하나만 최종 단어에 나타난다. - 정답과 답안은 `words.txt`에 존재하는 단어여야 한다. - 정답은 매일 바뀌며 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) 번째의 단어이다. @@ -65,11 +65,46 @@ spill - [Java 코드 컨벤션](https://github.com/woowacourse/woowacourse-docs/tree/master/styleguide/java) 가이드를 준수하며 프로그래밍한다. - 프로그래밍 요구 사항에서 별도의 변경 불가 안내가 없는 한 자유롭게 파일을 수정하고 패키지를 이동할 수 있다. - indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용한다. - - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. - - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. + - 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다. + - 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다. - 3항 연산자를 쓰지 않는다. - 함수(또는 메서드)의 길이가 15라인을 넘어가지 않도록 구현한다. - - 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다. + - 함수(또는 메서드)가 한 가지 일만 잘 하도록 구현한다. - else 예약어를 쓰지 않는다. - - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다. - - else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. + - 힌트: if 조건절에서 값을 return하는 방식으로 구현하면 else를 사용하지 않아도 된다. + - else를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다. + +--- + +# 업무 방식 - 페어프로그래밍 + +* Intellij Code With me 를 사용하여 페어 프로그래밍을 진행 합니다. + * 이거 재밌네요 +* Start role + * navigator: jimbae + * driver: yj +* Role 스위치 방식 + * 각각의 기능 혹은 메소드 단위로 드라이버와 네비게이터를 지정하여 진행한다. +* Repository + * fork 'woowahan-pjs/java-wordle' repository +* Requirements analysis method + * In -> Out + +# 기능 정의 + +* 정답 : s p i l l +* X X Y G X + + * 입력 : h e l l o + * +* hello 와 label 비교하여 단어 맞추기 +* enum : YELLOW, GREEN, GREY + + * 위치와 단어가 동일하면 GREEN + * 단어만 존재하면 YELLOW + * 없으면 GREY +* words.txt 파일에서 오늘의 단어를 선택한다. + * 단어는 ((현재 날짜 - 2021년 6월 19일) % 배열의 크기) +* 결과를 저장하는 객체 - ArrayList +* 입력을 담당하는 객체 +* 다섯글자만 입력 가능하도록 validation \ No newline at end of file diff --git a/src/main/java/.gitkeep b/src/main/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/java/controller/WordleController.java b/src/main/java/controller/WordleController.java new file mode 100644 index 00000000..9d26eb37 --- /dev/null +++ b/src/main/java/controller/WordleController.java @@ -0,0 +1,28 @@ +package controller; + +import domain.Colors; +import domain.TryResult; +import domain.Words; +import ui.IOUtils; +import ui.InputView; +import ui.ResultView; + +public class WordleController { + + private static final int PLAY_ROUND = 6; + private static final String WORDS_TXT = "words.txt"; + + public static void main(String[] args) { + Words words = Words.of(IOUtils.readFromResource(WORDS_TXT)); + + ResultView.startComent(); + + TryResult tryResult = new TryResult(); + int round = 0; + while (round++ < PLAY_ROUND && !tryResult.isFinished()) { + Colors colors = words.matchingAnswer(InputView.inputComment()); + tryResult.addTry(colors); + ResultView.results(tryResult); + } + } +} diff --git a/src/main/java/domain/Color.java b/src/main/java/domain/Color.java new file mode 100644 index 00000000..c93bfcd4 --- /dev/null +++ b/src/main/java/domain/Color.java @@ -0,0 +1,18 @@ +package domain; + +public enum Color { + GREY ("⬜"), + YELLOW ("\uD83D\uDFE8"), + GREEN ("\uD83D\uDFE9"); + + private String icon; + + Color(String icon) { + this.icon = icon; + } + + @Override + public String toString() { + return icon; + } +} diff --git a/src/main/java/domain/Colors.java b/src/main/java/domain/Colors.java new file mode 100644 index 00000000..952c2c42 --- /dev/null +++ b/src/main/java/domain/Colors.java @@ -0,0 +1,34 @@ +package domain; + +import java.util.List; +import java.util.Objects; + +public class Colors { + private static final List ALL_GREEN = List.of(Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN); + private final List colors; + + public Colors(List colors) { + this.colors = colors; + } + + public void add(Color color) { + colors.add(color); + } + + public boolean isAllGreen() { + return ALL_GREEN.equals(colors); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Colors colors1 = (Colors) o; + return Objects.equals(colors, colors1.colors); + } + + @Override + public int hashCode() { + return Objects.hash(colors); + } +} diff --git a/src/main/java/domain/TryResult.java b/src/main/java/domain/TryResult.java new file mode 100644 index 00000000..363a4fb3 --- /dev/null +++ b/src/main/java/domain/TryResult.java @@ -0,0 +1,28 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class TryResult { + private List results = new ArrayList<>(); + private boolean finished; + + public void addTry(Colors colors) { + if (colors.isAllGreen()) { + finished = true; + } + results.add(colors); + } + + public int count() { + return results.size(); + } + + public List getResults() { + return results; + } + + public boolean isFinished() { + return finished; + } +} diff --git a/src/main/java/domain/Word.java b/src/main/java/domain/Word.java new file mode 100644 index 00000000..4ee838d6 --- /dev/null +++ b/src/main/java/domain/Word.java @@ -0,0 +1,56 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class Word { + private final String word; + + public Word(String word) { + if (word.length() != 5) { + throw new IllegalArgumentException("단어는 다섯글자로만 입력 가능합니다"); + } + this.word = word; + } + + public Colors compareWith(Word input) { + List result = new ArrayList<>(); + char[] answerArray = word.toCharArray(); + char[] inputArray = input.word.toCharArray(); + + for (int i = 0; i < answerArray.length; i++) { + result.add(mapped(answerArray[i], inputArray[i])); + } + + return new Colors(result); + } + + private Color mapped(char answer, char input) { + if (answer == input) { + return Color.GREEN; + } + if (isContains(input)) { + return Color.YELLOW; + } + return Color.GREY; + } + + private boolean isContains(char c) { + return this.word.contains(String.valueOf(c)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Word word1 = (Word) o; + return Objects.equals(word, word1.word); + } + + @Override + public int hashCode() { + return Objects.hash(word); + } + +} diff --git a/src/main/java/domain/Words.java b/src/main/java/domain/Words.java new file mode 100644 index 00000000..768799bf --- /dev/null +++ b/src/main/java/domain/Words.java @@ -0,0 +1,38 @@ +package domain; + +import java.time.LocalDate; +import java.time.Period; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class Words { + private static final LocalDate BASE_DATE_FOR_ANSWER = LocalDate.of(2021, 6, 19); + private final List words; + + public Words(List words) { + this.words = Collections.unmodifiableList(words); + } + + public static Words of(List strings) { + return new Words(strings.stream().map(Word::new).collect(Collectors.toList())); + } + + public Word answer(LocalDate from) { + Period period = Period.between(BASE_DATE_FOR_ANSWER, from); + int range = period.getDays() % words.size(); + return words.get(range); + } + + public Colors matchingAnswer(Word input) { + validate(input); + Word answer = answer(LocalDate.now()); + return answer.compareWith(input); + } + + private void validate(Word input) { + if (!words.contains(input)) { + throw new IllegalArgumentException("단어집에 없는 단어를 선택하였습니다."); + } + } +} diff --git a/src/main/java/ui/IOUtils.java b/src/main/java/ui/IOUtils.java new file mode 100644 index 00000000..0203cd2f --- /dev/null +++ b/src/main/java/ui/IOUtils.java @@ -0,0 +1,43 @@ +package ui; + +import domain.Word; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class IOUtils { + + private IOUtils(){} + + public static List readFromResource(String resourceName){ + URL txtUrl = IOUtils.class.getClassLoader().getResource(resourceName); + try { + List words = Files.readAllLines(Paths.get(txtUrl.toURI())); + return words; + } catch (IOException e) { + System.out.println("파일을 읽는도중 문제가 발생했습니다."); + throw new RuntimeException(); + } catch (URISyntaxException e) { + System.out.println("존재하지 않는 경로 입니다."); + throw new RuntimeException(); + } + } + + public static String[] readFromResource2(String resourceName){ + URL txtUrl = IOUtils.class.getClassLoader().getResource(resourceName); + try { + List words = Files.readAllLines(Paths.get(txtUrl.toURI())); + return words.toArray(new String[words.size()]); + } catch (IOException e) { + System.out.println("파일을 읽는도중 문제가 발생했습니다."); + throw new RuntimeException(); + } catch (URISyntaxException e) { + System.out.println("존재하지 않는 경로 입니다."); + throw new RuntimeException(); + } + } +} diff --git a/src/main/java/ui/InputView.java b/src/main/java/ui/InputView.java new file mode 100644 index 00000000..fea0eae9 --- /dev/null +++ b/src/main/java/ui/InputView.java @@ -0,0 +1,15 @@ +package ui; + +import domain.Word; + +import java.util.Scanner; + +public class InputView { + private InputView(){} + + public static Word inputComment() { + Scanner scanner = new Scanner(System.in); + System.out.println("정답을 입력해 주세요.\n"); + return new Word(scanner.nextLine()); + } +} diff --git a/src/main/java/ui/ResultView.java b/src/main/java/ui/ResultView.java new file mode 100644 index 00000000..88149656 --- /dev/null +++ b/src/main/java/ui/ResultView.java @@ -0,0 +1,26 @@ +package ui; + +import domain.Colors; +import domain.TryResult; + +import java.util.List; + +public class ResultView { + + private ResultView(){} + + public static void startComent() { + System.out.println("WORDLE을 6번 만에 맞춰 보세요.\n시도의 결과는 타일의 색 변화로 나타납니다.\n"); + } + + public static void results(TryResult tryResult) { + List results = tryResult.getResults(); + if (tryResult.isFinished()) { + System.out.println(String.format("%d/6", tryResult.count())); + } + + for (Colors colors : results) { + System.out.println(colors); + } + } +} diff --git a/src/test/java/.gitkeep b/src/test/java/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/test/java/WordleTest.java b/src/test/java/WordleTest.java new file mode 100644 index 00000000..2f7bc229 --- /dev/null +++ b/src/test/java/WordleTest.java @@ -0,0 +1,35 @@ +import domain.Colors; +import domain.Word; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import ui.IOUtils; + +import java.util.Arrays; +import java.util.List; + +import static domain.Color.*; + +public class WordleTest { + @Test + void compare() { + Word answer = new Word("spill"); + Colors colors = answer.compareWith(new Word("hello")); + Assertions.assertEquals(new Colors(Arrays.asList(GREY, GREY, YELLOW, GREEN, GREY)), colors); + } + + @Test + void readFile() { + //when + List words = IOUtils.readFromResource("words.txt"); + + //then + Assertions.assertEquals(words.get(0), "cigar"); + } + + @Test + void sizeCheck() { + Assertions.assertThrows(IllegalArgumentException.class, () -> { + new Word("aaaa"); + }); + } +} \ No newline at end of file diff --git a/src/test/java/WordsTest.java b/src/test/java/WordsTest.java new file mode 100644 index 00000000..7435de08 --- /dev/null +++ b/src/test/java/WordsTest.java @@ -0,0 +1,31 @@ +import domain.Word; +import domain.Words; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.Arrays; + +public class WordsTest { + + @Test + void getArrayLocation(){ + //given + Words words = Words.of(Arrays.asList("aaaaa", "bbbbb")); + + //when + Word answers = words.answer(LocalDate.of(2021, 6, 20)); + + //then + Assertions.assertEquals(answers, new Word("bbbbb")); + } + + @Test + void validation() { + Words words = Words.of(Arrays.asList("aaaaa")); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + words.matchingAnswer(new Word("bbbbb")); + }); + } +} diff --git a/src/test/java/domain/ColorsTest.java b/src/test/java/domain/ColorsTest.java new file mode 100644 index 00000000..e52fe3fe --- /dev/null +++ b/src/test/java/domain/ColorsTest.java @@ -0,0 +1,19 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ColorsTest { + + @DisplayName("Colors equals 테스트") + @Test + void equalsTest() { + List green = List.of(Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN); + Colors colors = new Colors(green); + assertThat(colors.isAllGreen()).isTrue(); + } +} \ No newline at end of file