diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3be8e77
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.project/
+.gradle/
+.idea/
+bin/
+build/
+.settings
+.classpath
+out/
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 1b85b74..2242c59 100755
--- a/build.gradle
+++ b/build.gradle
@@ -11,4 +11,9 @@ repositories {
dependencies {
testCompile('org.junit.jupiter:junit-jupiter:5.4.2')
testCompile('org.assertj:assertj-core:3.11.1')
+ implementation 'junit:junit:4.12'
+}
+
+test {
+ useJUnitPlatform()
}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 290541c..96038ea 100755
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Thu Feb 20 23:25:10 KST 2020
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
-zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/src/main/java/BowlingApplication.java b/src/main/java/BowlingApplication.java
new file mode 100644
index 0000000..743e51b
--- /dev/null
+++ b/src/main/java/BowlingApplication.java
@@ -0,0 +1,30 @@
+import domain.BowlingGame;
+import domain.FallingPin;
+import domain.Player;
+import domain.Players;
+import input.BowlingGameInputtable;
+import input.ConsoleBowlingGameInputInterface;
+import output.ConsoleBowlingScorePresenter;
+
+import java.util.Collections;
+
+public class BowlingApplication {
+ private static final int DEFAULT_BOWLING_MAX_FRAME = 10;
+ private static BowlingGameInputtable inputManager = new ConsoleBowlingGameInputInterface();
+
+ public static void main(String[] args) throws IllegalAccessException {
+ String playerName = inputManager.getPlayerName();
+ Player player = new Player(playerName);
+ Players playerList = new Players(Collections.singletonList(player));
+ BowlingGame bowlingGame = new BowlingGame(DEFAULT_BOWLING_MAX_FRAME, playerList);
+
+ while (bowlingGame.hasNext()) {
+ Player thisTurnPlayer = bowlingGame.nextPlayer();
+ FallingPin fallingPinCount = inputManager.getFallingPint();
+ thisTurnPlayer.bowl(fallingPinCount);
+ ConsoleBowlingScorePresenter.print(bowlingGame);
+ }
+
+ System.out.println("--볼링 게임 끝--");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/domain/BowlingGame.java b/src/main/java/domain/BowlingGame.java
new file mode 100644
index 0000000..d230b85
--- /dev/null
+++ b/src/main/java/domain/BowlingGame.java
@@ -0,0 +1,37 @@
+package domain;
+
+public class BowlingGame {
+ public final int MAX_FRAME;
+ private final Players players;
+ private int nowFrameNumber;
+
+ public BowlingGame(int maxFrame, Players players) {
+ this.MAX_FRAME = maxFrame;
+ this.players = players;
+ }
+
+ public boolean hasNext() {
+ return MAX_FRAME > nowFrameNumber;
+ }
+
+ public Player nextPlayer() {
+ if (players.isLastPlayer()) {
+ nowFrameNumber++;
+ }
+
+ return players.getCurrentPlayer();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("| NAME |");
+ for (int i = 0; i < MAX_FRAME; i++) {
+ stringBuilder.append(String.format(" %2d |", i + 1));
+ }
+
+ stringBuilder.append("\n").append(players);
+
+ return stringBuilder.toString() + "\n";
+ }
+}
diff --git a/src/main/java/domain/FallingPin.java b/src/main/java/domain/FallingPin.java
new file mode 100644
index 0000000..e83de30
--- /dev/null
+++ b/src/main/java/domain/FallingPin.java
@@ -0,0 +1,49 @@
+package domain;
+
+public class FallingPin {
+ public final static FallingPin MISS = new FallingPin(0);
+ public final static FallingPin NONE = new FallingPin(-1);
+ private int fallingPinCount;
+
+ public FallingPin(int fallingPinCount) {
+ if (fallingPinCount > Frame.DEFAULT_BOWLING_PIN) {
+ throw new IllegalArgumentException("10개 이하");
+ }
+ this.fallingPinCount = fallingPinCount;
+ }
+
+ public int value() {
+ if(this.equals(NONE)) {
+ return 0;
+ }
+ return fallingPinCount;
+ }
+
+ public String getSymbol() {
+ if (this.equals(MISS)) {
+ return Frame.FrameStatus.MISS.symbol;
+ }
+
+ if (this.equals(NONE)) {
+ return Frame.FrameStatus.NONE.symbol;
+ }
+
+ return String.valueOf(fallingPinCount);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ FallingPin that = (FallingPin) o;
+
+ return fallingPinCount == that.fallingPinCount;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return fallingPinCount;
+ }
+}
diff --git a/src/main/java/domain/Frame.java b/src/main/java/domain/Frame.java
new file mode 100644
index 0000000..ca77914
--- /dev/null
+++ b/src/main/java/domain/Frame.java
@@ -0,0 +1,123 @@
+package domain;
+
+import java.util.Objects;
+
+import static domain.Frame.FrameStatus.*;
+
+public class Frame implements Scorable {
+ public final static int DEFAULT_BOWLING_PIN = 10;
+ public final static Frame NONE_FRAME = new Frame();
+
+ private FallingPin first = FallingPin.NONE;
+ private FallingPin second = FallingPin.NONE;
+
+ private Frame nextFrame = NONE_FRAME;
+
+ public void fall(FallingPin pins) throws IllegalAccessException {
+ if (first.equals(FallingPin.NONE)) {
+ this.first = pins;
+ return;
+ }
+ this.second = pins;
+
+ if (pinCount() > DEFAULT_BOWLING_PIN) {
+ throw new IllegalAccessException();
+ }
+ }
+
+ private int pinCount() {
+ return first.value() + second.value();
+ }
+
+ public void setNextFrame(Frame nextFrame) {
+ this.nextFrame = nextFrame;
+ }
+
+ public boolean isEnd() {
+ if (FrameStatus.of(this).equals(STRIKE)) {
+ return true;
+ }
+ return !second.equals(FallingPin.NONE);
+ }
+
+ @Override
+ public Score getScore() { // 다듬을 여지 있음
+ if (Objects.isNull(nextFrame) || !isEnd()) {
+ return Score.NOT_DETERMINED;
+ }
+
+ Score nextFrameScore = Score.of(0);
+
+ if (FrameStatus.of(this).equals(STRIKE)) {
+ if (!nextFrame.isEnd()) {
+ return Score.NOT_DETERMINED;
+ }
+ nextFrameScore = nextFrame.getFallingPinCount();
+ }
+
+ if (FrameStatus.of(this).equals(SPARE)) {
+ if (nextFrame.isEndFirstTry()) {
+ return Score.NOT_DETERMINED;
+ }
+ nextFrameScore = nextFrame.getFallingPinCountAtFirstTry();
+ }
+
+ return getFallingPinCount().add(nextFrameScore);
+ }
+
+ private boolean isEndFirstTry() {
+ return first.equals(FallingPin.NONE);
+ }
+
+ private Score getFallingPinCountAtFirstTry() {
+ return Score.of(first.value());
+ }
+
+ private Score getFallingPinCount() {
+ return Score.of(first.value() + second.value());
+ }
+
+ @Override
+ public String toString() {
+ switch (FrameStatus.of(this)) {
+ case STRIKE:
+ return " " + STRIKE.symbol + " ";
+
+ case SPARE:
+ return " " + first.getSymbol() + "|" + SPARE.symbol + " ";
+
+ default:
+ return " " + first.getSymbol() + "|" + second.getSymbol() + " ";
+ }
+ }
+
+ public enum FrameStatus {
+ STRIKE("X"), SPARE("/"), MISS("-"), HIT(""), NONE(" ");
+
+ String symbol;
+
+ FrameStatus(String symbol) {
+ this.symbol = symbol;
+ }
+
+ public static FrameStatus of(Frame frame) {
+ FallingPin first = frame.first;
+
+ if (first.equals(FallingPin.NONE)) {
+ return NONE;
+ }
+
+ if (first.value() == DEFAULT_BOWLING_PIN) {
+ return STRIKE;
+ }
+
+ FallingPin second = frame.second;
+
+ if (first.value() + second.value() == DEFAULT_BOWLING_PIN) {
+ return SPARE;
+ }
+
+ return HIT;
+ }
+ }
+}
diff --git a/src/main/java/domain/FrameCollection.java b/src/main/java/domain/FrameCollection.java
new file mode 100644
index 0000000..f44af30
--- /dev/null
+++ b/src/main/java/domain/FrameCollection.java
@@ -0,0 +1,52 @@
+package domain;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Optional;
+
+public class FrameCollection {
+ private LinkedList frameList = new LinkedList<>();
+
+ // 현재 유효한 Frame 반환
+ public Frame getCurrent() {
+ Frame currentFrame;
+ if (frameList.isEmpty()) { // 비어있으면 List에 새 Frame 추가 후 반환
+ currentFrame = new Frame();
+ frameList.add(currentFrame);
+ return currentFrame;
+ }
+
+ // 비어있지 않지만
+ currentFrame = frameList.getLast();
+ if (currentFrame.isEnd()) { // 마지막 Frame이 끝났으면 새 Frame 추가 후 반환
+ Frame nextFrame = new Frame();
+ currentFrame.setNextFrame(nextFrame);
+ frameList.add(nextFrame);
+ return nextFrame;
+ }
+
+ return currentFrame; // 안끝났으면 해당 Frame 반환
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ frameList.stream()
+ .map(Frame::toString)
+ .forEach(s -> stringBuilder.append(s).append("|"));
+ for (int i = 0; i < Frame.DEFAULT_BOWLING_PIN - frameList.size(); i++) {
+ stringBuilder.append(" |");
+ }
+
+ return stringBuilder.toString();
+ }
+
+ public String getScore() {
+ StringBuilder stringBuilder = new StringBuilder();
+ frameList.stream()
+ .map(Frame::getScore)
+ .forEach(s -> stringBuilder.append(s).append(" | "));
+ return stringBuilder.toString();
+ }
+}
diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java
new file mode 100644
index 0000000..d195651
--- /dev/null
+++ b/src/main/java/domain/Player.java
@@ -0,0 +1,29 @@
+package domain;
+
+public class Player {
+ private String name;
+ private FrameCollection frames = new FrameCollection();
+
+ public Player(String playerName) {
+ this.name = playerName;
+ }
+
+ public void bowl(FallingPin pins) throws IllegalAccessException {
+ Frame currentFrame = frames.getCurrent();
+ currentFrame.fall(pins);
+ }
+
+ public boolean hasChance() {
+ Frame currentFrame = frames.getCurrent();
+ return !currentFrame.isEnd();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("| ").append(name).append(" |").append(frames).append("\n");
+ sb.append(" | ").append(frames.getScore());
+
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java
new file mode 100644
index 0000000..29add0f
--- /dev/null
+++ b/src/main/java/domain/Players.java
@@ -0,0 +1,41 @@
+package domain;
+
+import java.util.List;
+
+public class Players {
+ private List players;
+ private int currentPlayerIndex;
+
+ public Players(List players) {
+ this.players = players;
+ }
+
+ public Player getCurrentPlayer() {
+ Player currentPlayer = currentPlayer();
+ if (currentPlayer.hasChance()) {
+ return currentPlayer;
+ }
+
+ return nextPlayer();
+ }
+
+ private Player nextPlayer() {
+ currentPlayerIndex = currentPlayerIndex % players.size();
+ return players.get(currentPlayerIndex++);
+ }
+
+ public boolean isLastPlayer() {
+ return currentPlayerIndex == players.size();
+ }
+
+ private Player currentPlayer() {
+ return players.get(currentPlayerIndex);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder stringBuilder = new StringBuilder();
+ players.stream().map(Player::toString).forEach(stringBuilder::append);
+ return stringBuilder.toString();
+ }
+}
diff --git a/src/main/java/domain/Scorable.java b/src/main/java/domain/Scorable.java
new file mode 100644
index 0000000..0966d59
--- /dev/null
+++ b/src/main/java/domain/Scorable.java
@@ -0,0 +1,5 @@
+package domain;
+
+public interface Scorable {
+ Score getScore();
+}
diff --git a/src/main/java/domain/Score.java b/src/main/java/domain/Score.java
new file mode 100644
index 0000000..27b2bc7
--- /dev/null
+++ b/src/main/java/domain/Score.java
@@ -0,0 +1,29 @@
+package domain;
+
+public class Score {
+ public final static Score NOT_DETERMINED = Score.of(0);
+
+ private int score;
+
+ private Score(int score) {
+ this.score = score;
+ }
+
+ public static Score of(int score) {
+ return new Score(score);
+ }
+
+ public Score add(Score score) {
+ this.score += score.score;
+ return Score.of(this.score);
+ }
+
+ @Override
+ public String toString() {
+ if (this.equals(NOT_DETERMINED)) {
+ return " ";
+ }
+
+ return String.format("%2d", score);
+ }
+}
diff --git a/src/main/java/empty.txt b/src/main/java/empty.txt
deleted file mode 100755
index e69de29..0000000
diff --git a/src/main/java/input/BowlingGameInputtable.java b/src/main/java/input/BowlingGameInputtable.java
new file mode 100644
index 0000000..b67d6cd
--- /dev/null
+++ b/src/main/java/input/BowlingGameInputtable.java
@@ -0,0 +1,8 @@
+package input;
+
+import domain.FallingPin;
+
+public interface BowlingGameInputtable {
+ String getPlayerName();
+ FallingPin getFallingPint();
+}
diff --git a/src/main/java/input/ConsoleBowlingGameInputInterface.java b/src/main/java/input/ConsoleBowlingGameInputInterface.java
new file mode 100644
index 0000000..12700e7
--- /dev/null
+++ b/src/main/java/input/ConsoleBowlingGameInputInterface.java
@@ -0,0 +1,21 @@
+package input;
+
+import domain.FallingPin;
+
+import java.util.Scanner;
+
+public class ConsoleBowlingGameInputInterface implements BowlingGameInputtable {
+ private Scanner scanner = new Scanner(System.in);
+
+ @Override
+ public String getPlayerName() {
+ System.out.println("이름: ");
+ return scanner.nextLine();
+ }
+
+ @Override
+ public FallingPin getFallingPint() {
+ System.out.println("쓰러트린 핀: ");
+ return new FallingPin(scanner.nextInt());
+ }
+}
diff --git a/src/main/java/output/BowlingScorePresentable.java b/src/main/java/output/BowlingScorePresentable.java
new file mode 100644
index 0000000..0f79448
--- /dev/null
+++ b/src/main/java/output/BowlingScorePresentable.java
@@ -0,0 +1,11 @@
+package output;
+
+public interface BowlingScorePresentable {
+ /*void show(final List players);
+
+ void show(Player player);
+
+ void show(Frame frame);
+
+ void show(FallingPin fallingPin);*/
+}
diff --git a/src/main/java/output/ConsoleBowlingScorePresenter.java b/src/main/java/output/ConsoleBowlingScorePresenter.java
new file mode 100644
index 0000000..b8fa12d
--- /dev/null
+++ b/src/main/java/output/ConsoleBowlingScorePresenter.java
@@ -0,0 +1,53 @@
+package output;
+
+import domain.BowlingGame;
+
+public class ConsoleBowlingScorePresenter implements BowlingScorePresentable {
+
+ private final static String STRIKE_SYMBOL = "X";
+ private final static String SPARE_SYMBOL = "/";
+ private final static String MISS_SYMBOL = "-";
+
+ public static void print(BowlingGame bowlingGame) {
+
+ }
+
+ /*@Override
+ public void show(final List players) {
+ // print about player info (score)
+ }
+
+ @Override
+ public void show(Player player) {
+
+ }
+
+ @Override
+ public void show(Frame frame) {
+ StringBuilder stringBuilder = new StringBuilder();
+
+
+ switch (Frame.FrameStatus.of(frame)) {
+ case STRIKE:
+ break;
+ }
+
+
+ System.out.println(stringBuilder);
+ }
+
+ @Override
+ public void show(FallingPin fallingPin) {
+
+ }
+
+ public static void main(String[] args) {
+ String s = "5|/";
+ String s1 = "X";
+ // String s2 = "5|/";
+ System.out.print("|");
+
+ System.out.print(String.format("%-6s|%-6s|%-6s", s, s1, s));
+ System.out.print("|");
+ }*/
+}
diff --git a/src/test/java/empty.txt b/src/test/java/empty.txt
deleted file mode 100755
index e69de29..0000000
diff --git a/src/test/java/ouput/ConsoleBowlingScorePresenterTest.java b/src/test/java/ouput/ConsoleBowlingScorePresenterTest.java
new file mode 100644
index 0000000..929e049
--- /dev/null
+++ b/src/test/java/ouput/ConsoleBowlingScorePresenterTest.java
@@ -0,0 +1,56 @@
+package ouput;
+
+import domain.*;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+public class ConsoleBowlingScorePresenterTest {
+ @Test
+ @DisplayName("콘솔 출력 확인")
+ void scorePrintTest() throws IllegalAccessException {
+
+
+ /* FrameCollection frameCollection = new FrameCollection();
+ frameCollection.add(new Frame(new FallingPin(10), new FallingPin(0)));
+ frameCollection.add(new Frame(new FallingPin(3), new FallingPin(7)));
+ frameCollection.add(new Frame(new FallingPin(4), new FallingPin(4)));
+ frameCollection.add(new Frame(new FallingPin(4), new FallingPin(0)));
+ frameCollection.add(new Frame(new FallingPin(0), new FallingPin(4)));
+ frameCollection.add(new Frame(new FallingPin(0), new FallingPin(0)));*/
+
+ Player player = new Player("LSH");
+ BowlingGame bowlingGame = new BowlingGame(10, new Players(Collections.singletonList(player)));
+
+ player = bowlingGame.nextPlayer();
+
+ player.bowl(new FallingPin(10));
+ System.out.println(bowlingGame);
+
+ player.bowl(new FallingPin(0));
+ System.out.println(bowlingGame);
+ player.bowl(new FallingPin(3));
+ System.out.println(bowlingGame);
+
+ player.bowl(new FallingPin(7));
+ System.out.println(bowlingGame);
+ player.bowl(new FallingPin(3));
+ System.out.println(bowlingGame);
+
+ player.bowl(new FallingPin(4));
+ System.out.println(bowlingGame);
+ player.bowl(new FallingPin(4));
+ System.out.println(bowlingGame);
+
+ player.bowl(new FallingPin(0));
+ System.out.println(bowlingGame);
+ player.bowl(new FallingPin(4));
+ System.out.println(bowlingGame);
+
+ player.bowl(new FallingPin(4));
+ System.out.println(bowlingGame);
+ player.bowl(new FallingPin(0));
+ System.out.println(bowlingGame);
+ }
+}