-
Notifications
You must be signed in to change notification settings - Fork 39
[사다리 미션] 정상희 미션 제출합니다. #19
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
base: sangheejeong
Are you sure you want to change the base?
Changes from all commits
1196afa
8b96693
f20be9f
19995ef
49d105c
090cb0f
06a00a7
3e47a2a
07fe975
2265787
2fef17c
f7ab094
dbbb328
65d58d2
56b093f
5c6b21e
67fcc5a
74f098d
9763754
a16726a
69871ca
169ec00
ea543eb
e81fa34
047d483
2dfe464
42cdbd6
62f451d
422af42
494e2d9
b2b1220
7dbb8cd
67b09e4
5c280c4
8eac61b
beeb626
570c4d7
6f6b09a
95f8ec1
f31cacc
e43ee2d
7e4cd52
f8dce70
ac02d9c
d48bce2
ea12de3
01b8efe
7cf78a6
174ff32
6b26030
1d96fb1
0bd1928
76e1d31
6473cca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# 기능 목록 | ||
|
||
### 1. 플레이어 및 사다리 정보 입력 기능 | ||
+ 플레이어 이름과 결과 종류를 입력한다. | ||
+ 사다리 넓이 : (플레이어 수 - 1) | ||
+ 사다리 높이 : 사용자 입력 | ||
### 2. 사다리 실행 기능 | ||
+ |-----|-----| 가로 라인이 겹치지 않게 사다리를 생성한다. | ||
=> 즉, 앞 라인이 true면 다음 라인은 무조건 false이다. | ||
### 3. 사다리 출력 기능 | ||
+ 플레이어 이름 입력 순으로 출력 | ||
+ 생성된 사다리 출력 | ||
+ 결과 종류 입력 순으로 출력 | ||
+ 보고 싶은 실행 결과 출력 ("all"일 때는 모두 출력) | ||
|
||
### <사다리 구현> | ||
+ Boolean (다리) | ||
+ ture : 연결 | ||
+ false : 연결 X | ||
+ List<Boolean> (한 층의 다리 모음) | ||
+ 사다리의 넒이만큼 | ||
+ 다리가 연결되어 있으면(=true) 수평 방향으로 이동이 가능하다. | ||
+ List<Line> (모든 층의 다리 모음) | ||
+ 사다리의 높이만큼 | ||
Comment on lines
+1
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Comment] 제가 코드를 잘 이해할 수 있도록 리드미에 의도를 잘 담아주셔서 감사합니다.😄 이 리드미는 훌륭한 가치와 내용을 담은 리드미라고 생각해요. 기능을 명세화할 떄 여러가지 방법 있겠죠?
이런 측면에서 잘 구조화 해주신 것 같습니다. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import controller.LadderController; | ||
import domain.Ladder; | ||
import domain.Players; | ||
import domain.ResultTypes; | ||
|
||
public class Application { | ||
public static void main(String[] args) { | ||
runLadderGame(); | ||
} | ||
|
||
private static void runLadderGame() { | ||
LadderController ladderController = new LadderController(); | ||
|
||
Players players = ladderController.initializePlayers(); | ||
ResultTypes resultTypes = ladderController.initializeResults(players.getPlayersSize()); | ||
Ladder ladder = ladderController.initializeLadder(players.getPlayersSize()); | ||
|
||
ladderController.playGame(players, ladder); | ||
|
||
ladderController.displayAllOutput(players, resultTypes, ladder); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package controller; | ||
|
||
import domain.Ladder; | ||
import domain.Players; | ||
import domain.ResultTypes; | ||
import view.InputView; | ||
import view.OutputView; | ||
|
||
import java.util.List; | ||
|
||
public class LadderController { | ||
|
||
public Players initializePlayers() { | ||
List<String> playerNames = InputView.splitString(InputView.inputNames()); | ||
|
||
return new Players(playerNames); | ||
} | ||
|
||
public ResultTypes initializeResults(int resultsSize) { | ||
List<String> kindOfResults = InputView.splitString(InputView.inputLadderResults()); | ||
|
||
return new ResultTypes(kindOfResults, resultsSize); | ||
} | ||
|
||
public Ladder initializeLadder(int width) { | ||
int height = InputView.inputHeight(); | ||
|
||
return new Ladder(width, height); | ||
} | ||
|
||
public void playGame(Players players, Ladder ladder) { | ||
ladder.determineLadderResults(players); | ||
} | ||
|
||
public void displayAllOutput(Players players, ResultTypes resultTypes, Ladder ladder) { | ||
displayLadder(players, resultTypes, ladder); | ||
displayResults(resultTypes, players); | ||
} | ||
|
||
private void displayLadder(Players players, ResultTypes resultTypes, Ladder ladder) { | ||
OutputView.printPlayers(players); | ||
OutputView.drawLadder(ladder); | ||
OutputView.printResultTypes(resultTypes.getResultTypes()); | ||
} | ||
|
||
private void displayResults(ResultTypes resultTypes, Players players) { | ||
OutputView.printResult(players, resultTypes.getResultTypes()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
public class Ladder { | ||
|
||
private final List<Line> lines; | ||
|
||
public Ladder(int width, int height) { | ||
this.lines = new ArrayList<>(); | ||
createLadder(width, height); | ||
} | ||
|
||
public void createLadder(int width, int height) { | ||
for (int i = 0; i < height; i++) { | ||
lines.add(new Line(width)); | ||
} | ||
} | ||
|
||
public void determineLadderResults(Players players) { | ||
players.getPlayers().forEach(player -> player.moveAlongLadder(lines)); | ||
} | ||
|
||
public List<Line> getLadder() { | ||
return Collections.unmodifiableList(lines); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package domain; | ||
|
||
import java.util.function.Function; | ||
|
||
public enum LadderStep { | ||
CONNECTED { | ||
@Override | ||
public boolean canMove() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public LadderStep nextStep() { | ||
return NOT_CONNECTED; | ||
} | ||
}, | ||
NOT_CONNECTED { | ||
@Override | ||
public boolean canMove() { | ||
return false; | ||
} | ||
|
||
@Override | ||
public LadderStep nextStep() { | ||
return FROM_BOOLEAN.apply(randomTrueOrFalse()); | ||
} | ||
}; | ||
|
||
public abstract boolean canMove(); | ||
|
||
public abstract LadderStep nextStep(); | ||
|
||
public static final Function<Boolean, LadderStep> FROM_BOOLEAN = value -> { | ||
if (value) { | ||
return CONNECTED; | ||
} | ||
return NOT_CONNECTED; | ||
}; | ||
|
||
public static boolean randomTrueOrFalse() { | ||
return Math.random() < 0.5; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import static domain.LadderStep.randomTrueOrFalse; | ||
|
||
public class Line { | ||
private final List<LadderStep> ladderSteps; | ||
|
||
public Line(int width) { | ||
this.ladderSteps = new ArrayList<>(); | ||
createLine(width); | ||
} | ||
|
||
public void createLine(int width) { | ||
ladderSteps.add(LadderStep.FROM_BOOLEAN.apply(randomTrueOrFalse())); | ||
|
||
for (int i = 1; i < width - 1; i++) { | ||
ladderSteps.add(ladderSteps.get(i - 1).nextStep()); | ||
} | ||
} | ||
|
||
public void decideWhereToGo(Position position) { | ||
int ladderOrder = position.getPosition(); | ||
|
||
if (canMoveRight(ladderOrder)) { | ||
position.moveRight(ladderSteps.size()); | ||
return; | ||
} | ||
|
||
if (canMoveLeft(ladderOrder)) { | ||
position.moveLeft(); | ||
} | ||
} | ||
|
||
private boolean canMoveRight(int ladderOrder) { | ||
return ladderOrder < ladderSteps.size() && ladderSteps.get(ladderOrder).canMove(); | ||
} | ||
|
||
private boolean canMoveLeft(int ladderOrder) { | ||
return ladderOrder != 0 && ladderSteps.get(ladderOrder - 1).canMove(); | ||
} | ||
|
||
public List<LadderStep> getLine() { | ||
return Collections.unmodifiableList(ladderSteps); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package domain; | ||
|
||
import java.util.List; | ||
|
||
public class Player { | ||
|
||
private final PlayerName playerName; | ||
private final Position position; | ||
|
||
public Player(PlayerName name, Position position) { | ||
this.playerName = name; | ||
this.position = position; | ||
} | ||
|
||
public void moveAlongLadder(List<Line> ladder) { | ||
ladder.forEach(line -> line.decideWhereToGo(this.position)); | ||
} | ||
|
||
public PlayerName getPlayerName() { | ||
return playerName.getName(); | ||
} | ||
|
||
public int getPosition() { | ||
return position.getPosition(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package domain; | ||
|
||
public class PlayerName { | ||
|
||
private final String name; | ||
private final static int MAX_LENGTH = 5; | ||
private final static String INVALID_NAME = "all"; | ||
Comment on lines
+6
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Approve] 객체의 규칙을 한눈에 볼 수 있는 상수 정말 좋은데요? 👍 |
||
|
||
public PlayerName(String name) { | ||
validateName(name); | ||
this.name = name; | ||
} | ||
|
||
private void validateName(String name) { | ||
validateNotBlank(name); | ||
validateMaxLength(name); | ||
validateNotEqualAll(name); | ||
} | ||
|
||
private void validateNotBlank(String name) { | ||
if (name.isBlank()) { | ||
throw new IllegalArgumentException("이름은 공백일 수 없습니다."); | ||
} | ||
} | ||
|
||
private void validateMaxLength(String name) { | ||
if (name.length() > MAX_LENGTH) { | ||
throw new IllegalArgumentException("이름은 " + MAX_LENGTH + "자를 초과할 수 없습니다."); | ||
} | ||
} | ||
|
||
private void validateNotEqualAll(String name) { | ||
if (name.equals(INVALID_NAME)) { | ||
throw new IllegalArgumentException("이름은 " + INVALID_NAME + "일 수 없습니다."); | ||
} | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; // 메모리 주소 비교 | ||
if (o == null || getClass() != o.getClass()) return false; | ||
PlayerName that = (PlayerName) o; | ||
return name.equals(that.name); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return name.hashCode(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return name; | ||
} | ||
|
||
public PlayerName getName() { | ||
return this; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package domain; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.NoSuchElementException; | ||
import java.util.Set; | ||
|
||
public class Players { | ||
|
||
private final List<Player> players; | ||
private final static int MIN_PLAYER_SIZE = 2; | ||
|
||
public Players(List<String> playerNames) { | ||
validateSize(playerNames); | ||
validateDuplicateName(playerNames); | ||
this.players = createPlayer(playerNames); | ||
} | ||
|
||
private void validateSize(List<String> playerNames) { | ||
if (playerNames.size() < MIN_PLAYER_SIZE) { | ||
throw new IllegalArgumentException("플레이어 수는 2명 이상이어야 합니다."); | ||
} | ||
} | ||
|
||
private void validateDuplicateName(List<String> playerNames) { | ||
Set<String> playerNamesSet = new HashSet<>(playerNames); | ||
|
||
if (playerNames.size() != playerNamesSet.size()) { | ||
throw new IllegalArgumentException("동명이인인 플레이어가 존재합니다."); | ||
} | ||
} | ||
Comment on lines
+27
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Approve] 놓칠 수 있지만, 현재 서비스에선 중요한 로직이죠! |
||
|
||
private List<Player> createPlayer(List<String> playerNames) { | ||
List<Player> players = new ArrayList<>(); | ||
for (int i = 0; i < playerNames.size(); i++) { | ||
players.add(new Player(new PlayerName(playerNames.get(i)), new Position(i))); | ||
} | ||
|
||
return players; | ||
} | ||
|
||
public Player findByName(String viewerName) { | ||
PlayerName playerName = new PlayerName(viewerName); | ||
|
||
return players.stream() | ||
.filter(player -> player.getPlayerName().equals(playerName)) | ||
.findFirst() | ||
.orElseThrow(() -> new NoSuchElementException("플레이어 이름 '" + viewerName + "' 이 존재하지 않습니다.")); | ||
} | ||
|
||
public List<Player> getPlayers() { | ||
return Collections.unmodifiableList(players); | ||
} | ||
Comment on lines
+53
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Approve] 방어적 복사 👍👍 |
||
|
||
public int getPlayersSize() { | ||
return players.size(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package domain; | ||
|
||
public class Position { | ||
|
||
private int position; | ||
|
||
public Position(int position) { | ||
this.position = position; | ||
} | ||
|
||
public void moveLeft() { | ||
if (position == 0) { | ||
throw new IllegalStateException("가장 왼쪽 사다리이므로 왼쪽으로 이동이 불가합니다."); | ||
} | ||
position--; | ||
} | ||
|
||
public void moveRight(int maxPosition) { | ||
if (position == maxPosition) { | ||
throw new IllegalStateException("가장 오른쪽 사다리이므로 오른쪽으로 이동이 불가합니다."); | ||
} | ||
position++; | ||
} | ||
Comment on lines
+18
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Approve] 꼼꼼한 예외처리를 이용해 예상치못한 버그를 방지하는 것 매우 좋습니다! 추가적으로 해당 예외 상황에 대한 테스트를 추가해두면 누군가 해당 로직을 수정했을 떄, 잘못됨을 알아차릴수 있겠네요!! |
||
|
||
public int getPosition() { | ||
return position; | ||
} | ||
Comment on lines
+25
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Comment] position을 getter로 꺼내는 방식 보다 조금 더 이 값에 대해서 판단을 이 Position이란 객체에게 맡겨보는 것은 어떨까요? 위의 리뷰들을 참고해서 한번 변경해보면 좋을 것 같아요 |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Comment]
🎮 컨트롤러 나누기 5
다시 리드미로 돌아와서 생각해보면 좋을 것 같아요.