Skip to content
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

[숫자 야구 게임] 윤영로 미션 제출합니다. #6

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
122 changes: 105 additions & 17 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,21 +1,109 @@
# Created by https://www.toptal.com/developers/gitignore/api/macos,visualstudiocode,java,gradle
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,visualstudiocode,java,gradle

### Java ###
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon


# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### macOS Patch ###
# iCloud generated files
*.icloud

### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets

# Local History for Visual Studio Code
.history/

# Built Visual Studio Code Extensions
*.vsix

### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide

### Gradle ###
.gradle
/build/
!gradle/wrapper/gradle-wrapper.jar
/out/
/target/
**/build/
!src/**/build/

### STS ###
.apt_generated
.classpath
.factorypath
# Ignore Gradle GUI config
gradle-app.setting

# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar

# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties

# Cache of project
.gradletasknamecache

# Eclipse Gradle plugin generated files
# Eclipse Core
.project
.settings
.springBeans
bin/

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
# JDT-specific (Eclipse Java Development Tools)
.classpath

### Gradle Patch ###
# Java heap dump
*.hprof

# End of https://www.toptal.com/developers/gitignore/api/macos,visualstudiocode,java,gradle
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@

<br>

### 구현 기능
1. 1-9 범위의 랜덤한 N자리 숫자 생성
2. IO 및 종료조건(성공/재시작/종료)
3. 스트라이크, 볼, 낫싱 판단
4. main 조합

## ✍🏻 입출력 요구사항

### ⌨️ 입력
Expand Down
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ repositories {
}

dependencies {
implementation('com.github.woowacourse-projects:mission-utils:1.0.0')
implementation 'com.github.woowacourse-projects:mission-utils:1.0.0'
testImplementation 'com.tngtech.archunit:archunit-junit5:1.2.1'
Copy link
Owner

Choose a reason for hiding this comment

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

엥 JUnit 의존성이 추가 안 되어있었나요?

Copy link
Author

Choose a reason for hiding this comment

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

@Jaeyoung22 앗.. 중복으로 추가한 것 같습니다. 감사합니다!!

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.1'
}

test {
Expand Down
28 changes: 27 additions & 1 deletion src/main/java/baseball/Application.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
package baseball;

import baseball.io.SystemOutput;
import baseball.io.UserInput;
import baseball.rule.BaseballResult;
import baseball.rule.BaseballRule;

public class Application {
public static void main(String[] args) {
//TODO: 숫자 야구 게임 구현
RandomDigit random = new RandomDigit();
Copy link
Owner

Choose a reason for hiding this comment

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

접근제한자가 따로 없고 default로 선언하신 이유가 있을까요?
더해서, 로컬 변수로 두지 않고 필드에 선언하신 이유가 있을까요?

SystemOutput systemOutput = new SystemOutput();
UserInput userInput = new UserInput();
BaseballRule rule = new BaseballRule();
boolean isContinue = true;

while (isContinue) {
String goal = random.generate(3);
// System.out.println(goal);
Copy link
Owner

Choose a reason for hiding this comment

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

사용하지 않는 코드는 지워주세용 ㅎㅎ

while (true) {
systemOutput.begin();
Copy link
Owner

Choose a reason for hiding this comment

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

개인적으로 밑에 end()와 더불어서 begin이나 end가 약간 SystemOutput 이라는 객체가 시작되고 끝나는 것 같은 네이밍이라고 느껴지네요... 영로님 생각은 어떠실까요?

String input = userInput.predict();
BaseballResult result = rule.check(input, goal);
systemOutput.miss(result.getBall(), result.getStrike());
Copy link
Owner

Choose a reason for hiding this comment

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

miss가 어떤 의미인지 이 코드만 봐서는 잘 모르겠어요. 바로 위의 커멘트와 비슷한 맥락으로 생각해주시면 감사하겠습니다!

if (result.getStrike() == 3) {
Copy link
Owner

Choose a reason for hiding this comment

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

매직넘버를 상수화하라 키워드로 검색해보는 걸 추천드려요!

systemOutput.end();
String restartCheck = userInput.end();
isContinue = restartCheck.equals("1");
break;
}
}
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/baseball/RandomDigit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package baseball;

import java.util.*;
import camp.nextstep.edu.missionutils.Randoms;

public class RandomDigit {

public String generate(int count) {
// List<Integer> numbers = Randoms.pickUniqueNumbersInRange(1, 9, count);
Set<Integer> numbers = new HashSet<>();
while (numbers.size() < 3) {
numbers.add(Randoms.pickNumberInRange(1, 9));
}
return numbers.stream().map(x -> String.valueOf(x)).reduce("", (acc, cur) -> acc + cur);
Copy link
Owner

Choose a reason for hiding this comment

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

객체지향 생활체조 키워드를 검색해보는 걸 추천 드립니다!

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

import camp.nextstep.edu.missionutils.Console;

public class SystemOutput {

public void begin() {
System.out.print("숫자를 입력해주세요 : ");
}

public void miss(int ball, int strike) {
Copy link
Owner

Choose a reason for hiding this comment

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

메서드 이름이 miss인데 전부 맞힌 경우도 출력하고 있네요. 다른 이름으로 바꿔보는 건 어떨까요?

StringBuilder builder = new StringBuilder();

if (ball == 0 && strike == 0) {
System.out.println("낫싱");
} else {
if (ball > 0) {
builder.append(ball + "볼");
}
if (strike > 0) {
builder.append(" " + strike + "스트라이크");
}
System.out.println(builder.toString().trim());
}
}

public void end() {
System.out.println("3개의 숫자를 모두 맞히셨습니다! 게임 종료\n게임을 새로 시작하려면 1, 종료하려면 2를 입력하세요.");
}

}
28 changes: 28 additions & 0 deletions src/main/java/baseball/io/UserInput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package baseball.io;
import java.util.*;
import camp.nextstep.edu.missionutils.Console;

public class UserInput {
public String predict() throws IllegalArgumentException {
String rawInput = Console.readLine().trim();
if (rawInput.length() != 3) {
throw new IllegalArgumentException("3자리 숫자를 입력해야 합니다.");
}
try {
Integer.parseInt(rawInput);
} catch (Exception e) {
Copy link
Owner

Choose a reason for hiding this comment

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

왜 NumberFormatException이 아닌 Exception을 받으셨나요?

throw new IllegalArgumentException("3자리 숫자를 입력해야 합니다.");
}

return rawInput;
}

public String end() throws IllegalArgumentException {
String rawInput = Console.readLine().trim();
if (rawInput.equals("1") || rawInput.equals("2")) {
return rawInput;
}
throw new IllegalArgumentException("1 혹은 2를 입력해야 합니다: " + rawInput);
}

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

public class BaseballResult {
private final int strike;
private final int ball;

public BaseballResult(int strike, int ball) {
this.strike = strike;
this.ball = ball;
}

public int getStrike() {
return strike;
}
public int getBall() {
return ball;
}

@Override
public boolean equals(Object obj) {
Copy link
Owner

Choose a reason for hiding this comment

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

equls()를 오버라이딩 하신 이유가 있으실까요? BaseballResult를 VO라고 보신걸까요?! 저도 매우 동의합니다.
equals()와 hashcode()를 동시에 오버라이딩하라 라는 키워드를 검색해보시는 걸 추천드려요!

BaseballResult target = (BaseballResult) obj;
return (strike == target.strike && ball == target.ball);
}
}
30 changes: 30 additions & 0 deletions src/main/java/baseball/rule/BaseballRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package baseball.rule;

import java.util.*;

public class BaseballRule {

public BaseballResult check(String input, String goal) {
if (Objects.isNull(input) || Objects.isNull(goal) || input.length() != 3 || goal.length() != 3) {
throw new IllegalArgumentException("입력값이 잘못되었습니다. 3자리 숫자를 입력해주세요: goal: " + goal + "/input: " + input);
}
// input, goal 모두 3자리 숫자
Copy link
Owner

Choose a reason for hiding this comment

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

주석보다, 위에 있는 input.length() != 3에서 3을 DIGIT_NUMBER 같은 상수로 두면 더 이해하기 쉬울 것 같아요!

Set<Character> goalSet = new HashSet<>();
for (char c : goal.toCharArray()) {
goalSet.add(c);
}

int strike = 0;
int ball = 0;
for (int i = 0; i < 3; ++i) {

Copy link
Owner

Choose a reason for hiding this comment

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

여기에 개행을 하신 이유가 있을까요?

if (input.charAt(i) == goal.charAt(i)) {
strike += 1;
} else if (goalSet.contains(input.charAt(i))) {
ball += 1;
}
}
return new BaseballResult(strike, ball);
}

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

import java.util.*;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

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

public class RandomDigitTest {
Copy link
Owner

Choose a reason for hiding this comment

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

테스트코드 아주 바람직하고 멋집니다

@DisplayName("Test Random n-digit")
@Test
public void testGenerateRandomDigits() {
// given
RandomDigit digit = new RandomDigit();

// when
String n1 = digit.generate(3);
String n2 = digit.generate(3);

// then
assertTrue(n1.length() == 3 && n2.length() == 3);
Copy link
Owner

Choose a reason for hiding this comment

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

assertAll이나 SoftAssertions의 assertSoftly에 대해서 검색해보시는 걸 추천드려요.

지금 같은 상황에서는 아래 반복문 안에 있는 assertFalse() 중에 하나라도 실패하면 아예 이 테스트 자체가 실패했다고 나옵니다.

assertNotEquals(n1, n2);

Set<Character> check = new HashSet<>();
for (Character c: n1.toCharArray()) {
assertFalse(check.contains(c));
check.add(c);
}
check.clear();
for (Character c: n2.toCharArray()) {
assertFalse(check.contains(c));
check.add(c);
}
}
}
Loading