Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2e3d8b4
chore : 자바 버전 변경
sdrs6921 Aug 1, 2021
d4664a6
feat : Ball 도메인 테스트 및 구현
sdrs6921 Aug 16, 2021
6405206
feat : Ball 정적 팩토리 메서드 변환
sdrs6921 Aug 16, 2021
6e98c18
feat : Balls 테스트 및 구현
sdrs6921 Aug 16, 2021
095f012
feat : 숫자와 위치를 비교하는 메서드 테스트 및 기능 구현
sdrs6921 Aug 16, 2021
9dd497a
feat : 사용자 입력 DTO 테스트 및 구현
sdrs6921 Aug 17, 2021
78e36d0
feat : Dto 이름 변경
sdrs6921 Aug 17, 2021
75cc6cd
feat : RoundOutputDto 테스트 및 구현
sdrs6921 Aug 17, 2021
638f9c5
refactor : final 키워드 추가
sdrs6921 Aug 17, 2021
5d7a0ad
feat : Round 도메인 테스트 및 구현
sdrs6921 Aug 17, 2021
5b40911
feat : GameStatus 도메인 테스트 및 구현
sdrs6921 Aug 17, 2021
7c335bc
feat : RoundInputView, RoundOutputView 구현
sdrs6921 Aug 17, 2021
852b6d7
feat : RandomUtils 테스트 및 기능 구현
sdrs6921 Aug 17, 2021
ca1ce3f
feat : RoundController 기능 구현
sdrs6921 Aug 17, 2021
437ac9f
feat : GameView 구현
sdrs6921 Aug 17, 2021
2c18d86
feat : GameController 기능 구현
sdrs6921 Aug 17, 2021
0266c7e
refactor : 게임 종료시 출력 추가
sdrs6921 Aug 17, 2021
79051c8
refactor : View 인터페이스 분리
sdrs6921 Aug 31, 2021
f68276c
refactor : BallNumber VO 객체 테스트 및 구현
sdrs6921 Aug 31, 2021
510f345
refactor : Position VO 객체 테스트 및 구현
sdrs6921 Aug 31, 2021
1126d10
refactor : BallStatus 테스트 및 구현
sdrs6921 Aug 31, 2021
fa9bdf2
refactor : Ball 상태를 리턴하도록 변경
sdrs6921 Aug 31, 2021
0058a55
refactor : Balls 비교 메서드 로직 변경
sdrs6921 Aug 31, 2021
60d98f8
refactor : BallStatus 일급컬렉션 테스트 및 구현
sdrs6921 Aug 31, 2021
4835be7
refactor : RoundInputDto 권한 검증 로직 수정
sdrs6921 Aug 31, 2021
30b244f
refactor : 난수 생성 전략 패턴 구현
sdrs6921 Aug 31, 2021
aba6370
refactor : Round BallStatus 일급 컬렉션 사용
sdrs6921 Aug 31, 2021
ea315f2
refactor : GameStatus 문자열로 변경
sdrs6921 Aug 31, 2021
70ba8b8
refactor : Util 클래스 삭제 및 전략 패턴 클래스로 변경
sdrs6921 Aug 31, 2021
9e5fd66
refactor : Main 메서드 수정
sdrs6921 Aug 31, 2021
5c89623
refactor : 패키지 구조 수정
sdrs6921 Aug 31, 2021
bda0bd7
refactor : 중복 제거시 Set 자료구조 사용
sdrs6921 Aug 31, 2021
cc706a7
refactor : final 키워드 추가
sdrs6921 Sep 6, 2021
1212900
style : 메서드 위치 변경
sdrs6921 Sep 6, 2021
677c907
refactor : 생성자 접근 제어자 변경
sdrs6921 Sep 6, 2021
5f0b905
refactor : 외부에서 사용하지 않는 상수 접근 제어자 변경
sdrs6921 Sep 6, 2021
650891f
refactor : 재정의한 메서드에 @Override 키워드 추가
sdrs6921 Sep 6, 2021
a6ae180
refactor : 모든 객체를 불변 객체로 변경
sdrs6921 Sep 6, 2021
728b2fd
refactor : Balls 생성자 매개변수 변경
sdrs6921 Sep 16, 2021
2e86f14
refactor : Controller 로직 Round로 분리
sdrs6921 Sep 16, 2021
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
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ apply plugin: 'eclipse'

group = 'camp.nextstep'
version = '1.0.0'
sourceCompatibility = '1.8'
sourceCompatibility = '11'

repositories {
mavenCentral()
Expand Down
File renamed without changes.
30 changes: 30 additions & 0 deletions src/main/java/baseball/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package baseball;

import baseball.controller.GameController;
import baseball.controller.RoundController;
import baseball.domain.Generation;
import baseball.domain.RandomNumberGeneration;
import baseball.view.GameConsoleView;
import baseball.view.GameView;
import baseball.view.RoundInputConsoleView;
import baseball.view.RoundInputView;
import baseball.view.RoundOutputConsoleView;
import baseball.view.RoundOutputView;

import java.util.Random;
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
RoundInputView roundInputView = RoundInputConsoleView.from(scanner);
GameView gameView = GameConsoleView.from(scanner);
RoundOutputView roundOutputView = RoundOutputConsoleView.getInstance();
Random random = new Random();
Generation generation = new RandomNumberGeneration(random);
RoundController roundController = RoundController.of(roundInputView, roundOutputView, generation);
GameController gameController = GameController.of(roundController, gameView);
gameController.run();
scanner.close();
}
}
28 changes: 28 additions & 0 deletions src/main/java/baseball/controller/GameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package baseball.controller;

import baseball.domain.GameStatus;
import baseball.view.GameView;

public class GameController {

private final GameView gameView;
private final RoundController roundController;

public GameController(final RoundController roundController, final GameView gameView) {
this.roundController = roundController;
this.gameView = gameView;
}

public static GameController of(final RoundController roundController, final GameView gameView) {
return new GameController(roundController, gameView);
}

public void run() {
GameStatus gameStatus = GameStatus.PLAY;

while (gameStatus == GameStatus.PLAY) {
roundController.run();
gameStatus = gameView.gameInput();
}
}
}
47 changes: 47 additions & 0 deletions src/main/java/baseball/controller/RoundController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package baseball.controller;

import baseball.domain.Balls;
import baseball.domain.Generation;
import baseball.domain.Round;
import baseball.dto.RoundInputDto;
import baseball.dto.RoundOutputDto;
import baseball.view.RoundInputView;
import baseball.view.RoundOutputView;

import java.util.List;

public class RoundController {

private final RoundInputView roundInputView;
private final RoundOutputView roundOutputView;
private final Generation generation;

private RoundController(final RoundInputView roundInputView, final RoundOutputView roundOutputView,
final Generation generation) {
this.roundInputView = roundInputView;
this.roundOutputView = roundOutputView;
this.generation = generation;
}

public static RoundController of(final RoundInputView roundInputView, final RoundOutputView roundOutputView,
final Generation generation) {
return new RoundController(roundInputView, roundOutputView, generation);
}

public void run() {
Round round = Round.nextRound(generation);
int strike;

do {
RoundInputDto roundInputDto = roundInputView.roundUserInput();
List<Integer> userNumbers = roundInputDto.numbers();
Balls userBalls = Balls.from(userNumbers);
RoundOutputDto roundOutputDto = round.countResult(userBalls);
strike = roundOutputDto.strike();
roundOutputView.roundOutput(roundOutputDto);
} while (!round.hasEnough(strike));

roundOutputView.roundOverOutput();
}

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

import baseball.domain.vo.BallNumber;
import baseball.domain.vo.Position;

import java.util.Objects;

public class Ball {

private final BallNumber number;
private final Position position;

private Ball(final BallNumber number, final Position position) {
this.number = number;
this.position = position;
}

public static Ball of(final int number, final int position) {
BallNumber ballNumber = BallNumber.from(number);
Position ballPosition = Position.from(position);
return new Ball(ballNumber, ballPosition);
}

public BallStatus compare(final Ball other) {
if (this.equals(other)) {
return BallStatus.STRIKE;
}

if (other.hasSameNumber(number)) {
return BallStatus.BALL;
}

return BallStatus.NOTHING;
}

private boolean hasSameNumber(final BallNumber number) {
return this.number.equals(number);
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (!(o instanceof Ball)) return false;
final Ball ball = (Ball) o;
return number.equals(ball.number) && position.equals(ball.position);
}

@Override
public int hashCode() {
return Objects.hash(number, position);
}
}
15 changes: 15 additions & 0 deletions src/main/java/baseball/domain/BallStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package baseball.domain;

public enum BallStatus {
STRIKE,
BALL,
NOTHING;

public boolean isStrike() {
return this == STRIKE;
}

public boolean isBall() {
return this == BALL;
}
}
37 changes: 37 additions & 0 deletions src/main/java/baseball/domain/BallStatuses.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package baseball.domain;

import java.util.List;

public class BallStatuses {

private static final int BALL_STATUSES_SIZE = 3;

private final List<BallStatus> statuses;

private BallStatuses(final List<BallStatus> statuses) {
this.statuses = statuses;
}

public static BallStatuses from(final List<BallStatus> statuses) {
validate(statuses);
return new BallStatuses(statuses);
}

private static void validate(final List<BallStatus> statuses) {
if (statuses.size() != BALL_STATUSES_SIZE) {
throw new IllegalArgumentException("숫자야구 상태의 길이는 3이어야 합니다");
}
}

public int countStrike() {
return (int) statuses.stream()
.filter(BallStatus::isStrike)
.count();
}

public int countBall() {
return (int) statuses.stream()
.filter(BallStatus::isBall)
.count();
}
}
67 changes: 67 additions & 0 deletions src/main/java/baseball/domain/Balls.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package baseball.domain;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

public class Balls {

private static final int START_POSITION = 1;
private static final int MAX_POSITION = 3;

private final List<Ball> values;

private Balls(final List<Ball> values) {
this.values = values;
}

public static Balls from(final Collection<Integer> numbers) {
validate(numbers);
List<Ball> balls = changeBallsFrom(numbers);
return new Balls(balls);
}

private static List<Ball> changeBallsFrom(final Collection<Integer> numbers) {
AtomicInteger position = new AtomicInteger(START_POSITION);

return numbers.stream()
.map(number -> Ball.of(number, position.getAndIncrement()))
.collect(Collectors.toList());
}

private static void validate(Collection<Integer> numbers) {
List<Integer> distinctNumber = extractDistinctNumber(numbers);

if (distinctNumber.size() != numbers.size()) {
throw new IllegalArgumentException("중복된 수가 존재합니다");
}

if (distinctNumber.size() != MAX_POSITION) {
throw new IllegalArgumentException("길이가 3이어야 합니다");
}
}

private static List<Integer> extractDistinctNumber(final Collection<Integer> numbers) {
Set<Integer> set = new LinkedHashSet<>(numbers);
return new ArrayList<>(set);
}

public BallStatuses compare(final Balls other) {
List<BallStatus> statuses = values.stream()
.map(other::compareBallStatus)
.collect(Collectors.toList());
return BallStatuses.from(statuses);
}

public BallStatus compareBallStatus(final Ball other) {
return values.stream()
.map(ball -> ball.compare(other))
.filter(ballStatus -> ballStatus.isStrike() || ballStatus.isBall())
.findAny()
.orElse(BallStatus.NOTHING);
}
}
21 changes: 21 additions & 0 deletions src/main/java/baseball/domain/GameStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package baseball.domain;

import java.util.Arrays;

public enum GameStatus {
PLAY("1"),
OVER("2");

private final String status;

GameStatus(final String status) {
this.status = status;
}

public static GameStatus from(final String status) {
return Arrays.stream(GameStatus.values())
.filter(value -> value.status.equals(status))
.findAny()
.orElseThrow(() -> new IllegalArgumentException("잘못된 게임의 상태입니다"));
}
}
6 changes: 6 additions & 0 deletions src/main/java/baseball/domain/Generation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package baseball.domain;

public interface Generation {

int generate();
}
25 changes: 25 additions & 0 deletions src/main/java/baseball/domain/RandomNumberGeneration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package baseball.domain;

import java.util.Random;

public class RandomNumberGeneration implements Generation {

private static final int START_INCLUSIVE = 1;
private static final int END_INCLUSIVE = 9;

private final Random random;

public RandomNumberGeneration(final Random random) {
this.random = random;
}


public static Generation from(final Random random) {
return new RandomNumberGeneration(random);
}

@Override
public int generate() {
return START_INCLUSIVE + random.nextInt(START_INCLUSIVE + END_INCLUSIVE - START_INCLUSIVE);
}
}
48 changes: 48 additions & 0 deletions src/main/java/baseball/domain/Round.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package baseball.domain;

import baseball.dto.RoundOutputDto;

import java.util.LinkedHashSet;
import java.util.Set;

public class Round {

private static final int ENOUGH_STRIKE_INCLUSIVE = 3;
private static final int BASEBALL_LENGTH = 3;

private final Balls balls;

private Round(final Balls balls) {
this.balls = balls;
}

public static Round from(Balls balls) {
return new Round(balls);
}

public static Round nextRound(final Generation generation) {
Set<Integer> numbers = generateNumbers(generation);
Balls balls = Balls.from(numbers);
return new Round(balls);
}

private static Set<Integer> generateNumbers(final Generation generation) {
Set<Integer> set = new LinkedHashSet<>();
while (set.size() < BASEBALL_LENGTH) {
int systemNumber = generation.generate();
set.add(systemNumber);
}
return set;
}

public RoundOutputDto countResult(Balls userBalls) {
BallStatuses ballStatuses = balls.compare(userBalls);
int strike = ballStatuses.countStrike();
int ball = ballStatuses.countBall();
return RoundOutputDto.of(strike, ball);
}

public boolean hasEnough(final int strike) {
return strike == ENOUGH_STRIKE_INCLUSIVE;
}
}
Loading