diff --git a/README.md b/README.md index 8fe711203..ca0e86a43 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,3 @@ -## [NEXTSTEP 플레이그라운드의 미션 진행 과정](https://github.com/next-step/nextstep-docs/blob/master/playground/README.md) - ---- -## 학습 효과를 높이기 위해 추천하는 미션 진행 방법 - ---- -1. 피드백 강의 전까지 미션 진행 -> 피드백 강의 전까지 혼자 힘으로 미션 진행. 미션을 진행하면서 하나의 작업이 끝날 때 마다 add, commit -> 예를 들어 다음 숫자 야구 게임의 경우 0, 1, 2단계까지 구현을 완료한 후 push - -![mission baseball](https://raw.githubusercontent.com/next-step/nextstep-docs/master/playground/images/mission_baseball.png) - ---- -2. 피드백 앞 단계까지 미션 구현을 완료한 후 피드백 강의를 학습한다. - ---- -3. Git 브랜치를 master 또는 main으로 변경한 후 피드백을 반영하기 위한 새로운 브랜치를 생성한 후 처음부터 다시 미션 구현을 도전한다. - -``` -git branch -a // 모든 로컬 브랜치 확인 -git checkout master // 기본 브랜치가 master인 경우 -git checkout main // 기본 브랜치가 main인 경우 - -git checkout -b 브랜치이름 -ex) git checkout -b apply-feedback -``` +1. 컴퓨터가 서로 다른 임의의 숫자를 3개 선택 +2. 플레이어가 입력한 문자열과 컴퓨터가 선택한 숫자를 비교하고 결과 반환 +3. 입력과 출력을 처리 \ No newline at end of file diff --git a/src/main/java/baseball/BaseballGame.java b/src/main/java/baseball/BaseballGame.java new file mode 100644 index 000000000..1288b032b --- /dev/null +++ b/src/main/java/baseball/BaseballGame.java @@ -0,0 +1,49 @@ +package baseball; + +import util.Terminal; + +import java.io.IOException; +import java.util.List; + +public class BaseballGame { + public static void main(String[] args) throws IOException { + while (true) { + Terminal.out("게임 시작!" + System.lineSeparator()); + Number targetNumber = RandomNumberGenerator.generate(); + BaseballStage stage = new BaseballStage(targetNumber); + if (proceed(stage)) { + return; + } + } + } + + private static boolean proceed(BaseballStage stage) throws IOException { + while (true) { + boolean proceed = stage.proceed(); + if (proceed) { + return askPlayEnd(stage.getHistory()); + } + } + } + + private static boolean askPlayEnd(List history) throws IOException { + while (true) { + Terminal.out("세 개의 숫자를 모두 맞히셨습니다! 게임 종료" + System.lineSeparator()); + + for (Discrimination discrimination : history) { + Terminal.out(discrimination.show()); + } + + String in = Terminal.in("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요." + System.lineSeparator()); + if (in.trim().equals("1")) { + return false; + } + + if (in.trim().equals("2")) { + return true; + } + + Terminal.out("1과 2중에서 입력해주세요"); + } + } +} diff --git a/src/main/java/baseball/BaseballStage.java b/src/main/java/baseball/BaseballStage.java new file mode 100644 index 000000000..c6e7cdc9c --- /dev/null +++ b/src/main/java/baseball/BaseballStage.java @@ -0,0 +1,38 @@ +package baseball; + +import util.Terminal; + +import java.io.IOException; +import java.util.*; + +public class BaseballStage { + private final Number targetNumber; + private final List history = new ArrayList<>(); + + public BaseballStage(Number number) { + this.targetNumber = number; + } + + public Number getTargetNumber() { + return this.targetNumber; + } + + public boolean proceed() throws IOException { + String in = Terminal.in("숫자를 입력해주세요 : "); + Discrimination discrimination = discriminate(Integer.parseInt(in)); + Terminal.out(discrimination.print()); + + return discrimination.getStrike() == 3; + } + + public Discrimination discriminate(int answer) { + Number compare = new Number(answer); + Discrimination discrimination = new Discrimination(targetNumber, compare); + history.add(discrimination); + return discrimination; + } + + public List getHistory() { + return new ArrayList<>(this.history); + } +} diff --git a/src/main/java/baseball/Discrimination.java b/src/main/java/baseball/Discrimination.java new file mode 100644 index 000000000..575ab79b1 --- /dev/null +++ b/src/main/java/baseball/Discrimination.java @@ -0,0 +1,92 @@ +package baseball; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.IntStream; + +public class Discrimination { + private final int input; + private final int strike; + private final int ball; + private final int out; + private final String[] visual = new String[3]; + + public Discrimination(Number base, Number compare) { + int[] compareArr = compare.get(); + int input = 0; + for (int i : compareArr) { + input = input * 10 + i; + } + this.input = input; + + int[] baseArr = base.get(); + Map baseMap = new HashMap<>(); + IntStream.range(0, 3).forEach(i -> baseMap.put(baseArr[i], i)); + + int strike = 0; + int ball = 0; + + for (int i = 0; i < compareArr.length; i++) { + if (baseMap.containsKey(compareArr[i])) { + if (baseMap.get(compareArr[i]) == i) { + visual[i] = "S"; + strike++; + } else { + visual[i] = "B"; + ball++; + } + + baseMap.remove(baseArr[i]); + } else { + visual[i] = "O"; + } + } + + this.strike = strike; + this.ball = ball; + this.out = baseMap.size(); + } + + public String print() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("[입력:%d] > ", this.input)); + + if (ball > 0) { + sb.append(String.format("%d볼 ", getBall())); + } + + if (strike > 0) { + sb.append(String.format("%d스트라이크", getStrike())); + } + + if (out == 3) { + sb.append("3아웃!"); + } + + sb.append(System.lineSeparator()); + return sb.toString(); + } + + public String show() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("[입력:%d] > ", this.input)); + for (String s : visual) { + sb.append(s); + } + + sb.append(System.lineSeparator()); + return sb.toString(); + } + + public int getStrike() { + return strike; + } + + public int getBall() { + return ball; + } + + public int getOut() { + return out; + } +} diff --git a/src/main/java/baseball/Number.java b/src/main/java/baseball/Number.java new file mode 100644 index 000000000..bae7c1445 --- /dev/null +++ b/src/main/java/baseball/Number.java @@ -0,0 +1,49 @@ +package baseball; + +import java.util.Arrays; + +public class Number { + private final int[] nums = new int[3]; + + public Number(int number) { + for (int i = 2; i >= 0; i--) { + nums[i] = number % 10; + number = number / 10; + } + } + + public int[] get() { + return Arrays.copyOf(nums, 3); + } + + @Override + public boolean equals(Object obj) { + if (obj.getClass() != this.getClass()) { + return false; + } + + int[] compare = ((Number) obj).get(); + + if (nums.length != compare.length) { + return false; + } + + for (int i = 0; i < this.nums.length; i++) { + if (nums[i] != compare[i]) { + return false; + } + } + + return true; + } + + @Override + public int hashCode() { + int hashCode = 1; + for (int num : nums) { + hashCode = 31 * hashCode + num; + } + + return hashCode; + } +} diff --git a/src/main/java/baseball/RandomNumberGenerator.java b/src/main/java/baseball/RandomNumberGenerator.java new file mode 100644 index 000000000..ac5688467 --- /dev/null +++ b/src/main/java/baseball/RandomNumberGenerator.java @@ -0,0 +1,20 @@ +package baseball; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class RandomNumberGenerator { + public static Number generate() { + List bucket = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); + Collections.shuffle(bucket); + + int num = 0; + for (int i = 0; i < 3; i++) { + num = num * 10 + bucket.get(i); + } + + return new Number(num); + } +} diff --git a/src/main/java/util/Terminal.java b/src/main/java/util/Terminal.java new file mode 100644 index 000000000..7be11cb5e --- /dev/null +++ b/src/main/java/util/Terminal.java @@ -0,0 +1,18 @@ +package util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class Terminal { + + public static String in(String message) throws IOException { + BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); + System.out.print(message); + return br.readLine(); + } + + public static void out(String str) { + System.out.print(str); + } +} diff --git a/src/test/java/baseball/BaseBallTest.java b/src/test/java/baseball/BaseBallTest.java new file mode 100644 index 000000000..1697c6d1f --- /dev/null +++ b/src/test/java/baseball/BaseBallTest.java @@ -0,0 +1,136 @@ +package baseball; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class BaseBallTest { + + @Test + void 컴퓨터가_세_개의_숫자를_선택() { + // given + Number num = RandomNumberGenerator.generate(); + BaseballStage baseballStage = new BaseballStage(num); + + // when + Number base = baseballStage.getTargetNumber(); + + // then + assertThat(base.get().length).isEqualTo(3); + assertThat(base).isEqualTo(num); + } + + @ParameterizedTest + @CsvSource(value = {"135:218", "135:241", "248:435", "248:134", "123:389", "123:739"}, delimiter = ':') + void one_ball(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(1); + assertThat(result.getStrike()).isEqualTo(0); + assertThat(result.getOut()).isEqualTo(2); + } + + @ParameterizedTest + @CsvSource(value = {"135:213", "135:251", "248:452", "248:854", "123:219", "123:319"}, delimiter = ':') + void two_ball(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(2); + assertThat(result.getStrike()).isEqualTo(0); + assertThat(result.getOut()).isEqualTo(1); + } + + @ParameterizedTest + @CsvSource(value = {"135:513", "135:351"}, delimiter = ':') + void three_ball(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(3); + assertThat(result.getStrike()).isEqualTo(0); + assertThat(result.getOut()).isEqualTo(0); + } + + @ParameterizedTest + @CsvSource(value = {"135:148", "135:238", "135:245"}, delimiter = ':') + void one_strike(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(0); + assertThat(result.getStrike()).isEqualTo(1); + assertThat(result.getOut()).isEqualTo(2); + } + + @ParameterizedTest + @CsvSource(value = {"135:138", "135:235", "135:145"}, delimiter = ':') + void two_strike(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(0); + assertThat(result.getStrike()).isEqualTo(2); + assertThat(result.getOut()).isEqualTo(1); + } + + @ParameterizedTest + @CsvSource(value = {"135:215", "135:231", "248:438", "248:234", "123:329", "123:139"}, delimiter = ':') + void one_ball_one_strike(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(1); + assertThat(result.getStrike()).isEqualTo(1); + assertThat(result.getOut()).isEqualTo(1); + } + + @ParameterizedTest + @CsvSource(value = {"135:135", "248:248", "123:123"}, delimiter = ':') + void three_strike(String targetNumber, String input) { + // given + BaseballStage baseballStage = new BaseballStage(new Number(Integer.parseInt(targetNumber))); + int compare = Integer.parseInt(input); + + // when + Discrimination result = baseballStage.discriminate(compare); + + // then + assertThat(result.getBall()).isEqualTo(0); + assertThat(result.getStrike()).isEqualTo(3); + assertThat(result.getOut()).isEqualTo(0); + } +} \ No newline at end of file