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

Step2 - 볼링 점수판(그리기) #993

Open
wants to merge 3 commits into
base: mnyok
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
22 changes: 22 additions & 0 deletions src/main/java/bowling/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package bowling;

import bowling.domain.Hit;
import bowling.domain.Name;
import bowling.domain.Round;
import bowling.view.InputView;
import bowling.view.ResultView;

public class App {

public static void main(String[] args) {
Name name = InputView.inputName();

Round round = new Round();
ResultView.printRound(name, round);
while (!round.isEnd()) {
Hit hit = InputView.inputPins(round.getCurrentFrameNumber());
round.hit(hit);
ResultView.printRound(name, round);
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/bowling/domain/Frame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package bowling.domain;

public interface Frame {
Copy link
Contributor

Choose a reason for hiding this comment

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

인터페이스에 메서드 수가 너무 많다.
메서드 수를 줄일 수 있는 방법을 찾아보면 어떨까?


void play(Hit hit);

FrameStatus getFirstStatus();
FrameStatus getSecondStatus();
FrameStatus getThirdStatus();
Comment on lines +7 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

State getState()와 같이 하나로 합쳐서 구현해 보는 것은 어떨까?


Hit getFirstHit();
Hit getSecondHit();
Hit getThirdHit();

boolean isEnd();
}
11 changes: 11 additions & 0 deletions src/main/java/bowling/domain/FrameStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package bowling.domain;

public enum FrameStatus {
BEFORE,
PLAYING,
SKIP,
STRIKE,
SPARE,
MISS,
GUTTER;
}
43 changes: 43 additions & 0 deletions src/main/java/bowling/domain/Hit.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package bowling.domain;

public class Hit {
public static final int MIN = 0;
public static final int MAX = 10;
private final int hit;


public Hit(int hit) {
Comment on lines +7 to +9
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

validate(hit);
this.hit = hit;
}

private void validate(int hit) {
if (hit < MIN || hit > MAX) {
throw new IllegalArgumentException("범위를 벗어나는 점수가 입력되었습니다.");
}
}

public Hit plus(Hit target) {
return new Hit(hit + target.hit);
}

public boolean isMin() {
return hit == MIN;
}

public boolean isMax() {
return hit == MAX;
}

public int getScore() {
return hit;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof Hit)) {
return false;
}
return hit == ((Hit) obj).hit;
}
}
122 changes: 122 additions & 0 deletions src/main/java/bowling/domain/LastFrame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package bowling.domain;

public class LastFrame implements Frame {
private Hit first;
private Hit second;
private Hit third;

@Override
public void play(Hit hit) {
if (getFirstStatus() == FrameStatus.BEFORE) {
firstThrow(hit);
return;
}
if (getSecondStatus() == FrameStatus.BEFORE) {
secondThrow(hit);
return;
}
thirdThrow(hit);
}

private void firstThrow(Hit hit) {
this.first = hit;
}

private void secondThrow(Hit hit) {
this.second = hit;
}

private void thirdThrow(Hit hit) {
this.third = hit;
}

@Override
public FrameStatus getFirstStatus() {
return getNormalStatus(first);
}

@Override
public FrameStatus getSecondStatus() {
if (first == null || second == null) {
return FrameStatus.BEFORE;
}
if (first.isMax()) {
return getNormalStatus(second);
}
Hit sum = first.plus(second);
if (sum.isMax()) {
return FrameStatus.SPARE;
}
if (second.isMin()) {
return FrameStatus.GUTTER;
}
return FrameStatus.MISS;
}

@Override
public FrameStatus getThirdStatus() {
Copy link
Contributor

Choose a reason for hiding this comment

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

각 상태에 따른 if 문이 너무 많다.
자바의 다형성을 적용해 if문을 최소화하도록 도전해 보면 어떨까?

if (first == null || second == null || third == null) {
return FrameStatus.BEFORE;
}
if (!canPlayThird()) {
return FrameStatus.SKIP;
}
if (third.isMax()) {
return FrameStatus.STRIKE;
}
if (third.isMin()) {
return FrameStatus.GUTTER;
}
if (second.isMax()) {
return FrameStatus.MISS;
}
Hit sum = second.plus(third);
if (sum.isMax()) {
return FrameStatus.SPARE;
}
return FrameStatus.MISS;
}

private FrameStatus getNormalStatus(Hit hit) {
if (hit == null) {
return FrameStatus.BEFORE;
}
if (hit.isMax()) {
return FrameStatus.STRIKE;
}
if (hit.isMin()) {
return FrameStatus.GUTTER;
}
return FrameStatus.MISS;
}

@Override
public Hit getFirstHit() {
return first;
}

@Override
public Hit getSecondHit() {
return second;
}

@Override
public Hit getThirdHit() {
return third;
}

@Override
public boolean isEnd() {
if (first == null || second == null) {
return false;
}
if (third != null) {
return true;
}
return !canPlayThird();
}

private boolean canPlayThird() {
return getFirstStatus() == FrameStatus.STRIKE || getSecondStatus() == FrameStatus.SPARE;
}
}
21 changes: 21 additions & 0 deletions src/main/java/bowling/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package bowling.domain;

public class Name {
private final String name;


public Name(String name) {
validate(name);
this.name = name;
}

private void validate(String name) {
if (name.length() != 3) {
throw new IllegalArgumentException("이름은 3글자로 입력되어야 합니다");
}
}

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

public class NormalFrame implements Frame {
Copy link
Contributor

Choose a reason for hiding this comment

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

NormalFrame과 FinalFrame을 보면 중복 코드가 많다.
AbstractFrame과 같은 객체를 추가해 NormalFrame과 FinalFrame의 중복 로직을 제거해 보면 어떨까?

private Hit first;
private Hit second;

@Override
public void play(Hit hit) {
if (getFirstStatus() == FrameStatus.BEFORE) {
firstThrow(hit);
return;
}
secondThrow(hit);
}

private void firstThrow(Hit hit) {
this.first = hit;
if (hit.isMax()) {
second = new Hit(0);
}
}

private void secondThrow(Hit hit) {
this.second = hit;
}

@Override
public FrameStatus getFirstStatus() {
if (first == null) {
return FrameStatus.BEFORE;
}
if (first.isMax()) {
return FrameStatus.STRIKE;
}
if (first.isMin()) {
return FrameStatus.GUTTER;
}
return FrameStatus.MISS;
}

@Override
public FrameStatus getSecondStatus() {
if (first == null || second == null) {
return FrameStatus.BEFORE;
}
if (first.isMax()) {
return FrameStatus.SKIP;
}
Hit sum = first.plus(second);
if (sum.isMax()) {
return FrameStatus.SPARE;
}
if (second.isMin()) {
return FrameStatus.GUTTER;
}
return FrameStatus.MISS;
}

@Override
public FrameStatus getThirdStatus() {
return FrameStatus.SKIP;
}

@Override
public Hit getFirstHit() {
return first;
}

@Override
public Hit getSecondHit() {
return second;
}

@Override
public Hit getThirdHit() {
return new Hit(0);
}

@Override
public boolean isEnd() {
return first != null && second != null;
}
}
50 changes: 50 additions & 0 deletions src/main/java/bowling/domain/Round.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package bowling.domain;

import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Round {
private static final int ROUND_COUNT = 10;
private final List<Frame> frames;

public Round() {
frames = IntStream.range(0, ROUND_COUNT - 1)
.mapToObj(i -> new NormalFrame())
.collect(Collectors.toList());
frames.add(new LastFrame());
}

public void hit(Hit hit) {
Frame last = getLastPlayingFrame()
.orElseThrow(() -> new IllegalStateException("모든 프레임이 종료되었습니다."));
last.play(hit);
}

public boolean isEnd() {
Optional<Frame> last = getLastPlayingFrame();
return last.isEmpty();
}

public int getCurrentFrameNumber() {
Optional<Frame> last = getLastPlayingFrame();
if (last.isEmpty()) {
return ROUND_COUNT;
}
Frame currentFrame = last.get();
return frames.indexOf(currentFrame) + 1;

}

private Optional<Frame> getLastPlayingFrame() {
return frames.stream()
.filter(frame -> !frame.isEnd())
.findFirst();
}

public void forEach(Consumer<Frame> consumer) {
frames.forEach(consumer);
}
}
23 changes: 23 additions & 0 deletions src/main/java/bowling/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package bowling.view;

import bowling.domain.Name;
import bowling.domain.Hit;

import java.util.Scanner;

public class InputView {
private static final Scanner scanner = new Scanner(System.in);

public static Name inputName() {
System.out.print("플레이어 이름은 (3 english letters)?: ");

String name = scanner.nextLine();
return new Name(name);
}

public static Hit inputPins(int frame) {
System.out.printf("%d프레임 투구: ", frame);

return new Hit(scanner.nextInt());
}
}
Loading