-
Notifications
You must be signed in to change notification settings - Fork 12
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
[사다리 타기] 김동균 미션 제출합니다. #4
base: dongkyun0713
Are you sure you want to change the base?
Changes from all commits
2ed04d7
c4f63be
e5c8d33
ce5e44a
105c223
3afef84
b149802
291c80b
d9deef5
a3a68d9
489e113
5a312a5
b4091ba
a586326
0393ada
468d016
d97ec88
4eb46b4
39a89bb
a9a4c0f
c50ea9a
89ad7c2
73a9881
58bd155
9894ad3
59de099
93374cc
e9a3a39
8ec798b
b0f375a
2f0bf29
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,35 @@ | ||
## 구현할 기능 목록 | ||
|
||
- [x] 참여할 사람 이름을 입력 | ||
- [x] 참여할 사람 입력을 위한 안내 출력 | ||
- [x] 참여할 사람 이름을 쉼표(,)를 기준으로 분리 | ||
- [x] 참여할 사람 이름을 입력받아 유효성 검사 | ||
|
||
- [x] 사다리 높이 입력 | ||
- [x] 사다리 높이 입력을 위한 안내 출력 | ||
- [x] 사다리 높이를 입력받아 유효성 검사 | ||
|
||
- [x] 결과 출력 | ||
- [x] 참여한 사람의 이름 출력 | ||
- [x] 사다리 결과 출력 | ||
|
||
## 우리가 생각한 사다리 | ||
|
||
- 하나의 행은 여러 개의 연결로 이루어져 있고, 사다리는 여러 개의 행으로 이루어져 있다. | ||
|
||
## 우리가 필요하다고 생각하는 객체 | ||
|
||
- 참여자 | ||
- 해야할 일: 참여할 사람 이름을 입력받아 유효성 검사 | ||
- 참여자들 | ||
- 해야할 일: 참여할 사람들을 생성하고 중복 여부를 검사 | ||
- 기준 | ||
- 해야할 일: 사다리 생성 전략을 담당하고 기준에 맞게 연결 여부를 생성 | ||
- 행 | ||
- 해야할 일: 사다리의 가로줄을 담당하고 기준에 맞게 무작위로 연결 | ||
- 연결 | ||
- 해야할 일: 연결 여부를 판단하고 연결된 결과를 반환 | ||
- 사다리 | ||
- 해야할 일: 사다리 높이에 맞게 행을 생성 | ||
- 입출력 뷰 | ||
- 해야할 일: 사용자 입력을 받고 결과를 출력 | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import controller.LadderGameController; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
LadderGameController ladderGameController = new LadderGameController(); | ||
ladderGameController.run(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package controller; | ||
|
||
import model.ladder.Ladder; | ||
import model.ladder.strategy.RandomGenerateStrategy; | ||
import model.players.Players; | ||
import view.InputView; | ||
import view.OutputView; | ||
|
||
public class LadderGameController { | ||
public void run() { | ||
Players players = initPlayers(); | ||
int countOfPlayers = players.countOfPlayers(); | ||
int height = InputView.readHeight(); | ||
Ladder ladder = initLadder(countOfPlayers, height); | ||
OutputView.printResult(players.getPlayerNames(), ladder.getLadderInformation()); | ||
} | ||
|
||
private Players initPlayers() { | ||
return new Players(InputView.readPlayerNames()); | ||
} | ||
|
||
private Ladder initLadder(int countOfPlayers, int height) { | ||
Ladder ladder = initLadderStrategy(); | ||
ladder.init(countOfPlayers, height); | ||
return ladder; | ||
} | ||
|
||
private Ladder initLadderStrategy() { | ||
return new Ladder(new RandomGenerateStrategy()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package model.ladder; | ||
|
||
public enum Bridge { | ||
EMPTY, EXIST; | ||
|
||
public static Bridge of(boolean exist) { | ||
if (exist) { | ||
return EXIST; | ||
} | ||
return EMPTY; | ||
} | ||
|
||
public boolean isExist() { | ||
return this == EXIST; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package model.ladder; | ||
|
||
import model.ladder.strategy.GenerateStrategy; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class Ladder { | ||
private final GenerateStrategy generateStrategy; | ||
private final List<Row> rows = new ArrayList<>(); | ||
|
||
public Ladder(GenerateStrategy generateStrategy) { | ||
this.generateStrategy = generateStrategy; | ||
} | ||
|
||
public void init(int countOfPlayer, int countOfHeight) { | ||
for (int i = 0; i < countOfHeight; i++) { | ||
rows.add(new Row(countOfPlayer, generateStrategy)); | ||
} | ||
} | ||
|
||
public List<List<Boolean>> getLadder() { | ||
return rows.stream() | ||
.map(row -> row.getBridges().stream() | ||
.map(Bridge::isExist) | ||
.toList()) | ||
.toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package model.ladder; | ||
|
||
import model.ladder.strategy.GenerateStrategy; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class Row { | ||
private final GenerateStrategy generateStrategy; | ||
private final List<Bridge> bridges = new ArrayList<>(); | ||
|
||
public Row(int countOfPlayer, GenerateStrategy generateStrategy) { | ||
this.generateStrategy = generateStrategy; | ||
generateRow(countOfPlayer); | ||
} | ||
|
||
private void generateRow(int countOfPlayer) { | ||
generateStrategy.generate(countOfPlayer) | ||
.forEach(bridge -> bridges.add(Bridge.of(bridge))); | ||
} | ||
Comment on lines
+12
to
+20
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. 전략 패턴을 활용한 것이 눈에 띄네요. 혹시 전략 패턴에 대해서 학습한 것이 있다면 말씀해주실 수 있나요? 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. 이번에 전략 패턴을 처음으로 사용해보면서 공부해봤습니다! |
||
|
||
public List<Bridge> getBridges() { | ||
return bridges; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package model.ladder.strategy; | ||
|
||
import java.util.List; | ||
|
||
public interface GenerateStrategy { | ||
List<Boolean> generate(int countOfPlayer); | ||
} | ||
Comment on lines
+5
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. 추상화 활용 👍 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package model.ladder.strategy; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class RandomGenerateStrategy implements GenerateStrategy { | ||
private static final int BRIDGE_UNCONNECTED = 0; | ||
private static final int MINIMUM_PLAYER_COUNT = 2; | ||
|
||
@Override | ||
public List<Boolean> generate(int countOfPlayer) { | ||
validatePlayerCount(countOfPlayer); | ||
return createBridges(countOfPlayer - 1); | ||
} | ||
|
||
private void validatePlayerCount(int countOfPlayer) { | ||
if (countOfPlayer < MINIMUM_PLAYER_COUNT) { | ||
throw new IllegalArgumentException("플레이어는 최소 2명 이상이어야 합니다."); | ||
} | ||
} | ||
|
||
private List<Boolean> createBridges(int countOfBridge) { | ||
List<Boolean> bridges = new ArrayList<>(); | ||
for (int i = 0; i < countOfBridge; i++) { | ||
bridges.add(decideBridgeConnection(bridges, i)); | ||
} | ||
return bridges; | ||
} | ||
|
||
private boolean decideBridgeConnection(List<Boolean> bridges, int currentIndex) { | ||
if (wasPreviousBridgeConnected(bridges, currentIndex)) { | ||
return false; | ||
} | ||
return decideBridgeConnection(); | ||
} | ||
|
||
private boolean wasPreviousBridgeConnected(List<Boolean> bridges, int currentIndex) { | ||
if (currentIndex == 0) { | ||
return false; | ||
} | ||
return bridges.get(currentIndex - 1); | ||
} | ||
|
||
private boolean decideBridgeConnection() { | ||
return (int) (Math.random() * 2) != BRIDGE_UNCONNECTED; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package model.players; | ||
|
||
public class Player { | ||
private static final int MAXIMUM_ALLOWED_LENGTH = 5; | ||
|
||
private final String name; | ||
|
||
public Player(String name) { | ||
checkPlayerName(name); | ||
this.name = name; | ||
} | ||
|
||
protected String getName() { | ||
return name; | ||
} | ||
|
||
private void checkPlayerName(String name) { | ||
checkNameIsNotNull(name); | ||
checkNameIsNotEmpty(name); | ||
checkNameLength(name); | ||
checkNameIsNotNumber(name); | ||
checkNameIsNotKorean(name); | ||
checkNameIsNotSpecialCharacter(name); | ||
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. 사용자 이름에 대한 메소드들을 잘 분리해두셨군요. 다만, 생성자에서는 |
||
} | ||
|
||
private void checkNameIsNotNull(String name) { | ||
if (name == null) { | ||
throw new IllegalArgumentException("참여자 이름은 null일 수 없습니다."); | ||
} | ||
} | ||
|
||
private void checkNameIsNotEmpty(String name) { | ||
if (name.isEmpty()) { | ||
throw new IllegalArgumentException("참여자 이름은 빈 문자열일 수 없습니다."); | ||
} | ||
} | ||
|
||
private void checkNameLength(String name) { | ||
if (name.length() > MAXIMUM_ALLOWED_LENGTH) { | ||
throw new IllegalArgumentException("참여자 이름은 5글자를 넘을 수 없습니다."); | ||
} | ||
} | ||
|
||
private void checkNameIsNotNumber(String name) { | ||
if (name.matches(".*\\d.*")) { | ||
throw new IllegalArgumentException("참여자 이름에 숫자가 포함될 수 없습니다."); | ||
} | ||
} | ||
|
||
private void checkNameIsNotKorean(String name) { | ||
if (name.matches(".*[ㄱ-ㅎㅏ-ㅣ가-힣].*")) { | ||
throw new IllegalArgumentException("참여자 이름에 한글이 포함될 수 없습니다."); | ||
} | ||
} | ||
|
||
private void checkNameIsNotSpecialCharacter(String name) { | ||
if (name.matches(".*[!@#$%^&*()].*")) { | ||
throw new IllegalArgumentException("참여자 이름에 특수문자가 포함될 수 없습니다."); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package model.players; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
public class Players { | ||
private static final int MINIMUM_ALLOWED_LENGTH = 2; | ||
|
||
private final List<Player> players; | ||
|
||
public Players(List<String> playerNames) { | ||
checkPlayersLength(playerNames); | ||
checkPlayersIsNotDuplicate(playerNames); | ||
this.players = generatePlayers(playerNames); | ||
} | ||
|
||
public List<String> getPlayerNames() { | ||
return players.stream() | ||
.map(Player::getName) | ||
.toList(); | ||
} | ||
|
||
public int countOfPlayers() { | ||
return players.size(); | ||
} | ||
|
||
private void checkPlayersLength(List<String> playerNames) { | ||
if (playerNames.size() < MINIMUM_ALLOWED_LENGTH) { | ||
throw new IllegalArgumentException("플레이어는 최소 2명 이상이어야 합니다."); | ||
} | ||
} | ||
|
||
private void checkPlayersIsNotDuplicate(List<String> playerNames) { | ||
if (playerNames.size() != playerNames.stream().distinct().count()) { | ||
throw new IllegalArgumentException("중복된 플레이어가 존재합니다."); | ||
} | ||
} | ||
|
||
private List<Player> generatePlayers(List<String> playerNames) { | ||
return playerNames.stream() | ||
.map(Player::new) | ||
.toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package view; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
public class InputView { | ||
private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); | ||
|
||
public static List<String> readPlayerNames() { | ||
System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); | ||
try { | ||
String input = reader.readLine(); | ||
String removedInput = removeBlank(input); | ||
return split(removedInput); | ||
} catch (IOException e) { | ||
throw new IllegalArgumentException("비정상적인 입력입니다. 다시 입력해주세요."); | ||
} | ||
} | ||
|
||
public static int readHeight() { | ||
System.out.println("최대 사다리 높이는 몇 개인가요?"); | ||
try { | ||
String input = reader.readLine(); | ||
reader.close(); | ||
return Integer.parseInt(input); | ||
} catch (NumberFormatException | IOException e) { | ||
throw new IllegalArgumentException("높이는 숫자로 입력해주세요."); | ||
} | ||
} | ||
|
||
private static String removeBlank(String input) { | ||
return input.replaceAll(" ", ""); | ||
} | ||
|
||
private static List<String> split(String input) { | ||
return Arrays.asList(input.split(",")); | ||
} | ||
} |
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.
구현 기능 목록 작성 👍
다만, "우리가"나 "해야할 일:" 같은 표현은 해당
README
가 기능 명세라기보단 메모에 가까운 느낌을 줄 수 있습니다.