diff --git a/README.md b/README.md index e69de29b..da07bf41 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,41 @@ + + +## 기능목록 + +여기서 게임은 숫자야구게임 1판을 의미한다 (새로운 정답을 만들고 유저가 맞출 때까지 시도) + +- [x] 게임을 반복하는 기능 (유저에게 계속할지를 물어봄) +- [x] 게임을 진행하는 기능 +- [x] 숫자야구게임의 볼조합을 생성하는 기능 +- [x] 두 볼조합을 통해 결과를 생성하는 기능 +- [x] 생성된 결과를 유저가 보기 쉬운 메세지로 만들기 + +## 어떻게 구현할까?? + +1. junit 관련 살펴보기 (간단한 예제 + 탐험) +2. mockito 를 이용한 간단한 테스트 +3. README.md 작성 +4. 각 기능 구현 (가능하면 테스트랑 같이) +5. 컨벤션 확인 (리뷰) + +- 일단 자바 문법에 익숙해졌으면 (최소한 자주 쓸 부분은) +- 테스트코드를 작성하는 이유중 하나도 코드를 막 고쳐보기 위함 (특히 여러가지 자료구조등을 사용해보고 연습해보고 싶어서) + + + + +### test + +// 테스트 객체 개념 +https://medium.com/@SlackBeck/mock-object%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-85159754b2ac + +// Intellij Idea junit +https://examples.javacodegeeks.com/desktop-java/ide/intellij-idea-create-test-tutorial/ +https://www.jetbrains.com/help/idea/tdd-with-intellij-idea.html + + +### 자바 익숙해지기... +https://1nyoung.tistory.com/14 +https://jdm.kr/blog/181 +https://github.com/winterbe/java8-tutorial +https://www.acmicpc.net/blog/view/3 \ No newline at end of file diff --git a/src/main/java/BallCombiGenerator.java b/src/main/java/BallCombiGenerator.java new file mode 100644 index 00000000..acce5bea --- /dev/null +++ b/src/main/java/BallCombiGenerator.java @@ -0,0 +1,59 @@ +import java.util.Arrays; +import java.util.Random; +import java.util.stream.IntStream; + +import static java.lang.Integer.max; + +public class BallCombiGenerator { + + public int[] genBallCombi() { + Random rand = new Random(); + + int [] ballPnts = IntStream.range(1, 10).toArray(); + + // shuffle ballPnts + for (int from = 0; from < ballPnts.length; from++) { + int to = rand.nextInt(ballPnts.length); + + int tmp = ballPnts[from]; + ballPnts[from] = ballPnts[to]; + ballPnts[to] = tmp; + } + + return Arrays.copyOfRange(ballPnts, 0, 3); + } + + public boolean isValid(int[] ballCombi) { + if (ballCombi.length != 3) return false; + + for (int i = 0; i < ballCombi.length; i++) { + int pnt = ballCombi[i]; + if (pnt <= 0 || 10 <= pnt) return false; + } + + // check duplicated number + int [] pntCnt = new int[10]; + Arrays.stream(ballCombi).forEach((pnt) -> pntCnt[pnt]++); + + int maxPntCnt = Arrays.stream(ballCombi) + .map(pnt -> pntCnt[pnt]) + .reduce((a, b) -> max(a, b)) + .getAsInt(); + + return maxPntCnt <= 1; + } + + public int[] toBallCombi(String ballCombiStr) { + if (ballCombiStr.length() != 3) return new int[0]; + + int [] ballCombi = new int[3]; + for (int i = 0; i < ballCombiStr.length(); i++) { + char c = ballCombiStr.charAt(i); + if (c <= '0' || '9' < c) return new int[0]; + + ballCombi[i] = c - '0'; + } + + return ballCombi; + } +} diff --git a/src/main/java/Game.java b/src/main/java/Game.java new file mode 100644 index 00000000..f3d42a1e --- /dev/null +++ b/src/main/java/Game.java @@ -0,0 +1,62 @@ +import java.util.Scanner; + +public class Game { + + final private int STRIKE = 0; + final private int BALL = 1; + + private Scanner sc; + private BallCombiGenerator generator; + private Referee referee; + + public Game() { + sc = new Scanner(System.in); + generator = new BallCombiGenerator(); + referee = new Referee(); + } + + public void play() { + + int [] ansBallCombi = generator.genBallCombi(); + + for (int trial = 1; ; trial++) { + int [] userBallCombi; + + System.out.printf("숫자를 입력해주세요: "); + String userBallCombiStr = sc.next(); // + userBallCombi = generator.toBallCombi(userBallCombiStr); + while (!generator.isValid(userBallCombi)) { + System.out.printf("잘못된 입력입니다. 숫자를 입력해주세요: "); + userBallCombiStr = sc.next(); // + userBallCombi = generator.toBallCombi(userBallCombiStr); + } + + int [] judgement = referee.judge(ansBallCombi, userBallCombi); + + if (judgement[STRIKE] == 3) { + System.out.printf("3개의 숫자를 모두 맞히셨습니다! 게임 종료 (%d 시도)\n", trial); + break; + } + + printJudgement(judgement); + } + } + + private void printJudgement(int [] judgement) { + if (judgement[STRIKE] == 0 && judgement[BALL] == 0) { + System.out.println("낫싱"); + } + + String str = ""; + + if (0 < judgement[STRIKE]) { + str += String.format("%d 스트라이크 ", judgement[STRIKE]); + } + + if (0 < judgement[BALL]) { + str += String.format("%d 볼", judgement[BALL]); + } + + System.out.println(str); + } +} diff --git a/src/main/java/GameExecutor.java b/src/main/java/GameExecutor.java new file mode 100644 index 00000000..e71fa14c --- /dev/null +++ b/src/main/java/GameExecutor.java @@ -0,0 +1,18 @@ +import java.util.Scanner; + +public class GameExecutor { + public static void main(String[] args) { + + Scanner sc = new Scanner(System.in); + // 지금은 아무 상태도 가지고 있지 않기에 동일한 game을 사용 + Game game = new Game(); + + while (true) { + game.play(); + + System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요. "); + + if (2 == sc.nextInt()) break; + } + } +} diff --git a/src/main/java/Referee.java b/src/main/java/Referee.java new file mode 100644 index 00000000..d16760b1 --- /dev/null +++ b/src/main/java/Referee.java @@ -0,0 +1,28 @@ +import java.util.Arrays; +import java.util.stream.IntStream; + +public class Referee { + + public int[] judge(int[] ansBallCombi, int[] inpBallCombi) { + int[] cnt = new int[10]; + + for (int ansPnt : ansBallCombi) { + cnt[ansPnt]++; + } + + int strikeCnt = IntStream.range(0, inpBallCombi.length) + .map(i -> (ansBallCombi[i] == inpBallCombi[i]) ? 1 : 0) + .reduce((a, b) -> a + b) + .getAsInt(); + + int ballCnt = Arrays.stream(inpBallCombi) + .map(pnt -> cnt[pnt]) + .reduce((a, b) -> a + b) + .getAsInt() + - strikeCnt; + + int[] judgement = {strikeCnt, ballCnt}; + + return judgement; + } +} diff --git a/src/test/java/BallCombiGeneratorTest.java b/src/test/java/BallCombiGeneratorTest.java new file mode 100644 index 00000000..600340d4 --- /dev/null +++ b/src/test/java/BallCombiGeneratorTest.java @@ -0,0 +1,124 @@ +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +public class BallCombiGeneratorTest { + + private BallCombiGenerator generator; + + @Before + public void setUp() throws Exception { + generator = new BallCombiGenerator(); + } + + @Test + public void genBallCombi_generatedBallCombiAllValid() { + int n = 100; + + for (int i = 0; i < n; i++) { + int [] ballCombi = generator.genBallCombi(); +// System.out.println(Arrays.toString(ballCombi)); +// System.out.flush(); + + boolean got = generator.isValid(ballCombi); + + Assert.assertTrue(String.format("[%d] got: %b\n", i, got), got); + } + } + + @Test + public void isValid_possibleValidBallCombis() { + // 입력 + int [][] possibleBallCombis = genPossibleBallCombis(); + + for (int [] ballCombi: possibleBallCombis) { +// System.out.println(Arrays.toString(ballCombi)); +// System.out.flush(); + boolean got = generator.isValid(ballCombi); + Assert.assertTrue(String.format("ballCombi: %s", Arrays.toString(ballCombi)), got); + } + } + + + @Test + public void isValid_invalidBallCombis() { + // 입력 + int [][] ballCombis = { + {1, 1, 1, 1}, + {0, 1, 2}, + {1, 2, 2}, + {9, 9, 9}, + }; + + for(int i = 0; i < ballCombis.length; i++) { + int [] ballCombi = ballCombis[i]; + + boolean got = generator.isValid(ballCombi); + + Assert.assertFalse(String.format("[%d] ", i), got); + } + } + + @Test + public void toBallCombi_usualInputStr() { + // + String [] strs = { + "hello", + "012344", + "adkfj", + "023", + "987", + "345", + }; + + int [][] wants = { + {}, + {}, + {}, + {}, + {9, 8, 7}, + {3, 4, 5}, + }; + + for (int i = 0; i < strs.length; i++) { + String str = strs[i]; + int [] want = wants[i]; + + int [] got = generator.toBallCombi(str); + + Assert.assertArrayEquals( + String.format("[%d] want: %s, got: %s", i, Arrays.toString(want), Arrays.toString(got)), + want, + got + ); + } + } + + private int[][] genPossibleBallCombis() { + int used[] = new int [10]; + + ArrayList combis = new ArrayList<>(); + + for (int p1 = 1; p1 <= 9; p1++) { + used[p1]++; + for (int p2 = 1; p2 <= 9; p2++) { + if (used[p2] != 0) continue; + used[p2]++; + for(int p3 = 1; p3 <= 9; p3++) { + if (used[p3] != 0) continue; + + // 생성해서 바로 넣는 방법이 없으려나??.. + int [] ballCombi = {p1, p2, p3}; + combis.add(ballCombi); + } + used[p2]--; + } + used[p1]--; + } + + return combis.toArray(new int[combis.size()][]); + } +} diff --git a/src/test/java/RefereeTest.java b/src/test/java/RefereeTest.java new file mode 100644 index 00000000..d78c6813 --- /dev/null +++ b/src/test/java/RefereeTest.java @@ -0,0 +1,53 @@ +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +public class RefereeTest { + + private Referee referee; + + @Before + public void setUp() throws Exception { + referee = new Referee(); + } + + @Test + public void judge_usualCases() { + int [] ansBallCombi = {1, 2, 3}; + int [][] inpBallCombis = { + {1, 2, 3}, // 3s, 0b + {1, 3, 2}, // 1s, 2b + {2, 1, 3}, // 1s, 2b + {2, 3, 1}, // 0s, 3b + {9, 2, 5}, // 1s, 0b + {3, 4, 5}, // 0s, 1b + {4, 5, 6}, // 0s, 0b + {6, 2, 5}, // 1s, 0b + }; + int [][] wants = { + {3, 0}, + {1, 2}, + {1, 2}, + {0, 3}, + {1, 0}, + {0, 1}, + {0, 0}, + {1, 0}, + }; + + for (int i = 0; i < wants.length; i++) { + int [] inpBallCombi = inpBallCombis[i]; + int [] want = wants[i]; + + int [] got = referee.judge(ansBallCombi, inpBallCombi); + + Assert.assertArrayEquals(String.format("[%d] want: %s, got: %s", i, Arrays.toString(want), Arrays.toString(got)), + want, + got + ); + } + } +} +