diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..a55e7a17
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/kr/ladder/domain/InputValidation.java b/src/main/java/kr/ladder/domain/InputValidation.java
index a088608d..fea1ffd9 100644
--- a/src/main/java/kr/ladder/domain/InputValidation.java
+++ b/src/main/java/kr/ladder/domain/InputValidation.java
@@ -3,9 +3,17 @@
import kr.ladder.view.InputView;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
public class InputValidation {
public static final String ERROR_MASSAGE_PLAYER_NAME = "정해진 형식에 맞지 않습니다. 다시 입력해주세요";
+ public static final String ERROR_MESSAGE_LADDER_HEIGHT = "다시 입력해주세요. 최소 사다리 높이는 1입니다.";
+ public static final String ERROR_MESSAGE_LADDER_TYPE = "정수를 입력해 주세요.";
+ public static final String ERROR_MASSAGE_PRIZES_NUMBER = "경품을 다시 입력해주세요. 인원 수와 같은 수가 들어와야 합니다.";
+ private static final String ERROR_MASSAGE_NO_PLAYER_NAME = "해당 참가자가 없습니다.";
public static final int MIN_NAME_LENGTH = 1;
public static final int MAX_NAME_LENGTH = 5;
private final InputView inputView;
@@ -21,12 +29,13 @@ public InputValidation(){
- 각 이름중에 null이 있는 경우
3. 쉼표로 끝난 경우
4. 영어, 한글이 아닌 문자가 들어온 경우
+ 5. 같은 이름을 가진 플레이어가 있을 경우
-> player 입력을 다시 받는다
// 🤔InputView에서 요청해서 다시 받는게 맞나??
return 위에서 검증을 마친(정상적인) 플레이어 이름 배열
*/
- public String[] inspectPlayers(String[] players) throws IOException {
- return inspectPlayersNameLength(players);
+ public String[] inspectPlayers() throws IOException {
+ return inspectPlayersNameLength(inputView.getPlayer());
}
private String[] inspectPlayersNameLength(String[] players) throws IOException {
@@ -37,16 +46,16 @@ private String[] inspectPlayersNameLength(String[] players) throws IOException {
return players;
}
- private boolean correctLength(String[] players){
+ private boolean correctLength(String[] words){
int errors = 0; // 이름이 1~5글자 사이에 있지 않으면 count
- for (String playerName : players) {
- errors += countOverScopeName(playerName);
+ for (String word : words) {
+ errors += countOverScopeName(word);
}
return (errors == 0);
}
- private int countOverScopeName(String playerName){
- if (playerName.length() >= MIN_NAME_LENGTH && playerName.length() <= MAX_NAME_LENGTH){
+ private int countOverScopeName(String word){
+ if (word.length() >= MIN_NAME_LENGTH && word.length() <= MAX_NAME_LENGTH){
return 0;
}
return 1;
@@ -55,14 +64,85 @@ private int countOverScopeName(String playerName){
/* 사다리 높이 검사()
while 정상적인 사다리 높이가 아니라면
1. 사다리 높이가 0 이하 ✅
- 2. int가 아닌 경우
+ 2. int가 아닌 경우 ✅
-> 입력을 다시 받는다
return 정상적인 사다리 높이
*/
- public int inspectLadderHeight(int ladderHeight) throws IOException {
- if (ladderHeight < 1) {
+ public int inspectLadderHeight() throws IOException {
+ String ladderHeight = inputView.getLadderHeight();
+ while (!isInteger(ladderHeight) || !isAvailableHeight(Integer.parseInt(ladderHeight))) {
ladderHeight = inputView.getLadderHeight();
}
- return ladderHeight;
+ return Integer.parseInt(ladderHeight);
+ }
+
+ private boolean isAvailableHeight(int ladderHeight){
+ if (ladderHeight < 1) {
+ System.out.println(ERROR_MESSAGE_LADDER_HEIGHT);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isInteger(String ladderHeight) {
+ try {
+ Integer.parseInt(ladderHeight);
+ return true;
+ } catch (NumberFormatException e) {
+ System.out.println(ERROR_MESSAGE_LADDER_TYPE);
+ return false;
+ }
+ }
+
+ /*
+ 상품 목록 검사
+ while 정상적인 경품 목록이 아니라면
+ 1. 1~5 글자 사이가 아닌 경우 ✅(사람 이름 검사 로직 재사용)
+ 2. 플레이어 숫자와 동일한 갯수가 아닐 경우
+ -> 경품 입력을 다시 받는다.
+ return 정상적인 경품 목록
+ */
+
+ public String[] inspectPrizes(int playersNumber) throws IOException {
+ String[] prizes = inputView.getPrizes();
+ while (!correctPrizeLength(prizes) || !sameNumberAsPlayers(prizes.length, playersNumber)) {
+ prizes = inputView.getPrizes();
+ }
+ return prizes;
+ }
+
+ private boolean correctPrizeLength(String[] prizes) throws IOException {
+ if (!correctLength(prizes)) {// 각 이름이 1~5 글자 사이가 아니면
+ System.out.println(ERROR_MASSAGE_PLAYER_NAME);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean sameNumberAsPlayers(int prizesNumber, int playersNumber){
+ if (prizesNumber != playersNumber) {
+ System.out.println(ERROR_MASSAGE_PRIZES_NUMBER);
+ return false;
+ }
+ return true;
+ }
+
+ /*
+ 결과를 보고 싶은 사람 검사
+ players에 있는 사람만 입력받을 수 있도록 한다.
+ */
+ public String inspectCommand(String[] players) throws IOException {
+ String command = inputView.getCommand();
+
+ if (command.equals("all") || command.equals("춘식이")) { // 모두 출력하거나 실행 종료하는 로직은 다른 클래스에 위임한다.
+ return command;
+ }
+ Optional matchedPlayer = Arrays.stream(players).filter(p -> p.equals(command)).findFirst();
+ while (matchedPlayer.isEmpty()){
+ System.out.println(ERROR_MASSAGE_NO_PLAYER_NAME);
+ String newCommand = inputView.getCommand();
+ matchedPlayer = Arrays.stream(players).filter(p -> p.equals(newCommand)).findFirst();
+ }
+ return command;
}
}
diff --git a/src/main/java/kr/ladder/domain/Ladder.java b/src/main/java/kr/ladder/domain/Ladder.java
index f2c0209d..f4388418 100644
--- a/src/main/java/kr/ladder/domain/Ladder.java
+++ b/src/main/java/kr/ladder/domain/Ladder.java
@@ -1,7 +1,9 @@
package kr.ladder.domain;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class Ladder {
private final List ladder;
@@ -14,14 +16,15 @@ public void make(int playerNumber, int ladderHeight) {
// 1. 사다리를 만든다
makeLadderLine(playerNumber, ladderHeight);
// 2. 유효성 검사를 한다 (세로줄 공백인지 확인하고, 사다리 재입력 받음)
- while (!available()){
+ while (!available() && ladderHeight != 1){
+ ladder.clear();
makeLadderLine(playerNumber, ladderHeight);
}
// 3. OutputView에 넘겨서 바로 출력 가능하게 만들어준다.
// generate();
}
-
- private void makeLadderLine(int playerNumber, int ladderHeight){
+
+ private void makeLadderLine(int playerNumber, int ladderHeight) {
for (int i = 0; i < ladderHeight; i++) { // 행 넣기
LadderLine ladderLine = new LadderLine();
ladderLine.make(playerNumber);
@@ -30,7 +33,7 @@ private void makeLadderLine(int playerNumber, int ladderHeight){
}
private boolean available(){
- int[] countBlanks = new int[ladder.size()];
+ int[] countBlanks = new int[ladder.get(0).size()];
for (LadderLine ladderLine : ladder){
countBlank(countBlanks, ladderLine);
}
@@ -54,37 +57,47 @@ private boolean isFilled(int[] countBlanks){
}
return true;
}
-
-// 욕심 시작...
-// private void rebuildColumn(int ladderHeight){
-// int[] columnFalses = new int[ladder.size()];
-// for (LadderLine ladderLine : ladder) {
-// List booleans = ladderLine.ladderLine;
-// for (int i = 0; i < booleans.size(); i++) {
-// if (!booleans.get(i)){
-// columnFalses[i]++;
-// }
-// }
-// }
-//
-// for (int i = 0; i < columnFalses.length; i++) {
-// if (columnFalses[i] == ladderHeight) {
-// changeLadderColumn(i);
-// }
-// }
-// }
-
- // 하드 코딩해서 마지막 열에서 추가하는 것으로 생각중..
-// private void changeLadderColumn(int falseIndex){
-//
-// }
public String generate(){
StringBuilder sb = new StringBuilder();
for (LadderLine ladderLine : ladder) {
+ sb.append(" "); // player name과 맞추기 위해서
sb.append(ladderLine.generate()).append("\n");
}
return sb.toString();
}
+ public List play(){
+ List mappingIndex = new ArrayList<>();
+ int playerNum = ladder.get(0).size()+1;
+ for (int i = 0; i < playerNum; i++) { // player 수
+ int nowIndex = i;
+ for (int j = 0; j < ladder.size(); j++) { // 사다리 높이
+ nowIndex += compareRight(nowIndex, playerNum, j) + compareLeft(nowIndex, j);
+ }
+ mappingIndex.add(nowIndex);
+ }
+ return mappingIndex;
+ }
+
+ private int compareRight(int nowIndex, int playerNum, int height) {
+ if (nowIndex == playerNum-1) { // 오른쪽 끝
+ return 0;
+ }
+ if (ladder.get(height).get(nowIndex)) { // 오른쪽 발판 있으면
+ return 1;
+ }
+ return 0;
+ }
+
+ private int compareLeft(int nowIndex, int height){
+ if (nowIndex == 0) { // 왼쪽 끝
+ return 0;
+ }
+ if (ladder.get(height).get(nowIndex-1)) { // 왼쪽 발판 있으면
+ return -1;
+ }
+ return 0;
+ }
+
}
diff --git a/src/main/java/kr/ladder/domain/LadderGameController.java b/src/main/java/kr/ladder/domain/LadderGameController.java
index 42a71ca1..82b822e9 100644
--- a/src/main/java/kr/ladder/domain/LadderGameController.java
+++ b/src/main/java/kr/ladder/domain/LadderGameController.java
@@ -7,27 +7,37 @@
import java.io.IOException;
public class LadderGameController {
- private final InputView inputView;
-
- private final Ladder ladder;
-
- private final OutputView outputView;
- private final InputValidation validation;
-
- public LadderGameController() {
- this.inputView = new InputView();
- this.ladder = new Ladder();
- this.outputView = new OutputView();
- this.validation = new InputValidation();
+ private final Ladder ladder;
+ private final InputValidation validation;
+ private final ResultRepository resultRepository;
+
+ public LadderGameController() {
+ this.ladder = new Ladder();
+ this.validation = new InputValidation();
+ this.resultRepository = new ResultRepository();
+ }
+
+ public void run() throws IOException {
+ // 입력
+ String[] players = validation.inspectPlayers();
+ String[] prizes = validation.inspectPrizes(players.length);
+ int ladderHeight = validation.inspectLadderHeight();
+ // 사다리 만들기
+ ladder.make(players.length, ladderHeight);
+ // 플레이어와 경품 맵핑하기
+ resultRepository.mapping(ladder.play(), players, prizes, ladder.generate());
+ // 결과를 보고 싶은 사람 입력 받기
+ String command = validation.inspectCommand(players);
+ // 출력
+ while (!command.equals("춘식이")) {
+ resultRepository.printPrize(command);
+ command = validation.inspectCommand(players);
}
+ // 종료
+ exit();
+ }
- public void run() throws IOException {
- // 입력
- String[] players = validation.inspectPlayers(inputView.getPlayer());
- int ladderHeight = validation.inspectLadderHeight(inputView.getLadderHeight());
- // 사다리 만들기
- ladder.make(players.length, ladderHeight);
- // 출력
- outputView.printPlayersAndLadder(players, ladder.generate());
- }
+ private void exit() {
+ resultRepository.exit();
+ }
}
diff --git a/src/main/java/kr/ladder/domain/ResultRepository.java b/src/main/java/kr/ladder/domain/ResultRepository.java
new file mode 100644
index 00000000..a8f3c99b
--- /dev/null
+++ b/src/main/java/kr/ladder/domain/ResultRepository.java
@@ -0,0 +1,46 @@
+package kr.ladder.domain;
+
+import kr.ladder.view.OutputView;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ResultRepository {
+ private final Map result;
+ private final OutputView outputView;
+
+ public ResultRepository(){
+ this.result = new HashMap<>();
+ this.outputView = new OutputView();
+ }
+
+ public void mapping(List mappingIndex, String[] players, String[] prizes, String generatedLadder){
+ // player index, prize index
+ for (int i = 0; i < mappingIndex.size(); i++) {
+ result.put(players[i], prizes[mappingIndex.get(i)]);
+ }
+ outputView.printAll(players, generatedLadder, prizes);
+ }
+
+ public void printPrize(String command){
+ if (command.equals("all")) {
+ outputView.print(resultToString());
+ }
+ if (!command.equals("all")) {
+ outputView.print(result.get(command));
+ }
+ }
+
+ private String resultToString() {
+ StringBuilder sb = new StringBuilder();
+ for (String key : result.keySet()) {
+ sb.append(key).append(" : ").append(result.get(key)).append("\n");
+ }
+ return sb.toString();
+ }
+
+ public void exit() {
+ outputView.printExitMassage();
+ }
+}
diff --git a/src/main/java/kr/ladder/view/InputView.java b/src/main/java/kr/ladder/view/InputView.java
index 1bf04892..58f73e6e 100644
--- a/src/main/java/kr/ladder/view/InputView.java
+++ b/src/main/java/kr/ladder/view/InputView.java
@@ -6,7 +6,9 @@
public class InputView {
public static final String ASKING_LADDER_HEIGHT = "최대 사다리 높이는 몇 개인가요?";
- public static final String ASKING_PLAYER_NAMES = "참여할 사람 이름을 입력하세요. 각 이름은 최대 5글자까지 입니다. (이름은 쉼표(,)로 구분하세요)";
+ public static final String ASKING_PLAYER_NAME = "참여할 사람 이름을 입력하세요. 각 이름은 최대 5글자까지 입니다. (이름은 쉼표(,)로 구분하세요)";
+ public static final String ASKING_PRIZE_NAME = "경품 목록을 입력하세요. (경품은 쉼표(,)로 구분하세요)";
+ private static final String ASKING_RESULT_PLAYER = "결과를 보고 싶은 사람은?";
BufferedReader br;
public InputView() {
@@ -14,12 +16,22 @@ public InputView() {
}
public String[] getPlayer() throws IOException {
- System.out.println(ASKING_PLAYER_NAMES);
+ System.out.println(ASKING_PLAYER_NAME);
return br.readLine().split(",");
}
- public int getLadderHeight() throws IOException {
- System.out.println(ASKING_LADDER_HEIGHT);
- return Integer.parseInt(br.readLine());
+ public String getLadderHeight() throws IOException {
+ System.out.println("\n" + ASKING_LADDER_HEIGHT);
+ return br.readLine();
+ }
+
+ public String[] getPrizes() throws IOException {
+ System.out.println("\n" + ASKING_PRIZE_NAME);
+ return br.readLine().split(",");
+ }
+
+ public String getCommand() throws IOException {
+ System.out.println("\n" + ASKING_RESULT_PLAYER);
+ return br.readLine();
}
}
diff --git a/src/main/java/kr/ladder/view/OutputView.java b/src/main/java/kr/ladder/view/OutputView.java
index 502198a1..c15c7c9d 100644
--- a/src/main/java/kr/ladder/view/OutputView.java
+++ b/src/main/java/kr/ladder/view/OutputView.java
@@ -2,33 +2,56 @@
public class OutputView {
private static final int DEFAULT_WIDTH = 6;
+ private static final String EXIT_MASSAGE = "게임을 종료합니다.";
+ private static final String RESULT_MESSAGE = "실행 결과";
StringBuilder sb;
public OutputView(){
sb = new StringBuilder();
}
- public void printPlayersAndLadder(String[] players, String ladder){
- printPlayersName(players);
+ public void printAll(String[] players, String ladder, String[] prizes) {
+ sb.append("\n").append("사다리 결과").append("\n").append("\n");
+ printName(players);
printLadder(ladder);
+ printName(prizes);
+ sb.deleteCharAt(sb.length() - 1); // 마지막 개행 제거
System.out.println(sb);
sb.setLength(0); // stringBuilder 초기화 (리셋)
}
- // 이 부분은 OutputView 의 일이 아니지 않나 고민중...
- private void printPlayersName(String[] players){
- for (String player : players) {
- sb.append(player).append(insertBlank(player.length()));
+ private void printName(String[] words){
+ for (String word : words) {
+ sb.append(insertBlankAroundName(word));
}
sb.append("\n");
}
- public String insertBlank(int playerNameLength){
- return " ".repeat(DEFAULT_WIDTH - playerNameLength);
+ // TODO: 테스트를 위해 private -> public로 변경했는데 더 나은 방법이 없을까?
+ public String insertBlankAroundName(String word){
+ return insertFront(word.length()) + word + insertBack(word.length());
}
+ private String insertFront(int word){ // 글자수가 홀수면 (이름 뒤에 들어가는 공백 수 - 1) 개가 들어가야 한다.
+ return " ".repeat((int)Math.floor((double)(DEFAULT_WIDTH - word) / 2));
+ }
+
+ private String insertBack(int word){ // 글자수가 홀수면 (이름 앞에 들어가는 공백 수 + 1) 개가 들어가야 한다.
+ return " ".repeat((int)Math.ceil((double)(DEFAULT_WIDTH - word) / 2));
+ }
+
+
private void printLadder(String ladder){
sb.append(ladder);
}
+
+ public void printExitMassage() {
+ System.out.println(EXIT_MASSAGE);
+ }
+
+ public void print(String str) {
+ System.out.println("\n" + RESULT_MESSAGE);
+ System.out.println(str);
+ }
}
diff --git a/src/main/java/kr/ladder/Test.java b/src/test/java/ladder/InputTest.java
similarity index 92%
rename from src/main/java/kr/ladder/Test.java
rename to src/test/java/ladder/InputTest.java
index b3bf4391..53a52b27 100644
--- a/src/main/java/kr/ladder/Test.java
+++ b/src/test/java/ladder/InputTest.java
@@ -1,10 +1,10 @@
-package kr.ladder;
+package ladder;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
-public class Test {
+public class InputTest {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String name = br.readLine();
diff --git a/src/test/java/ladder/OutputTest.java b/src/test/java/ladder/OutputTest.java
new file mode 100644
index 00000000..e192a253
--- /dev/null
+++ b/src/test/java/ladder/OutputTest.java
@@ -0,0 +1,30 @@
+package ladder;
+
+import kr.ladder.view.OutputView;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+public class OutputTest {
+
+ @Test
+ @DisplayName("플레이어 이름 글자수에 따라 공백이 적절하게 들어가는지 확인.")
+ void testPlayerName(){
+ /*
+ 공백을 포함한 이름 글자 수는 6개이다. (사다리와 간격을 맞추기 위해)
+ 글자수가 홀수면 (ex) 이지안)
+ 1. 이름 앞에 들어가는 공백 수 = 이름 뒤에 들어가는 공백 수 - 1 (ex) 1)
+ 2. 이름 뒤에 들어가는 공백 수 = 이름 앞에 들어가는 공백 수 + 1 (ex) 2)
+ */
+ //given
+ OutputView outputView = new OutputView();
+ SoftAssertions softAssertions = new SoftAssertions();
+
+ //when
+ String playerName = "이지안";
+ String playerNameWithBlanks = outputView.insertBlankAroundName(playerName);
+
+ //then
+ softAssertions.assertThat(playerNameWithBlanks).isEqualTo(" 이지안 ");
+ }
+}
diff --git a/src/test/java/ladder/PlayerTest.java b/src/test/java/ladder/PlayerTest.java
deleted file mode 100644
index 56a13f6d..00000000
--- a/src/test/java/ladder/PlayerTest.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package ladder;
-
-import kr.ladder.view.OutputView;
-import org.assertj.core.api.SoftAssertions;
-import org.junit.jupiter.api.DisplayName;
-import org.junit.jupiter.api.Test;
-
-public class PlayerTest {
-
- @Test
- @DisplayName("플레이어 이름을 출력할 때 5글자를 정확히 출력하는지 확인")
- void testPlayerName(){
- //given
- OutputView outputView = new OutputView();
- SoftAssertions softAssertions = new SoftAssertions();
-
- //when
- String playerName = "하이이이이이";
- int blankRepeatNumber = outputView.insertBlank(playerName.length()).length();
-
- System.out.println(blankRepeatNumber);
- //then
- // 🤔넣는 공백이 0은 아니어야 하는데(=이름이 6글자라는 소리) 왜 테스트에 안걸릴까?
- softAssertions.assertThat(blankRepeatNumber).isPositive().isGreaterThan(1).isLessThan(5).isNotEqualTo(0);
- }
-
-}