diff --git a/build.gradle b/build.gradle index 1b85b74..1fa1679 100755 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'java' apply plugin: 'eclipse' version = '1.0.0' -sourceCompatibility = 1.8 +sourceCompatibility = 11 repositories { mavenCentral() @@ -11,4 +11,4 @@ repositories { dependencies { testCompile('org.junit.jupiter:junit-jupiter:5.4.2') testCompile('org.assertj:assertj-core:3.11.1') -} \ No newline at end of file +} diff --git a/src/main/java/bowling/Bowling.java b/src/main/java/bowling/Bowling.java new file mode 100644 index 0000000..4f8f1ed --- /dev/null +++ b/src/main/java/bowling/Bowling.java @@ -0,0 +1,49 @@ +package bowling; + +import bowling.frame.FirstPitchingFrame; +import bowling.frame.Frame; +import bowling.frame.result.FrameResult; +import bowling.score.Score; +import bowling.score.ScoreBoard; + +import java.util.ArrayList; +import java.util.List; + +public class Bowling { + private final List frameResults = new ArrayList<>(); + + public void bowl(final Score score) { + if (frameResults.isEmpty()) { + firstBowl(score); + return; + } + final Frame frame = getLastFrameResult().nextFrame(); + bowl(score, frame); + } + + private void firstBowl(final Score score) { + frameResults.clear(); + final Frame firstFrame = new FirstPitchingFrame(Frame.MIN_NO); + bowl(score, firstFrame); + } + + private void bowl(final Score score, final Frame frame) { + frameResults.add(frame.pitch(score)); + } + + public boolean hasNext() { + return frameResults.isEmpty() || getLastFrameResult().getNextFrameNo() <= Frame.MAX_NO; + } + + public int getNextFrameNo() { + return getLastFrameResult().getNextFrameNo(); + } + + private FrameResult getLastFrameResult() { + return frameResults.get(frameResults.size() - 1); + } + + public ScoreBoard getScoreBoard() { + return new ScoreBoard(frameResults); + } +} diff --git a/src/main/java/bowling/BowlingGame.java b/src/main/java/bowling/BowlingGame.java new file mode 100644 index 0000000..2f18002 --- /dev/null +++ b/src/main/java/bowling/BowlingGame.java @@ -0,0 +1,19 @@ +package bowling; + +import bowling.frame.Frame; +import bowling.view.InputView; +import bowling.view.ResultView; + +public class BowlingGame { + public static void main(String[] args) { + final Player player = InputView.askPlayerName(); + final Bowling bowling = new Bowling(); + + int nextFrameNo = Frame.MIN_NO; + while (bowling.hasNext()) { + bowling.bowl(InputView.askScore(nextFrameNo)); + ResultView.printScoreBoard(player, bowling.getScoreBoard()); + nextFrameNo = bowling.getNextFrameNo(); + } + } +} diff --git a/src/main/java/bowling/Player.java b/src/main/java/bowling/Player.java new file mode 100644 index 0000000..82484d7 --- /dev/null +++ b/src/main/java/bowling/Player.java @@ -0,0 +1,21 @@ +package bowling; + +public class Player { + private final String name; + + private static final int MAX_LENGTH = 3; + + public static Player of(final String name) { + return new Player(name); + } + + private Player(final String name) { + if (name.length() > MAX_LENGTH) + throw new IllegalArgumentException("3글자까지 가능"); + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/bowling/frame/FinalFrame.java b/src/main/java/bowling/frame/FinalFrame.java new file mode 100644 index 0000000..a3adace --- /dev/null +++ b/src/main/java/bowling/frame/FinalFrame.java @@ -0,0 +1,17 @@ +package bowling.frame; + +import bowling.frame.result.FinalResult; +import bowling.frame.result.FrameResult; +import bowling.score.Score; + +public class FinalFrame implements Frame { + @Override + public FrameResult pitch(final Score score) { + return FinalResult.of(score); + } + + @Override + public int getFrameNo() { + return Frame.MAX_NO; + } +} diff --git a/src/main/java/bowling/frame/FirstPitchingFrame.java b/src/main/java/bowling/frame/FirstPitchingFrame.java new file mode 100644 index 0000000..b79c0f7 --- /dev/null +++ b/src/main/java/bowling/frame/FirstPitchingFrame.java @@ -0,0 +1,31 @@ +package bowling.frame; + +import bowling.frame.result.FrameResult; +import bowling.frame.result.Gutter; +import bowling.frame.result.Hit; +import bowling.frame.result.Strike; +import bowling.score.Score; + +public class FirstPitchingFrame implements Frame { + private final int frameNo; + + public FirstPitchingFrame(final int frameNo) { + this.frameNo = frameNo; + } + + @Override + public FrameResult pitch(final Score score) { + if (score.isTen()) { + return Strike.of(frameNo); + } + if (score.isZero()){ + return Gutter.of(frameNo, true); + } + return Hit.of(frameNo, score); + } + + @Override + public int getFrameNo() { + return frameNo; + } +} diff --git a/src/main/java/bowling/frame/Frame.java b/src/main/java/bowling/frame/Frame.java new file mode 100644 index 0000000..65b6056 --- /dev/null +++ b/src/main/java/bowling/frame/Frame.java @@ -0,0 +1,13 @@ +package bowling.frame; + +import bowling.frame.result.FrameResult; +import bowling.score.Score; + +public interface Frame { + int MIN_NO = 1; + int MAX_NO = 10; + + FrameResult pitch(final Score score); + + int getFrameNo(); +} diff --git a/src/main/java/bowling/frame/SecondPitchingFrame.java b/src/main/java/bowling/frame/SecondPitchingFrame.java new file mode 100644 index 0000000..7515db6 --- /dev/null +++ b/src/main/java/bowling/frame/SecondPitchingFrame.java @@ -0,0 +1,34 @@ +package bowling.frame; + +import bowling.frame.result.FrameResult; +import bowling.frame.result.Gutter; +import bowling.frame.result.Miss; +import bowling.frame.result.Spare; +import bowling.score.Score; + +public class SecondPitchingFrame implements Frame { + private final int frameNo; + private final Score beforeScore; + + public SecondPitchingFrame(final int frameNo, final Score beforeScore) { + this.frameNo = frameNo; + this.beforeScore = beforeScore; + } + + @Override + public FrameResult pitch(final Score score) { + final Score totalScore = beforeScore.add(score); + if (totalScore.isTen()) { + return Spare.of(getFrameNo(), score); + } + if (totalScore.isZero()) { + return Gutter.of(getFrameNo(), false); + } + return Miss.of(getFrameNo(), score); + } + + @Override + public int getFrameNo() { + return frameNo; + } +} diff --git a/src/main/java/bowling/frame/result/FinalResult.java b/src/main/java/bowling/frame/result/FinalResult.java new file mode 100644 index 0000000..5e35c3f --- /dev/null +++ b/src/main/java/bowling/frame/result/FinalResult.java @@ -0,0 +1,47 @@ +package bowling.frame.result; + +import bowling.frame.Frame; +import bowling.score.Score; + +public class FinalResult implements FrameResult { + private final Score score; + + public static FinalResult of(final Score score) { + return new FinalResult(score); + } + + private FinalResult(final Score score) { + this.score = score; + } + + @Override + public Frame nextFrame() { + throw new IllegalArgumentException("마지막 프레임"); + } + + @Override + public Score getScore() { + return score; + } + + @Override + public int getFrameNo() { + return Frame.MAX_NO; + } + + @Override + public int getNextFrameNo() { + return Frame.MAX_NO; + } + + @Override + public String toString() { + if (score.isTen()) { + return Strike.DISPLAY_STRING; + } + if (score.isZero()) { + return Gutter.DISPLAY_STRING; + } + return String.valueOf(score.toInt()); + } +} diff --git a/src/main/java/bowling/frame/result/FrameResult.java b/src/main/java/bowling/frame/result/FrameResult.java new file mode 100644 index 0000000..b03620c --- /dev/null +++ b/src/main/java/bowling/frame/result/FrameResult.java @@ -0,0 +1,14 @@ +package bowling.frame.result; + +import bowling.frame.Frame; +import bowling.score.Score; + +public interface FrameResult { + Frame nextFrame(); // TODO: FinalFrame 조건 추가 + + Score getScore(); + + int getFrameNo(); + + int getNextFrameNo(); +} diff --git a/src/main/java/bowling/frame/result/Gutter.java b/src/main/java/bowling/frame/result/Gutter.java new file mode 100644 index 0000000..02cfa8b --- /dev/null +++ b/src/main/java/bowling/frame/result/Gutter.java @@ -0,0 +1,51 @@ +package bowling.frame.result; + +import bowling.frame.FirstPitchingFrame; +import bowling.frame.Frame; +import bowling.frame.SecondPitchingFrame; +import bowling.score.Score; + +public class Gutter implements FrameResult { + static final String DISPLAY_STRING = "-"; + private final int frameNo; + private final boolean isFirstPitching; + + public static Gutter of(final int frameNo, final boolean isFirstPitching) { + return new Gutter(frameNo, isFirstPitching); + } + + private Gutter(final int frameNo, final boolean isFirstPitching) { + this.frameNo = frameNo; + this.isFirstPitching = isFirstPitching; + } + + @Override + public Frame nextFrame() { + if (isFirstPitching) { + return new SecondPitchingFrame(getNextFrameNo(), Score.ZERO); + } + return new FirstPitchingFrame(getNextFrameNo()); + } + + @Override + public Score getScore() { + return Score.ZERO; + } + + @Override + public int getFrameNo() { + return frameNo; + } + + @Override + public int getNextFrameNo() { + if (isFirstPitching) + return frameNo; + return frameNo + 1; + } + + @Override + public String toString() { + return DISPLAY_STRING; + } +} diff --git a/src/main/java/bowling/frame/result/Hit.java b/src/main/java/bowling/frame/result/Hit.java new file mode 100644 index 0000000..a3aa505 --- /dev/null +++ b/src/main/java/bowling/frame/result/Hit.java @@ -0,0 +1,44 @@ +package bowling.frame.result; + +import bowling.frame.Frame; +import bowling.frame.SecondPitchingFrame; +import bowling.score.Score; + +public class Hit implements FrameResult { + private final int frameNo; + private final Score score; + + public static Hit of(final int frameNo, final Score score) { + return new Hit(frameNo, score); + } + + private Hit(final int frameNo, final Score score) { + this.frameNo = frameNo; + this.score = score; + } + + @Override + public Frame nextFrame() { + return new SecondPitchingFrame(frameNo, score); + } + + @Override + public Score getScore() { + return score; + } + + @Override + public int getFrameNo() { + return frameNo; + } + + @Override + public int getNextFrameNo() { + return frameNo; + } + + @Override + public String toString() { + return String.valueOf(score.toInt()); + } +} diff --git a/src/main/java/bowling/frame/result/Miss.java b/src/main/java/bowling/frame/result/Miss.java new file mode 100644 index 0000000..2d61e19 --- /dev/null +++ b/src/main/java/bowling/frame/result/Miss.java @@ -0,0 +1,44 @@ +package bowling.frame.result; + +import bowling.frame.FirstPitchingFrame; +import bowling.frame.Frame; +import bowling.score.Score; + +public class Miss implements FrameResult { + private final int frameNo; + private final Score score; + + public static Miss of(final int frameNo, final Score score) { + return new Miss(frameNo, score); + } + + private Miss(final int frameNo, final Score score) { + this.frameNo = frameNo; + this.score = score; + } + + @Override + public Frame nextFrame() { + return new FirstPitchingFrame(getNextFrameNo()); + } + + @Override + public Score getScore() { + return score; + } + + @Override + public int getFrameNo() { + return frameNo; + } + + @Override + public int getNextFrameNo() { + return frameNo + 1; + } + + @Override + public String toString() { + return score.isZero() ? "-" : String.valueOf(score.toInt()); + } +} diff --git a/src/main/java/bowling/frame/result/Spare.java b/src/main/java/bowling/frame/result/Spare.java new file mode 100644 index 0000000..44cc61b --- /dev/null +++ b/src/main/java/bowling/frame/result/Spare.java @@ -0,0 +1,45 @@ +package bowling.frame.result; + +import bowling.frame.FirstPitchingFrame; +import bowling.frame.Frame; +import bowling.score.Score; + +public class Spare implements FrameResult { + static final String DISPLAY_STRING = "/"; + private final int frameNo; + private final Score score; + + public static Spare of(final int frameNo, final Score score) { + return new Spare(frameNo, score); + } + + private Spare(final int frameNo, final Score score) { + this.frameNo = frameNo; + this.score = score; + } + + @Override + public Frame nextFrame() { + return new FirstPitchingFrame(getNextFrameNo()); + } + + @Override + public Score getScore() { + return score; + } + + @Override + public int getFrameNo() { + return frameNo; + } + + @Override + public int getNextFrameNo() { + return frameNo + 1; + } + + @Override + public String toString() { + return DISPLAY_STRING; + } +} diff --git a/src/main/java/bowling/frame/result/Strike.java b/src/main/java/bowling/frame/result/Strike.java new file mode 100644 index 0000000..29bcf6e --- /dev/null +++ b/src/main/java/bowling/frame/result/Strike.java @@ -0,0 +1,43 @@ +package bowling.frame.result; + +import bowling.frame.FirstPitchingFrame; +import bowling.frame.Frame; +import bowling.score.Score; + +public class Strike implements FrameResult { + static final String DISPLAY_STRING = "X"; + private final int frameNo; + + public static Strike of(final int frameNo) { + return new Strike(frameNo); + } + + private Strike(final int frameNo) { + this.frameNo = frameNo; + } + + @Override + public Frame nextFrame() { + return new FirstPitchingFrame(getNextFrameNo()); + } + + @Override + public Score getScore() { + return Score.TEN; + } + + @Override + public int getFrameNo() { + return frameNo; + } + + @Override + public int getNextFrameNo() { + return frameNo + 1; + } + + @Override + public String toString() { + return DISPLAY_STRING; + } +} diff --git a/src/main/java/bowling/score/Score.java b/src/main/java/bowling/score/Score.java new file mode 100644 index 0000000..237a760 --- /dev/null +++ b/src/main/java/bowling/score/Score.java @@ -0,0 +1,54 @@ +package bowling.score; + +public class Score { + private static final int MIN_VALUE = 0; + private static final int MAX_VALUE = 10; + public static final Score ZERO = Score.of(MIN_VALUE); + public static final Score TEN = Score.of(MAX_VALUE); + + private final int value; + + public static Score of(final int value) { + return new Score(value); + } + + private Score(final int value) { + if (value < MIN_VALUE || value > MAX_VALUE) + throw new IllegalArgumentException("점수는 0이상 10이하"); + this.value = value; + } + + public Score add(final Score score) { + return Score.of(this.value + score.toInt()); + } + + public boolean isZero() { + return this.equals(Score.ZERO); + } + + public boolean isTen() { + return this.equals(Score.TEN); + } + + public int toInt() { + return this.value; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (!(o instanceof Score)) return false; + final Score score = (Score) o; + return value == score.value; + } + + @Override + public int hashCode() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } +} diff --git a/src/main/java/bowling/score/ScoreBoard.java b/src/main/java/bowling/score/ScoreBoard.java new file mode 100644 index 0000000..b8ac4ab --- /dev/null +++ b/src/main/java/bowling/score/ScoreBoard.java @@ -0,0 +1,30 @@ +package bowling.score; + +import bowling.frame.result.FrameResult; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class ScoreBoard { + private final Map board = new HashMap<>(); + + public ScoreBoard(final List frameResults) { + for (final FrameResult frameResult : frameResults) { + final int frameNo = frameResult.getFrameNo(); + final String frameScore = board.get(frameNo); + + if (Objects.nonNull(frameScore)) { + final String totalFrameScore = String.join("|", frameScore, frameResult.toString()); + board.put(frameNo, totalFrameScore); + continue; + } + board.put(frameNo, frameResult.toString()); + } + } + + public String getFrameScore(final Integer frameNo) { + return board.get(frameNo); + } +} diff --git a/src/main/java/bowling/view/InputView.java b/src/main/java/bowling/view/InputView.java new file mode 100644 index 0000000..f300221 --- /dev/null +++ b/src/main/java/bowling/view/InputView.java @@ -0,0 +1,22 @@ +package bowling.view; + +import bowling.Player; +import bowling.score.Score; + +import java.util.Scanner; + +public class InputView { + private static Scanner scanner; + + public static Player askPlayerName() { + scanner = new Scanner(System.in); + System.out.print("플레이어 이름은(3 english letters)?: "); + return Player.of(scanner.nextLine()); + } + + public static Score askScore(final int frameNo) { + scanner = new Scanner(System.in); + System.out.print(frameNo + "프레임 투구: "); + return Score.of(scanner.nextInt()); + } +} diff --git a/src/main/java/bowling/view/ResultView.java b/src/main/java/bowling/view/ResultView.java new file mode 100644 index 0000000..1fcee46 --- /dev/null +++ b/src/main/java/bowling/view/ResultView.java @@ -0,0 +1,24 @@ +package bowling.view; + +import bowling.Player; +import bowling.frame.Frame; +import bowling.score.ScoreBoard; + +import java.util.Objects; + +public class ResultView { + public static void printScoreBoard(final Player player, final ScoreBoard scoreBoard) { + System.out.print("| NAME\t"); + for (int i = Frame.MIN_NO; i <= Frame.MAX_NO; i++) { + System.out.print("|\t" + i + "\t"); + } + System.out.println("|"); + + System.out.print("| " + player.getName() + "\t"); + for (int i = Frame.MIN_NO; i <= Frame.MAX_NO; i++) { + final String score = Objects.nonNull(scoreBoard.getFrameScore(i)) ? scoreBoard.getFrameScore(i) : ""; + System.out.print("|\t" + score + "\t"); + } + System.out.println("|\n"); + } +} diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt deleted file mode 100755 index e69de29..0000000