Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,43 @@ git checkout main // 기본 브랜치가 main인 경우
git checkout -b 브랜치이름
ex) git checkout -b apply-feedback
```

기본적으로 1부터 9까지 서로 다른 수로 이루어진 3자리의 수를 맞추는 게임이다.

같은 수가 같은 자리에 있으면 스트라이크,
다른 자리에 있으면 볼,
같은 수가 전혀 없으면 포볼 또는 낫싱이란 힌트를 얻고,
그 힌트를 이용해서 먼저 상대방(컴퓨터)의 수를 맞추면 승리한다.
위 숫자 야구 게임에서 상대방의 역할을 컴퓨터가 한다.
컴퓨터는 1에서 9까지 서로 다른 임의의 수 3개를 선택한다.
게임 플레이어는 컴퓨터가 생각하고 있는 3개의 숫자를 입력하고, 컴퓨터는 입력한 숫자에 대한 결과를 출력한다.
이 같은 과정을 반복해 컴퓨터가 선택한 3개의 숫자를 모두 맞히면 게임이 종료된다.
게임을 종료한 후 게임을 다시 시작하거나 완전히 종료할 수 있다.

- [x] 숫자
- [x] randomNumberMaker

- [x] ListUtil
- [x] List에 같은 숫자 있는지 중복 확인
- [x] List의 사이즈 3인지 확인

- [x] 게임결과 판별기 (Referee)
- [x] 같은 숫자가 몇 개 있는지 확인
- [x] 같은 자리, 같은 숫자 몇 개 있는지 확인
- [x] 스트라이크, 볼, 낫싱 결과 도출

- [x] Computer
- [x] randomNumberMaker와 ListUtil을 통해 숫자 배열 반환

- [x] ScannerUtil
- [x] 숫자(String) 입력
- [x] split 을 사용해 연속되어 들어오는 숫자 나누기
- [x] split 한 String 배열을 List<Integer>로 변환

- [x] Player
- [x] ScannerUtil 을 사용해서 숫자배열 반환

- [x] GameUtil
- [x] 1번을 누르면 재시작, 2번을 누르면 종료
- [x] 1번 실행되는 게임
- [x] 3스트라이크가 나올때까지 실행되는 게임
23 changes: 23 additions & 0 deletions src/main/java/baseball/Computer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package baseball;

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

public class Computer {

public List<Integer> makeNumbers() {
RandomNumber randomNumber = new RandomNumber();

ListUtil listUtil = new ListUtil();

List<Integer> computerNumbers = new ArrayList<>();

while (!listUtil.checkListSize(computerNumbers)) {
int number = randomNumber.make();
listUtil.distinctNumberAdd(computerNumbers, number);
}

System.out.println("computerNumbers = " + computerNumbers);
return computerNumbers;
}
}
8 changes: 8 additions & 0 deletions src/main/java/baseball/Game.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package baseball;

public class Game {
public static void main(String[] args) {
GameUtil gameUtil = new GameUtil();
gameUtil.runGame();
}
}
62 changes: 62 additions & 0 deletions src/main/java/baseball/GameUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package baseball;


import java.util.List;

public class GameUtil {

Choose a reason for hiding this comment

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

Util 이라는 이름의 클래스는 적합하지 않은 것 같아요 :)

유틸 클래스는 보통 실용성이나 유용성에 중점을 둔 정적 메서드들을 모아두고 여러 곳에서 호출하는 형식으로 사용하며 여러 곳에서 호출하기 때문에 유틸 클래스는 공통적인 로직을 다루도록 만들어야하며 합니다.

개인적으로는 실제로는 이러한 유틸 클래스의 메서드를 변경했을 때 영향이 너무 크기 때문에 최대한 사용을 지양하는 것을 선호합니다 :)


public void runGame() {

if (runOnlyOnceGame()) {
showMenu();
}
}

public boolean runOnlyOnceGame() {

Computer computer = new Computer();
List<Integer> computers = computer.makeNumbers();

return gameResult(computers);
}

private boolean gameResult(List<Integer> computers) {
boolean threeStrike = true;
while (threeStrike) {

Player player = new Player();
List<Integer> playerNumbers = player.makeNumbers();
Referee referee = new Referee();

String result = referee.informStrikeBall(computers, playerNumbers);
System.out.println(result);
threeStrike = isGame(threeStrike, result);
}

return true;
}

private boolean isGame(boolean game, String result) {
if (result.equals("3스트라이크")) {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료");
game = false;
}
return game;
}

private void showMenu() {
ScannerUtil scannerUtil = new ScannerUtil();
System.out.println("게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");

Choose a reason for hiding this comment

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

  • 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
  • UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다.

프로그래밍 요구사항 중에 위와 같은 요구사항이 있었는데요. 이 부분을 어떻게 구현할지 생각해보시면 좋을 것 같습니다.


int choice = scannerUtil.insertInt();
if (choice == 1) {
runGame();
}

while (choice != 1 && choice != 2) {
System.out.println("잘못 입력하셨습니다. 다시입력해주세요.");
choice = scannerUtil.insertInt();
}
System.out.println("수고하셨습니다.");
}
}

Choose a reason for hiding this comment

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

파일 마지막에 엔터(개행문자)를 넣어주세요 :)

이유는 리뷰를 진행할 때 깃허브에서 경고메시지를 지우고 혹시 모르는 파일 읽기 오류에 대비하기 위함입니다.

좀 더 알고싶으시면 참고 링크를 보셔도 재밌을 것 같네요 :)

Intellij 를 사용하실 경우엔Preferences -> Editor -> General -> Ensure line feed at file end on save 를 체크해주시면파일 저장 시 마지막에 개행문자를 자동으로 넣어줍니다!

https://minz.dev/19https://stackoverflow.com/questions/729692/why-should-text-files-end-with-a-newline

16 changes: 16 additions & 0 deletions src/main/java/baseball/ListUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package baseball;

import java.util.List;

public class ListUtil {

public boolean checkListSize(List<Integer> list) {
return list.size() == 3;
}

public void distinctNumberAdd(List<Integer> numberList, int randomNumber) {
if (!numberList.contains(randomNumber)) {
numberList.add(randomNumber);
}
}
}
15 changes: 15 additions & 0 deletions src/main/java/baseball/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package baseball;

import java.util.List;

public class Player {

public List<Integer> makeNumbers() {

ScannerUtil scannerUtil = new ScannerUtil();

List<Integer> integers = scannerUtil.makeScannerNumbers();

return integers;
}
}
11 changes: 11 additions & 0 deletions src/main/java/baseball/RandomNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package baseball;

import java.util.Random;

public class RandomNumber {

public int make() {
Random random = new Random();
return random.nextInt(9) + 1;
}
}
61 changes: 61 additions & 0 deletions src/main/java/baseball/Referee.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package baseball;

import java.util.List;

public class Referee {

Choose a reason for hiding this comment

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

Referee 클래스의 인스턴스는 어떤 상태(내부 필드)도 가지지 않기 때문에 이 클래스의 모든 객체들은 동일한 객체이겠네요 !

너무 많은 상태를 가지는 것은 좋은 설계가 아니지만, 아무것도 가지지 않는 방식 또한 바람직한 설계는 아닙니다.

적절한 상태를 가진 객체를 설계해보면 좋을 것 같아요.

다른 클래스들에도 함께 적용되는 피드백일 것 같습니다 :)


public int countBall(List<Integer> list1, List<Integer> list2) {

int count = 0;
int strike = countStrike(list1, list2);

for (Integer number : list1) {
count = getCount(list2, count, number);
}
return count - strike;
}

public int countStrike(List<Integer> list1, List<Integer> list2) {

int count = 0;
for (int index = 0; index < 3; index++) {

Choose a reason for hiding this comment

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

임의의 숫자를 사용하는 매직넘버는소스 코드를 읽기 어렵게 만드는데요 !

이 부분을 어떻게 개선할 수 있을까요? 관련 링크 남겨놓겠습니다 :)

https://www.slipp.net/questions/356

count = getCountStrike(list1, list2, count, index);
}
return count;
}

public String informStrikeBall(List<Integer> list1, List<Integer> list2) {

int ball = countBall(list1, list2);
int strike = countStrike(list1, list2);

if (strike == 3) {
return strike + "스트라이크";
}
Comment on lines +32 to +34

Choose a reason for hiding this comment

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

핵심 로직에 화면(콘솔 출력)에 대한 요구사항이 섞여있네요!
만약 화면 요구사항이 변하게 된다면 어떻게 될까요?
화면의 요구사항이 바뀌었지만 개발자가 수정해야하는 부분은 도메인의 핵심 로직입니다.
아래 요구사항을 반영해야하는 이유중 하나가 될 수 있겠네요 :)

핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.


if (strike == 0 && ball != 0) {
return ball + "볼";
}

if (strike != 0 && ball != 0) {
return ball + "볼 " + strike + "스트라이크";
}

return "낫싱";
}

private int getCountStrike(List<Integer> list1, List<Integer> list2, int count, int index) {
if (list1.get(index) == list2.get(index)) {
count++;
}
return count;
}

private int getCount(List<Integer> list2, int count, Integer number) {
if (list2.contains(number)) {
count++;
}
return count;
}

}
56 changes: 56 additions & 0 deletions src/main/java/baseball/ScannerUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package baseball;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class ScannerUtil {

public List<Integer> makeScannerNumbers() {
System.out.print("숫자를 입력하세요: ");

ListUtil listUtil = new ListUtil();

List<Integer> integers = stringListToIntegerList();

while (!listUtil.checkListSize(integers)) {
System.out.println("잘못된 숫자입니다.");
System.out.print("숫자를 입력하세요: ");

integers = stringListToIntegerList();
}
return integers;
}

public String insertString() {

Scanner scanner = new Scanner(System.in);

Choose a reason for hiding this comment

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

Scanner는 매우 비싼 자원입니다. 미리 생성해두고 재활용하도록 해보면 어떨까요 ?

static 메서드를 활용해보면 좋을 것 같아요.

return scanner.next();
}

public int insertInt() {

Scanner scanner = new Scanner(System.in);
return scanner.nextInt();
}

private String[] splitStringList() {
String string = insertString();

return string.split("");
}

private List<Integer> stringListToIntegerList() {
String[] strings = splitStringList();

List<Integer> temp = new ArrayList<>();
ListUtil listUtil = new ListUtil();

for (String string : strings) {
int number = Integer.parseInt(string);
listUtil.distinctNumberAdd(temp, number);
}

return temp;
}
}
47 changes: 47 additions & 0 deletions src/test/java/baseball/ListUtilTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package baseball;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

import static org.assertj.core.api.Assertions.assertThat;

public class ListUtilTest {

@Test
@DisplayName("리스트의 사이즈가 3이면 true 반환")
void checkListSize() throws Exception {
//given
ListUtil listUtil = new ListUtil();

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);

//when
boolean checkListSize = listUtil.checkListSize(list);

//then
assertThat(checkListSize).isTrue();
}

@Test
@DisplayName("리스트에 중복 숫자가 들어갈 경우 리스트에 add 안함")
void checkDuplicate() throws Exception {
//given
ListUtil listUtil = new ListUtil();

int number = 1;
List<Integer> list = new ArrayList<>();

//when
for (int i = 0; i < 2; i++) {
listUtil.distinctNumberAdd(list, number);
}
//then
assertThat(list.size()).isEqualTo(1);
}
}
22 changes: 22 additions & 0 deletions src/test/java/baseball/RandomNumberTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package baseball;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

public class RandomNumberTest {

@Test
@DisplayName("랜덤 넘버 만들기 테스트 -> 숫자 범위가 1~9 사이")
void randomNumberMakeTest() throws Exception {
//given
RandomNumber number = new RandomNumber();

//when
int randomNUmber = number.make();

//then
assertThat(randomNUmber).isBetween(1, 9);
}
}
Loading