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

[이영진] 2주차 미션 #12

Open
wants to merge 2 commits into
base: youngreal
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
20 changes: 20 additions & 0 deletions src/main/java/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import util.GameSetting;
import view.View;

public class Main {
public static void main(String[] args) {
GameSetting gameSetting = new GameSetting();
do {
gameSetting.startGame();
gameSetting.correctAnswer();
if (isNotContinueGame()) {
break;
}
gameSetting.reGame();
} while(true);
}

private static boolean isNotContinueGame() {
return !View.isContinue();
}
}
7 changes: 7 additions & 0 deletions src/main/java/exception/DuplicateNumberException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package exception;

public class DuplicateNumberException extends RuntimeException {
public DuplicateNumberException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/exception/NotOnlyNumberException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package exception;

public class NotOnlyNumberException extends RuntimeException{
public NotOnlyNumberException(String message) {
super(message);
}
}
27 changes: 27 additions & 0 deletions src/main/java/util/Answer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package util;

import java.util.ArrayList;

import static util.Constant.ANSWER_MAX_SIZE;
import static util.Constant.ANSWER_NUMBER_RANGE;

/**
* 정답 넘버 중복없는 3자리 생성하는 클래스
*/
public class Answer{
private final ArrayList<Integer> answerNum= new ArrayList<>();

public ArrayList<Integer> generateNumber() {
while (answerNum.size() < ANSWER_MAX_SIZE) {
int element = (int) (Math.random() * ANSWER_NUMBER_RANGE);
if(isNotContainsNumber(element)){
answerNum.add(element);

Choose a reason for hiding this comment

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

answerNum을 불변 컬렉션으로 만드는 방법은 좋았지만 해당 리스트 안에 인자를 추가하는 건 불변이라고 부르기 어려울 것 같아요..!!

불변 컬렉션과 관련된 링크 첨부하겠습니다. ☺️
https://www.daleseo.com/java9-immutable-collections/

그리고 추가적으로 불변 객체를 생성하는 이유도 링크 첨부하겠습니다!
https://mangkyu.tistory.com/131

}
}
return this.answerNum;
}

private boolean isNotContainsNumber(int element) {
return !answerNum.contains(element);
}
}
57 changes: 57 additions & 0 deletions src/main/java/util/CompareAnswer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package util;

import java.util.ArrayList;

/**
* 정답숫자와 인풋숫자를 비교하여 점수를 카운팅하는 클래스
*/
public class CompareAnswer {

Choose a reason for hiding this comment

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

정답 숫자와 입력하는 숫자를 비교하기 위해 새로운 구현체를 만들지 않고, Answer 클래스에서 비교할 수 있도록 구현하는건 어떨까요? ☺️ 이 부분은 응집도를 저해하는 방법이라 생각이 듭니다. ☺️

private final ArrayList<Integer> inputNum;
private final ArrayList<Integer> answerNum;
private int strikeCount=0;
private int ballCount=0;
private int nothing=0;

public CompareAnswer(ArrayList<Integer> inputNum, ArrayList<Integer> answerNum) {
this.inputNum = inputNum;
this.answerNum = answerNum;
}

public void ballScoreCount() {

Choose a reason for hiding this comment

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

메서드 명은 항상 동사로 시작해야 합니다!

Choose a reason for hiding this comment

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

예를 들면 이 방식이 있겠군요!

Suggested change
public void ballScoreCount() {
public void countBall() {

for (int i = 0; i < 3; i++) {
ballCounting(i);
}
}

public void ballCounting(int position) {
if (isStrike(position)) {
this.strikeCount++;
return;
}
if (isBall(position)) {
this.ballCount++;
return;
}
this.nothing++;
}

private boolean isStrike(int position) {
return this.inputNum.get(position).equals(this.answerNum.get(position));
}

private boolean isBall(int position) {
return this.answerNum.contains(this.inputNum.get(position));
}

public int getStrikeCount() {
return strikeCount;
}

public int getBallCount() {
return ballCount;
}

public int getNothing() {
return nothing;
}
}
18 changes: 18 additions & 0 deletions src/main/java/util/Constant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package util;

/**
* 상수값들을 보관한 클래스
*/
public class Constant {

Choose a reason for hiding this comment

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

상수 값들을 보관하는 클래스를 구현하셨군요! 이 방법 말고 상수가 필요한 구현체에서 선언하는건 어떨까요? 해당 방식은 결합도를 높이면서 응집도를 저해하는 방식이라 생각이 듭니다! ☺️

public static final int ANSWER_MAX_SIZE = 3;
public static final int ANSWER_NUMBER_RANGE = 10;
public static final int CHAR_TO_INT = 48;
public static final int INPUT_NUMBER_LENGTH = 3;
public static final int INPUT_NUMBER_MAXVALUE = 9;
public static final int INPUT_NUMBER_MINVALUE = 0;
public static final int STRIKE_BALL_MIN = 0;
public static final int NOTHING = 3;
public static final String GAME_START_MESSAGE = "숫자를 입력해주세요";
public static final String ALL_NUMBER_CORRECT_MESSAGE = "3개의 숫자를 모두 맞히셨습니다! 게임종료";
public static final String CONTINUE_GAME_QUESTION = "게임을 새로시작하려면 1, 종료하려면 2를 입력하세요";
}
66 changes: 66 additions & 0 deletions src/main/java/util/GameSetting.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package util;

import exception.DuplicateNumberException;
import exception.NotOnlyNumberException;
import view.View;

import java.util.ArrayList;

/**
* 정답을 맞출때까지 게임을 진행하는 클래스
*/
public class GameSetting {
public void startGame() {
ArrayList<Integer> answerNumber = getAnswerNumber();
View view = new View();
int strikeCount=0;

do {
View.printStart();
// 인풋숫자 받고,검증
InputNumber inputNumber = new InputNumber();
if (inputNumberScanAndValidation(inputNumber)) continue;
ArrayList<Integer> inputNumberArray = getInputNumber(inputNumber);

// 인풋숫자와 정답을 비교하고, 스코어매기기
CompareAnswer compareAnswer = new CompareAnswer(inputNumberArray,answerNumber);
compareAnswer.ballScoreCount();

// 정답확인하기
strikeCount = compareAnswer.getStrikeCount();
view.printResult(compareAnswer);

}while (strikeCount<3);
}

private ArrayList<Integer> getInputNumber(InputNumber inputNumber) {
return inputNumber.getInputNumArray();
}

private boolean inputNumberScanAndValidation(InputNumber inputNumber) {
try {
inputNumber.inputNumberValidation(inputNumber.inputNumberScanner());
} catch (ArrayIndexOutOfBoundsException | NotOnlyNumberException | DuplicateNumberException e) {
System.out.println(e.getMessage());
return true;
}
return false;
}

private ArrayList<Integer> getAnswerNumber() {
Answer answer = new Answer();

Choose a reason for hiding this comment

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

새로운 객체를 생성해서 구현하는 방식보다 generateAnswerNumber 메서드에서 Answer를 구현하는 방식이이 낫지 않을까 생각이 듭니다. 그리고 너무 많은 메서드가 만들어져서 오히려 가독성을 해치는 것 같습니다! 딱 필요한 메서드만을 의미있는 이름으로 짓는건 어떨까요? ☺️

return generateAnswerNumber(answer);
}

public void correctAnswer() {
View.printEnding();
}

private ArrayList<Integer> generateAnswerNumber(Answer answer) {
return answer.generateNumber();
}

public void reGame() {
getAnswerNumber();
}
}
58 changes: 58 additions & 0 deletions src/main/java/util/InputNumber.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package util;

import exception.DuplicateNumberException;
import exception.NotOnlyNumberException;

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

import static util.Constant.*;

/**
* 사용자가 입력한 숫자에대해 다루는 클래스
*/
public class InputNumber {
private final Scanner sc= new Scanner(System.in);
private final ArrayList<Integer> inputNumArray= new ArrayList<>();

public ArrayList<Integer> getInputNumArray() {
return inputNumArray;
}

public char[] inputNumberScanner() {
this.inputNumArray.clear();
String scStr = sc.nextLine();
return scStr.toCharArray();
}

public void inputNumberValidation(char[] scChar) {
ArrayIndexExceptionValidation(scChar);
for (char c : scChar) {
notOnlyExceptionValidation(c);
DuplicateNumberExceptionValidation(c);
this.inputNumArray.add(c - CHAR_TO_INT);
}
}

private void DuplicateNumberExceptionValidation(char c) {

Choose a reason for hiding this comment

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

메서드 이름에서 첫글자는 항상 소문자여야 합니다. ☺️

스크린샷 2022-05-29 오후 10 30 02

Suggested change
private void DuplicateNumberExceptionValidation(char c) {
private void duplicateNumberExceptionValidation(char c) {

if (inputNumArray.contains(c - CHAR_TO_INT)) {
throw new DuplicateNumberException("서로다른 숫자만 입력해주세요");
}
}

private void notOnlyExceptionValidation(char c) {

Choose a reason for hiding this comment

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

동사로 시작하는 이름으로 메서드로 짓는건 어떨까요? ☺

스크린샷 2022-05-29 오후 10 29 22

if (OutOfRangeNumber(c)) {
throw new NotOnlyNumberException("0~9사이의 숫자만 입력해주세요");
}
}

private boolean OutOfRangeNumber(char scChar) {

Choose a reason for hiding this comment

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

boolean을 리턴하는 메서드 이름을 isXXX 로 시작하도록 네이밍 하는건 어떨까요? ☺️

Suggested change
private boolean OutOfRangeNumber(char scChar) {
private boolean isRightNumber(char scChar) {

return scChar - CHAR_TO_INT > INPUT_NUMBER_MAXVALUE || scChar - CHAR_TO_INT < INPUT_NUMBER_MINVALUE;
}

private void ArrayIndexExceptionValidation(char[] scChar) {

Choose a reason for hiding this comment

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

이 부분도 동사로 시작할 수 있도록 메서드 명을 수정해주세요!

if (scChar.length != INPUT_NUMBER_LENGTH) {
throw new ArrayIndexOutOfBoundsException("세자리 수를 입력해주세요.");
}
}
}
39 changes: 39 additions & 0 deletions src/main/java/view/View.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package view;

import util.CompareAnswer;

import java.util.Scanner;

import static util.Constant.*;

/**
* 화면출력용 클래스
*/
public class View {
public static void printStart() {
System.out.println(GAME_START_MESSAGE);
}

public void printResult(CompareAnswer answer) {
if (answer.getStrikeCount()>STRIKE_BALL_MIN) {

Choose a reason for hiding this comment

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

인텔리제이에서 자동 줄 정렬 기능을 제공하고 있습니다!

https://penthegom.tistory.com/47

Suggested change
if (answer.getStrikeCount()>STRIKE_BALL_MIN) {
if (answer.getStrikeCount() > STRIKE_BALL_MIN) {

System.out.printf("%d스트라이크 ",answer.getStrikeCount());
}
if (answer.getBallCount()>STRIKE_BALL_MIN) {
System.out.printf("%d볼 ",answer.getBallCount());
}
if (answer.getNothing()== NOTHING) {
System.out.print("낫싱");
}
System.out.println("");
}

public static void printEnding() {
System.out.println(ALL_NUMBER_CORRECT_MESSAGE);

Choose a reason for hiding this comment

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

만약 시간적인 여유가 되신다면 메시지와 같은 상수를 enum으로 관리하시는건 어떨까요? ☺️

https://techblog.woowahan.com/2527/

System.out.println(CONTINUE_GAME_QUESTION);
}

public static boolean isContinue() {
Scanner sc = new Scanner(System.in);
return sc.nextInt() == 1;
}
}
80 changes: 80 additions & 0 deletions src/test/java/util/CompareAnswerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package util;

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

import java.util.ArrayList;

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

class CompareAnswerTest {
ArrayList<Integer> inputNum= new ArrayList<>();
ArrayList<Integer> answerNum= new ArrayList<>();

@BeforeEach
void setup() {
answerNum.add(3);
answerNum.add(4);
answerNum.add(6);
}

@Test
@DisplayName("0스트라이크 1볼")
void ballCountingTest() {
inputNum.add(1);
inputNum.add(2);
inputNum.add(3);
CompareAnswer compareAnswer = new CompareAnswer(inputNum,answerNum);
ballCounting(compareAnswer);
assertThat(compareAnswer.getStrikeCount()).isEqualTo(0);
assertThat(compareAnswer.getBallCount()).isEqualTo(1);
assertThat(compareAnswer.getNothing()).isNotEqualTo(3);
System.out.println(compareAnswer.getNothing());
}

@Test
@DisplayName("2스트라이크")
void ballCountingTest2() {
inputNum.add(3);
inputNum.add(5);
inputNum.add(6);
CompareAnswer compareAnswer = new CompareAnswer(inputNum,answerNum);
ballCounting(compareAnswer);
assertThat(compareAnswer.getStrikeCount()).isEqualTo(2);
assertThat(compareAnswer.getBallCount()).isEqualTo(0);
assertThat(compareAnswer.getNothing()).isNotEqualTo(3);
}

@Test
@DisplayName("낫싱")
void ballCountingTest3() {
inputNum.add(1);
inputNum.add(2);
inputNum.add(5);
CompareAnswer compareAnswer = new CompareAnswer(inputNum,answerNum);
ballCounting(compareAnswer);
assertThat(compareAnswer.getStrikeCount()).isEqualTo(0);
assertThat(compareAnswer.getBallCount()).isEqualTo(0);
assertThat(compareAnswer.getNothing()).isEqualTo(3);
}

@Test
@DisplayName("3볼")
void ballCountingTest4() {
inputNum.add(6);
inputNum.add(3);
inputNum.add(4);
CompareAnswer compareAnswer = new CompareAnswer(inputNum,answerNum);
ballCounting(compareAnswer);
assertThat(compareAnswer.getStrikeCount()).isEqualTo(0);
assertThat(compareAnswer.getBallCount()).isEqualTo(3);
assertThat(compareAnswer.getNothing()).isNotEqualTo(3);
}

private void ballCounting(CompareAnswer compareAnswer) {
compareAnswer.ballCounting(0);
compareAnswer.ballCounting(1);
compareAnswer.ballCounting(2);
}
}
Loading