Skip to content

Step1 - 볼링 점수판(그리기) 리뷰 요청드립니다. #37

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

Merged
merged 44 commits into from
Jul 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
f75c463
[step1] docs : 구현 기능 목록(초벌) 작성
Integerous Jul 10, 2019
4f43503
[step1] feat : PlayerName(플레이어 이름) 객체 생성
Integerous Jul 10, 2019
d97a2d7
[step1] docs : 구현 기능 목록 수정
Integerous Jul 10, 2019
c91ccdd
[step1] feat : 플레이어 이름 유효성 체크
Integerous Jul 10, 2019
a527bef
[step1] feat : 입력받은 플레이어 이름을 대문자로 변환
Integerous Jul 10, 2019
b08f003
[step1] refactor : getter 대신 메세지 전달, 구현 기능 목록 수정
Integerous Jul 10, 2019
06e6e27
[step1] docs : 구현 기능 목록 수정
Integerous Jul 10, 2019
8689424
[step1] feat : main 메서드, InputView, OutputView 생성
Jul 11, 2019
01f2c62
[step1] feat : ScoreBoard 객체 생성
Jul 11, 2019
3b9de76
[step1] feat : Score 객체 생성
Jul 11, 2019
900551a
[step1] refactor : Score 객체 삭제
Jul 11, 2019
a8d9487
[step1] refactor : ScoreBoard에서 Scores 필드 제거
Jul 11, 2019
9c301d3
[step1] refactor : Frame 객체 생성 (draft), 초기 스코어보드 출력
Jul 11, 2019
b35d56f
[step1] refactor : PlayerName, View 제외하고 전부 삭제
Jul 11, 2019
4111c53
[step1] refactor : 객체 이름 변경 (PlayerName -> Player)
Integerous Jul 13, 2019
c67cb3c
[step1] feat : Pins(쓰러진 핀 개수) 객체 생성
Integerous Jul 13, 2019
38f0992
[step1] feat : NormalFrame 객체 생성
Integerous Jul 13, 2019
5bf2a61
[step1] feat : NormalFrame 객체에 다음 프레임 생성 로직 추가
Integerous Jul 13, 2019
75b4abc
[step1] refactor : 메서드 분리, 상수 사용
Integerous Jul 13, 2019
b3fa4e5
[step1] feat : FinalFrame 객체 생성
Integerous Jul 14, 2019
1bc898d
[step1] feat : 스트라이크가 아닌 초구와 2구의 합이 10이 넘는 예외 처리
Integerous Jul 15, 2019
c3963d0
[step1] feat : BowlingGame 객체 생성 (미완성)
Jul 16, 2019
962783a
[step1] feat : 쓰러진 핀 입력받는 부분 추가 (미완성)
Integerous Jul 16, 2019
4e903dc
[step1] refactor : NormalFrame, FinalFrame 삭제
Jul 16, 2019
6497c2c
[step1] feat : NormalFrame 객체 생성
Jul 17, 2019
fe3d527
[step1] feat : Frame, State 인터페이스 생성
Jul 17, 2019
7660217
[step1] feat : 쓰러진 핀의 개수를 입력받아 상태를 업데이트 하는 로직 추가 (미완성)
Jul 17, 2019
04f93c2
[step1] feat : NormalFrame에 index 필드 추가, FinalFrame 빈 객체 생성
Jul 17, 2019
42f9c87
[step1] feat : 프레임 번호를 FrameIndex 객체로 포장
Jul 17, 2019
6610cab
[step1] refactor : NormalFrame의 index를 FrameIndex로 변경
Jul 17, 2019
9ee2177
[step1] refactor : new 연산자 대신 팩토리메서드 사용
Integerous Jul 17, 2019
97488f4
[step1] feat : Strike, Hit 상태 클래스 생성
Integerous Jul 17, 2019
f846d9b
[step1] refactor : 패키지 분리, Strike 객체 메서드 구현
Integerous Jul 17, 2019
b242a51
[step1] feat : Hit 상태 업데이트 메서드 구현
Integerous Jul 17, 2019
9ddccdc
[step1] feat : Spare 클래스 구현
Integerous Jul 17, 2019
765a22c
[step1] feat : Miss 클래스 구현
Integerous Jul 17, 2019
f3ac7c9
[step1] feat : FinalFrame 클래스 구현
Integerous Jul 17, 2019
769a7a7
[step1] refactor : GameOverException 추가
Integerous Jul 17, 2019
e0a43e8
[step1] feat : BowlingGame 객체 구현
Integerous Jul 17, 2019
cc22913
[step1] feat : Application 클래스 내부 구현 (미완성)
Integerous Jul 17, 2019
c82476f
[step1] refactor : 프레임 번호 출력 수정
Integerous Jul 17, 2019
9d02fb1
[step1] feat : 모든 State에 상태 출력 메서드 추가
Integerous Jul 17, 2019
e77607e
[step1] feat : 마지막 프레임 상태출력을 위해 FinalState 구현
Integerous Jul 17, 2019
c8e04eb
[step1] feat : 볼링점수판 출력 일부 개선 (미완성)
Integerous Jul 17, 2019
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
53 changes: 45 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
# 볼링 게임 점수판
## 진행 방법
* 볼링 게임 점수판 요구사항을 파악한다.
* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다.
* 코드 리뷰 피드백에 대한 개선 작업을 하고 다시 PUSH한다.
* 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다.

## 온라인 코드 리뷰 과정
* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview)
~~~
플레이어 이름은(3 english letters)?: PJS
| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
| PJS | | | | | | | | | | |

1프레임 투구 : 10
| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
| PJS | X | | | | | | | | | |

2프레임 투구 : 8
| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
| PJS | X | 8 | | | | | | | | |

2프레임 투구 : 2
| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
| PJS | X | 8|/ | | | | | | | | |

3프레임 투구 : 7
| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
| PJS | X | 8|/ | 7 | | | | | | | |

3프레임 투구 : : 0
| NAME | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 |
| PJS | X | 8|/ | 7|- | | | | | | | |

...
~~~

## 구현 기능 목록

1. [ ] 플레이어 이름 입력 받기
- [x] 플레이어 (Player) 객체 생성
- [x] 3자리 영어 이름이 아니면 예외 발생
- [x] 숫자 혹은 한글이 포함되면 예외 발생
- [x] 입력받은 이름을 대문자로 변환
2. [ ] 사용자 이름이 포함된 프레임(1~10) 출력
3. [ ] 각 라운드별 투구 결과 입력 받기
- [ ] 1~9 라운드까지는 결과를 최소 1번, 최대 2번 입력 받기
- [ ] 10 라운드에서는 결과를 최소 2번, 최대 3번 입력 받기
4. [ ] 입력받은 투구 결과가 포함된 프레임(1~10)을 각 라운드마다 출력
- [ ] NormalFrame 객체 생성 (1~9)
- [ ] FinalFrame 객체 생성 (10)
- [ ] Frame 객체 생성 (for 중복 제거)


23 changes: 23 additions & 0 deletions src/main/java/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import domain.BowlingGame;
import domain.Pins;
import domain.Player;
import domain.frame.FrameIndex;
import view.InputView;
import view.OutputView;

public class Application {

public static void main(String[] args) {
Player player = Player.from(InputView.askPlayerName());
BowlingGame bowlingGame = BowlingGame.from(player);
OutputView.printBoard(bowlingGame);

while(!bowlingGame.isGameOver()) {
FrameIndex currentFrameIndex = bowlingGame.currentFrame().getIndex();
Pins fallenPins = InputView.askFallenPins(currentFrameIndex);

bowlingGame.play(fallenPins);
OutputView.printBoard(bowlingGame);
}
}
}
59 changes: 59 additions & 0 deletions src/main/java/domain/BowlingGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package domain;

import domain.frame.Frame;
import domain.frame.GameOverException;
import domain.frame.NormalFrame;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class BowlingGame {

Choose a reason for hiding this comment

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

BowlingGame에 대한 단위 테스트가 있으면 좋을 것 같아요 :)


private Player player;
private List<Frame> frames;

private BowlingGame(Player player) {
this.player = player;
this.frames = new ArrayList<>(Arrays.asList(NormalFrame.initFrame()));
}

public static BowlingGame from(Player player) {
return new BowlingGame(player);
}

public void play(Pins fallenPins) {
if (isGameOver()) {
throw new GameOverException();
}
Frame bowledFrame = currentFrame().fillFrame(fallenPins);

if (bowledFrame.getIndex().isSameIndex(currentFrame().getIndex())) {

Choose a reason for hiding this comment

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

List frames 의 일급컬렉션을 만들어 if분의 분기를 일급컬렉션으로 분리해보면 좋을 것 같습니다 :)

frames.set(lastFrameIndex(), bowledFrame);
}
if (!bowledFrame.getIndex().isSameIndex(currentFrame().getIndex())) {

Choose a reason for hiding this comment

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

규칙 4: 한 줄에 점을 하나만 찍는다.

Frame에서 Index를 꺼내와서 비교하는 로직이네요~
꺼내와서 처리하는 방법보다 직접 처리하는 메서드를 가지는 방법으로 구현해보세요 :)

frames.add(bowledFrame);
}
}

public Frame currentFrame() {
return frames.get(lastFrameIndex());
}

public boolean isGameOver() {
return frames.get(lastFrameIndex()).isGameOver();
}

private int lastFrameIndex() {
return frames.size() - 1;
}

public Player getPlayer() {
return player;
}

public List<Frame> getFrames() {
return Collections.unmodifiableList(frames);
}
}
66 changes: 66 additions & 0 deletions src/main/java/domain/Pins.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package domain;

import java.util.Objects;

public class Pins {
static final String ALERT_OUT_OF_PINS_RANGE = "쓰러진 핀의 개수는 최소 0개에서 최대 10개 입니다.";
public static final int STRIKE_PINS = 10;
public static final int GUTTER_PINS = 0;

private final int fallenPins;

private Pins(int fallenPins) {
validationPins(fallenPins);
this.fallenPins = fallenPins;
}

private void validationPins(int fallenPins) {
if (fallenPins < GUTTER_PINS || fallenPins > STRIKE_PINS) {
throw new IllegalArgumentException(ALERT_OUT_OF_PINS_RANGE);
}
}

public static Pins from(int fallenPins) {
return new Pins(fallenPins);
}

public static Pins from(Pins fallenPins) {
return new Pins(fallenPins.fallenPins);
}

public boolean isStrike() {
return this.fallenPins == STRIKE_PINS;
}

public boolean isSpare(Pins secondFallenPins) {
int sumOfPins = this.fallenPins + secondFallenPins.fallenPins;
validationPins(sumOfPins);
return sumOfPins == STRIKE_PINS;
}

public boolean exceedMiss(Pins secondFallenPins) {
return fallenPins + secondFallenPins.fallenPins >= STRIKE_PINS;
}

public boolean isMatch(Pins pins) {
return this.equals(pins);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pins pins = (Pins) o;
return fallenPins == pins.fallenPins;
}

@Override
public int hashCode() {
return Objects.hash(fallenPins);
}

@Override
public String toString() {
return String.valueOf(fallenPins);
}
}
31 changes: 31 additions & 0 deletions src/main/java/domain/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package domain;

public class Player {
private static final String REGEX_FOR_PLAYER_NAME = "^[a-zA-Z]{3}$";
static final String ALERT_INVALID_PLAYER_NAME = "플레이어의 이름은 세 자리의 영문만 가능합니다.";

private final String name;

private Player(String inputName) {
validationPlayerName(inputName);
this.name = inputName.toUpperCase();
}

public static Player from(String inputName) {
return new Player(inputName);
}

private void validationPlayerName(String inputName) {
if (!inputName.matches(REGEX_FOR_PLAYER_NAME)) {
throw new IllegalArgumentException(ALERT_INVALID_PLAYER_NAME);
}
}

public boolean isSameName(String nameToCompare) {
return nameToCompare.equals(name);
}

public String getName() {
return name;
}
}
72 changes: 72 additions & 0 deletions src/main/java/domain/frame/FinalFrame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package domain.frame;

import domain.Pins;
import domain.state.FinalState;
import domain.state.Miss;
import domain.state.StandBy;
import domain.state.State;

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

public class FinalFrame implements Frame {
private static final int INDEX_OF_FINAL_FRAME = 10;
private static final int MAXIMUM_BOWL_ORDER = 3;
private static final int INITIAL_BOWL_ORDER = 0;

private int bowlOrder;
private List<State> states = new ArrayList<>();

private FinalFrame() {
this.bowlOrder = INITIAL_BOWL_ORDER;
this.states.add(new StandBy());
}

public static FinalFrame of() {
return new FinalFrame();
}

@Override
public Frame fillFrame(Pins fallenPins) {
if (isGameOver()) {
throw new GameOverException();
}
bowlOrder++;

if (currentState().isClosed()) {
this.states.add(new StandBy().update(fallenPins));
return this;
}
State newState = currentState().update(fallenPins);
states.set(getLastBowlOrder(), newState);

return this;
}

@Override
public boolean isGameOver() {
return bowlOrder == MAXIMUM_BOWL_ORDER || isStateMiss();
}

private boolean isStateMiss() {
return states.get(getLastBowlOrder()) instanceof Miss;
}

public State currentState() {
return states.get(getLastBowlOrder());
}

private int getLastBowlOrder() {
return states.size() - 1;
}

@Override
public FrameIndex getIndex() {
return FrameIndex.from(INDEX_OF_FINAL_FRAME);
}

@Override
public State getState() {
return new FinalState(states);
}
}
15 changes: 15 additions & 0 deletions src/main/java/domain/frame/Frame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package domain.frame;

import domain.Pins;
import domain.state.State;

public interface Frame {

Frame fillFrame(Pins fallenPins);

boolean isGameOver();

FrameIndex getIndex();

State getState();
}
57 changes: 57 additions & 0 deletions src/main/java/domain/frame/FrameIndex.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package domain.frame;

import java.util.Objects;

public class FrameIndex {
static final String ALERT_INVALID_FRAME_NUMBER = "프레임 번호는 1부터 10까지만 허용됩니다.";
static final int MINIMUM_FRAME_INDEX = 1;
static final int MAXIMUM_FRAME_INDEX = 10;
static final int SECOND_TO_LAST_INDEX = 9;
static final int INCREMENT_AMOUNT = 1;

private int frameIndex;

private FrameIndex(int frameNumber) {
validationFrameNumber(frameNumber);
this.frameIndex = frameNumber;
}

public static FrameIndex from(int frameNumber) {
return new FrameIndex(frameNumber);
}

boolean isSecondToLastIndex() {
return frameIndex == SECOND_TO_LAST_INDEX;
}

FrameIndex increment() {
return from(frameIndex + INCREMENT_AMOUNT);
}

public boolean isSameIndex(FrameIndex target) {
return frameIndex == target.frameIndex;
}

private void validationFrameNumber(int frameNumber) {
if (frameNumber < MINIMUM_FRAME_INDEX || frameNumber > MAXIMUM_FRAME_INDEX) {
throw new IllegalArgumentException(ALERT_INVALID_FRAME_NUMBER);
}
}

public int getFrameIndex() {
return frameIndex;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FrameIndex that = (FrameIndex) o;
return frameIndex == that.frameIndex;
}

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

public class GameOverException extends RuntimeException {

public GameOverException() {
super("게임이 종료되었습니다. 게임을 더 진행하시려면 카운터에 문의하세요.");
}
}
Loading