Skip to content
This repository was archived by the owner on Feb 9, 2026. It is now read-only.
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
29 changes: 3 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -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. 입력과 출력을 처리
49 changes: 49 additions & 0 deletions src/main/java/baseball/BaseballGame.java
Original file line number Diff line number Diff line change
@@ -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<Discrimination> 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중에서 입력해주세요");
}
}
}
38 changes: 38 additions & 0 deletions src/main/java/baseball/BaseballStage.java
Original file line number Diff line number Diff line change
@@ -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<Discrimination> 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<Discrimination> getHistory() {
return new ArrayList<>(this.history);
}
}
92 changes: 92 additions & 0 deletions src/main/java/baseball/Discrimination.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package baseball;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

public class Discrimination {

Choose a reason for hiding this comment

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

class 이름을 discrimination으로 설정하신 이유가 궁금합니다!

Copy link
Author

Choose a reason for hiding this comment

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

두 숫자를 비교하는 행위를 '판별한다(discriminate)'고 표현하고 싶었습니다.
검증하다(Verify)나 판단하다(Judge)로 표현하는 게 더 자연스러웠을지 모르겠네요..

Discrimianation은 생성되는 순간 두 숫자(Number)를 판별하고 그 정보를 저장해놓았다가 표시하는 역할을 하는 클래스입니다.

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<Integer, Integer> 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;
}
}
49 changes: 49 additions & 0 deletions src/main/java/baseball/Number.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Comment on lines +8 to +13
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 매서드는 사용하는 측에서의 활용을 모른다면(사용하는 측의 로직을 모른다면) 이해하기 힘든 로직인 것 같아요!

  1. 해당 로직의 책임을 다른 곳으로 위임하거나
  2. 해당 생성자 매서드 안에 있는 로직에 "이름을 부여" 해서 의도를 밝혀보는

것은 어떨까요?


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

Choose a reason for hiding this comment

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

hashCode() 와 equals(Object obj) 를 오버라이드한 이유가 궁금합니다...!
Number클래스는 뭔갈 상속받고있는 클래스도 아닌것 같은데.. 왜 사용하신건가요..?

Copy link
Author

@deok-beom deok-beom Nov 14, 2023

Choose a reason for hiding this comment

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

Object는 Java의 모든 클래스의 최고 조상 클래스입니다.
equals()hashCode()는 모두 이 Object가 가지고 있는 메소드입니다.

equals() 메소드는 두 인스턴스가 같은지를 비교하는 메소드로 재정의 하지 않는다면 두 인스턴스가 저장된 메모리 주소를 비교하게 됩니다. 이를 재정의 하고 있는 이유는 두 Number 인스턴스가 같은지 비교할 때 멤버 변수로 저장하고 있는 정수 배열(int[] nums) 안의 정수 값들과 그 순서로 비교하기 위해서 입니다. 이로써 실제로 같은 숫자를 저장하고 있는 Number의 인스턴스를 여러개 만들어도 메모리에 저장된 위치만 다를 뿐 같은 데이터라고 인식할 수 있습니다.

hashCode()는 보통 equals()를 재정의 할 때 함께 재정의 하는 것이 권장되고 있습니다. 이 메소드는 인스턴스의 해시코드를 구해서 반환하는 메소드로 재정의 하지 않는다면 인스턴스가 저장된 메모리 주소로 해시코드를 만들어 반환합니다. 위의 equals() 메소드에서처럼 이 메소드의 실질적인 데이터의 본질을 말하고 있는 건 int[] nums안의 정수 값들입니다. 따라서 hashCode()도 재정의하고 있습니다. (이 함수는 HashMap이나 HashSet과 같은 자료형에 저장될 때 사용됩니다.)

Copy link
Author

Choose a reason for hiding this comment

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

equals(), hashCode() 두 메소드는 해시 코드를 이용하는 컬렉션에서 주로 활용됩니다.

해시 알고리즘은 모든 인스턴스에 대해서 완전히 중복되지 않는 고유한 값을 만들어주지는 않습니다. 알고리즘에 따라서 그 확률은 다르겠지만 해시 코드값이 중복되는 경우도 있습니다.

해시 코드를 이용하는 컬렉션들은 값을 저장, 조회할 때 일단 해시코드를 이용해서 저장하고, 만약 중복되는 해시코드 값이 이미 있다면 그 이후에는 equals()를 이용해서 값이 같은지 비교하여 처리하는 방식입니다.

public int hashCode() {
int hashCode = 1;
for (int num : nums) {
hashCode = 31 * hashCode + num;
}

return hashCode;
}
}
20 changes: 20 additions & 0 deletions src/main/java/baseball/RandomNumberGenerator.java
Original file line number Diff line number Diff line change
@@ -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<Integer> 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);
}
}
18 changes: 18 additions & 0 deletions src/main/java/util/Terminal.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading