Skip to content
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

[2단계 - 사다리 게임 실행] 허브(방대의) 미션 제출합니다. #234

Merged
merged 71 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
53baf2e
refactor: 사다리높이 입력 예외 메시지가 자세한 내용을 출력하도록 수정
greeng00se Feb 18, 2023
63388cd
refactor: 반환할 때만 불변 리스트로 생성하도록 변경
greeng00se Feb 18, 2023
6f71881
feat: 가로 라인(Line)을 생성하는 정적 팩터리 메서드 추가
greeng00se Feb 18, 2023
e4d47ad
refactor: 가로 라인(Line) 정적 팩터리 메서드 적용
greeng00se Feb 18, 2023
8dd1b1f
feat: 사다리(Ladder)를 생성하는 정적 팩터리 메서드 추가
greeng00se Feb 18, 2023
84d108c
feat: 사다리를 생성하는 정적 팩터리 메서드 적용
greeng00se Feb 18, 2023
190e693
refactor: Players 생성할 때 정적 팩터리 메서드 적용
greeng00se Feb 18, 2023
16c94d5
style: booleanGenerator 매개변수명 변경
greeng00se Feb 18, 2023
c137477
refactor: OutputView 가독성 개선
greeng00se Feb 19, 2023
0e9f359
refactor: LadderGame 정적 팩터리 메서드 적용
greeng00se Feb 20, 2023
cdd3c8f
refactor: 불필요한 코드 제거
greeng00se Feb 20, 2023
f90c14c
docs: 2단계 요구사항 추가
greeng00se Feb 20, 2023
5127aea
refactor: 참가자의 이름에 대한 예외 메시지 수정
greeng00se Feb 20, 2023
3ef389d
feat: 실행 결과(Item)를 표현하는 클래스 추가
greeng00se Feb 20, 2023
6d0605e
feat: Player이 이름 검증시 null check 기능 추가
greeng00se Feb 20, 2023
cf9d52b
feat: Item의 일급 컬렉션 추가
greeng00se Feb 21, 2023
21fde32
feat: 실행결과 입력 기능 추가
greeng00se Feb 21, 2023
48977ba
refactor: final 빠진 부분 추가
greeng00se Feb 21, 2023
4ab0b42
feat: LadderGame Items 필드 추가
greeng00se Feb 21, 2023
a3c6182
feat: 위치를 표현하는 클래스 추가
greeng00se Feb 21, 2023
e293af6
feat: 이름을 표현하는 Name 클래스 추가
greeng00se Feb 21, 2023
112f329
feat: 참가자와 실행결과에 Position 적용
greeng00se Feb 22, 2023
3527a00
feat: 참가자수 상한선 설정
greeng00se Feb 22, 2023
7660742
feat: 이전 위치, 다음 위치를 반환하는 기능 추가
greeng00se Feb 22, 2023
afb96fd
feat: 입력한 값까지의 Position을 반환하는 메서드 추가
greeng00se Feb 22, 2023
8c7c997
feat: 가로라인 한 줄에 대한 사다리 게임을 진행하는 기능 추가
greeng00se Feb 22, 2023
86748d9
feat: 한 위치에 대한 사다리 게임 진행 기능 추가
greeng00se Feb 23, 2023
fd278f6
style: 메서드 위치 변경
greeng00se Feb 23, 2023
7de3d99
feat: 게임 결과를 위한 클래스 추가
greeng00se Feb 23, 2023
4cfd6ee
refactor: Items, Players 저장시 Map을 사용하도록 수정
greeng00se Feb 23, 2023
d5a2024
refactor: 게임 결과의 타입 변경
greeng00se Feb 23, 2023
c50ec09
feat: 예약어는 이름으로 사용하지 못하도록 하는 기능 추가
greeng00se Feb 23, 2023
933e2be
feat: 모든 참가자에 대한 사다리 게임을 진행하는 기능 추가
greeng00se Feb 23, 2023
03e46fa
feat: 사다리의 출력 문자열을 생성하는 클래스 추가
greeng00se Feb 23, 2023
758df5a
feat: 실행결과 출력 기능 추가
greeng00se Feb 23, 2023
e866678
feat: 사다리게임 결과 출력 기능 추가
greeng00se Feb 23, 2023
39e192c
refactor: 문자열 비교 위치 변경
greeng00se Feb 23, 2023
20d6371
style: equals랑 getter 순서 변경
greeng00se Feb 24, 2023
bcc9c07
feat: 사다리 높이 원시값 포장
greeng00se Feb 24, 2023
74e5f71
style: 공백 제거
greeng00se Feb 24, 2023
2dfe990
feat: 사용자의 이름을 원시값 포장
greeng00se Feb 24, 2023
7cf5ae9
refactor: players가 리스트를 사용하도록 수정
greeng00se Feb 24, 2023
7f66159
feat: Item 이름에 대한 원시값 포장 클래스 추가
greeng00se Feb 24, 2023
1682d00
refactor: Item 이름에 대한 원시값 포장 클래스 적용
greeng00se Feb 24, 2023
346bbb0
feat: 입력받은 위치와 같은 위치인지 확인하는 메서드 추가
greeng00se Feb 24, 2023
9fab87d
feat: 참가자가 사다리를 받아 사다리 타기를 진행하는 기능 추가
greeng00se Feb 24, 2023
c492ff5
feat: 모든 참가자가 사다리 타기를 진행하는 기능 추가
greeng00se Feb 24, 2023
aaa3b86
refactor: LadderGameResult의 타입 변경
greeng00se Feb 24, 2023
dd5b2a0
refactor: players에 ladder를 넘겨주는 방법으로 사다리 게임 진행 변경
greeng00se Feb 24, 2023
932fcec
remove: 사용하지 않는 메서드 제거
greeng00se Feb 24, 2023
908ed1a
style: 도메인 패키지 분리
greeng00se Feb 24, 2023
85a8b51
refactor: 사다리 게임 결과 타입 재변경
greeng00se Feb 24, 2023
6457ea7
remove: 사용하지 않는 equals & hashcode 제거
greeng00se Feb 24, 2023
576cdbb
docs: 요구사항 정리
greeng00se Feb 24, 2023
e96ec85
refactor: final 빠진 부분 추가
greeng00se Feb 24, 2023
64db4b6
refactor: Items를 생성하는 정적팩터리 메서드명 of로 변경
greeng00se Feb 25, 2023
3b4c7f4
refactor: OutputView로 객체 바로 전달하도록 수정
greeng00se Feb 25, 2023
46bdddf
refactor: Position의 생성 책임을 Items에서 Item에게 할당
greeng00se Feb 25, 2023
a79b044
refactor: Position의 생성 책임을 Players에서 Player에게 할당
greeng00se Feb 25, 2023
e8918af
refactor: 이름을 확인할 때 getter가 아닌 메시지를 보내도록 수정
greeng00se Feb 25, 2023
b64ae2f
refactor: 깊은 고민없이 패키지 분리한 부분 다시 원래대로 변경
greeng00se Feb 25, 2023
c4565fd
refactor: BooleanGenerator와 구현체 util 패키지로 이동
greeng00se Feb 25, 2023
2f844e6
refactor: 이름에 대한 테스트명 수정
greeng00se Feb 25, 2023
082d975
refactor: 예외 메시지 package-private으로 변경
greeng00se Feb 25, 2023
2aee49b
fix: 결과 확인할 때 존재하지 않는 이름 입력시 종료되는 부분 수정
greeng00se Feb 25, 2023
661cdf6
refactor: 결과를 위한 입력 검증 부분 최적화
greeng00se Feb 25, 2023
3e3c4b9
refactor: 불필요한 this 제거
greeng00se Feb 26, 2023
7e28ac7
refactor: LadderMessageGenerator 인스턴스생성 불가능 하도록 수정
greeng00se Feb 26, 2023
08dc6db
refactor: LadderGameCommand 분리
greeng00se Feb 26, 2023
e0c224a
test: DisplayNameGeneration 빠진 부분 추가
greeng00se Feb 26, 2023
8206c8b
refactor: Position을 사용하는 입장에서 명확하도록 변경
greeng00se Feb 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 50 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,78 @@ graph TD
LadderGameController --> LadderGame
LadderGame --> Ladder
LadderGame --> Players
LadderGame --> Items

Players --> Player
Ladder --> Line
Line --> LineStatus
Line --> Position

Players --> Ladder
Player --> Ladder

Item --> Position
Player --> Position


LadderGame --> LadderGameResult

Items --> Item --> ItemName
Players --> Player --> PlayerName
begaonnuri marked this conversation as resolved.
Show resolved Hide resolved

LadderGameController --> InputView
LadderGameController --> OutputView

Ladder --> Line
Line --> LineStatus
OutputView --> LadderMessageGenerator

```

### 참가자

- [x] 참가자는 이름을 가진다.
- [x] 이름은 1자 이상, 5자 이하의 길이를 가진다.
- [x] 이름이 없거나, 5자를 초과하는 경우 예외를 던진다.
- [x] 이름이 없거나, 5자를 초과하는 경우 예외를 던진다.
- [x] 참가자들의 이름은 중복될 수 없다.
- [x] 중복된 이름이 존재하는 경우 예외를 던진다.
- [x] 참가자는 최소 2명 이어야 한다.
- [x] 참가자가 1명 이하인 경우 예외를 던진다.
- [x] 참가자들의 이름은 중복될 수 없다.
- [x] 중복된 이름이 존재하는 경우 예외를 던진다.
- [x] 참가자는 최대 20명 이어야 한다.
- [x] 참가자가 20명을 초과하는 경우 예외를 던진다.
- [x] 참가자는 위치를 가진다.
- [x] 위치 값은 0부터 시작한다.

### 아이템(실행결과)

- [x] 아이템은 이름을 가진다.
- [x] 이름 길이는 참가자의 이름과 동일하게 1자 이상, 5자 이하의 길이를 가진다.
- [x] 아이템은 참가인원과 동일한 개수가 있어야 한다.
- [x] 아이템은 위치를 가진다.
- [x] 위치 값은 0부터 시작한다.

### 사다리
### 사다리 게임

- [x] 사다리는 높이를 가진다.
- [x] 사다리 가로 라인을 가진다.
- [x] 사다리 가로 라인의 상태가 연속으로 `연결됨` 상태일 수 없다.
- [x] 각각의 가로 라인은 상태를 가진다.
- [x] 연결됨, 연결되지 않음으로 구분된다.
- [x] 높이는 1이상, 100이하의 값이어야 한다.
- [x] 사다리의 높이만큼 가로 라인을 가진다.
begaonnuri marked this conversation as resolved.
Show resolved Hide resolved
- [x] 각각의 가로 라인은 `사다리 게임 참가자 - 1` 너비만큼의 연결 상태를 가진다.
- [x] `사다리 게임 참가자 - 1` 만큼의 위치값을 가지고 각 위치에 연결상태가 존재한다.
- [x] 연결 상태는 연결됨, 연결되지 않음으로 구분된다.
- [x] 가로 라인의 연결 상태가 연속으로 `연결됨` 일 수 없다.
- [x] 사다리 게임을 진행한다.
- [x] 모든 참가자에 대한 결과를 반환한다.

### 입력

- [x] 사람 이름은 쉼표(,)를 기준으로 구분하여 입력받는다.
- [x] 이름의 앞뒤 공백을 제거한다.
- [x] 참가자 이름은 쉼표(,)를 기준으로 구분하여 입력받는다.
- [x] 이름의 앞뒤 공백을 제거한다.
- [x] 결과명은 쉼표(,)를 기준으로 구분하여 입력받는다.
- [x] 결과명의 앞뒤 공백을 제거한다.
- [x] 최대 사다리 높이를 입력받는다.
- [x] 1보다 작은 값을 입력하는 경우 예외를 던진다.
- [x] 1보다 작은 값을 입력 받거나, 100보다 큰 값을 입력받는 경우 예외를 던진다.
- [x] 실행결과를 보고 싶은 참가자명을 입력받는다.

### 출력

- [x] 최대 사람이름을 기준으로 사다리 폭이 넓어진다.
- [x] 가장 긴 사람 이름을 기준으로 사다리 폭이 넓어진다. 예) 가장 긴 사람이름 5, 사다리 폭 5
- [x] 실행 결과를 이용하여 해당 참가자에 대한 결과를 출력한다.


20 changes: 4 additions & 16 deletions src/main/java/ladder/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.Scanner;
import ladder.controller.LadderGameController;
import ladder.domain.RandomBooleanGenerator;
import ladder.util.RandomBooleanGenerator;
import ladder.view.InputView;
import ladder.view.OutputView;

Expand All @@ -11,23 +11,11 @@ public class Application {
public static void main(String[] args) {
try (Scanner scanner = new Scanner(System.in)) {
begaonnuri marked this conversation as resolved.
Show resolved Hide resolved
final LadderGameController ladderGameController = new LadderGameController(
booleanGenerator(),
inputView(scanner),
outputView()
new RandomBooleanGenerator(),
new InputView(scanner),
new OutputView()
begaonnuri marked this conversation as resolved.
Show resolved Hide resolved
);
ladderGameController.run();
}
}

private static RandomBooleanGenerator booleanGenerator() {
return new RandomBooleanGenerator();
}

private static OutputView outputView() {
return new OutputView();
}

private static InputView inputView(final Scanner scanner) {
return new InputView(scanner);
}
}
67 changes: 46 additions & 21 deletions src/main/java/ladder/controller/LadderGameController.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ladder.controller;

import java.util.List;
import ladder.domain.BooleanGenerator;
import java.util.function.Supplier;
import ladder.domain.Height;
import ladder.domain.Items;
import ladder.domain.LadderGame;
import ladder.domain.Line;
import ladder.domain.LadderGameResult;
import ladder.domain.Players;
import ladder.util.BooleanGenerator;
import ladder.view.InputView;
import ladder.view.OutputView;

Expand All @@ -26,35 +28,58 @@ public LadderGameController(

public void run() {
final LadderGame ladderGame = initialize();
final List<String> players = ladderGame.getPlayers();
final List<Line> ladder = ladderGame.getLadder();

outputView.printResult(players, ladder);
outputView.printLadderResult(ladderGame);
final LadderGameResult ladderGameResult = ladderGame.play();
printLadderGameResult(ladderGameResult);
}

private LadderGame initialize() {
final Players players = readPlayers();
final int height = readHeight();

return new LadderGame(booleanGenerator, players, height);
final Players players = repeatUntilGetValidInput(() -> Players.from(inputView.readPlayerNames()));
final Items items = repeatUntilGetValidInput(() -> Items.of(inputView.readItemNames(), players.count()));
final Height height = repeatUntilGetValidInput(() -> new Height(inputView.readLadderHeight()));

return LadderGame.initialize(players, booleanGenerator, height, items);
}

private Players readPlayers() {
private <T> T repeatUntilGetValidInput(final Supplier<T> inputReader) {
try {
final List<String> names = inputView.readPlayerNames();
return new Players(names);
return inputReader.get();
} catch (IllegalArgumentException e) {
outputView.printError(e.getMessage());
return readPlayers();
return repeatUntilGetValidInput(inputReader);
}
}

private int readHeight() {
try {
return inputView.readLadderHeight();
} catch (IllegalArgumentException e) {
outputView.printError(e.getMessage());
return readHeight();
private void printLadderGameResult(final LadderGameResult ladderGameResult) {
LadderGameCommand command = LadderGameCommand.SINGLE;
while (command.isContinued()) {
final String name = repeatUntilGetValidInput(() -> getValidPlayerName(ladderGameResult));
command = LadderGameCommand.from(name);
outputView.printLadderGameResult(ladderGameResult, name);
}
}

private String getValidPlayerName(final LadderGameResult ladderGameResult) {
final String name = inputView.readPlayerName();
ladderGameResult.validatePlayerName(name);
return name;
}

private enum LadderGameCommand {
MULTIPLE,
SINGLE;

private static final String MULTIPLE_RESULT_RESERVED_NAME = "all";

public static LadderGameCommand from(final String name) {
if (MULTIPLE_RESULT_RESERVED_NAME.equals(name)) {
return MULTIPLE;
}
return SINGLE;
}

public boolean isContinued() {
return this == SINGLE;
}
}
}
41 changes: 41 additions & 0 deletions src/main/java/ladder/domain/Height.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ladder.domain;

public class Height {
private static final int HEIGHT_LOWER_BOUND = 1;
private static final int HEIGHT_UPPER_BOUND = 100;
static final String INVALID_HEIGHT_MESSAGE =
"높이는 " + HEIGHT_LOWER_BOUND + "이상, " + HEIGHT_UPPER_BOUND + "이하의 값이어야 합니다.";

private final int value;

public Height(final String value) {
this(parseInt(value));
}

private Height(final int value) {
validate(value);
this.value = value;
}

private static int parseInt(final String value) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(INVALID_HEIGHT_MESSAGE);
}
}

private static void validate(final int value) {
if (isInvalidHeight(value)) {
throw new IllegalArgumentException(INVALID_HEIGHT_MESSAGE);
}
}

private static boolean isInvalidHeight(final int value) {
return value < HEIGHT_LOWER_BOUND || HEIGHT_UPPER_BOUND < value;
}

public int getValue() {
return value;
}
}
23 changes: 23 additions & 0 deletions src/main/java/ladder/domain/Item.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ladder.domain;

public class Item {
private final ItemName name;
private final Position position;

private Item(final ItemName name, final Position position) {
this.name = name;
this.position = position;
}

public static Item of(final String name, final int index) {
return new Item(new ItemName(name), Position.valueOf(index));
}

public boolean isSamePosition(final Position position) {
return this.position == position;
}

public String getName() {
return name.getValue();
}
}
28 changes: 28 additions & 0 deletions src/main/java/ladder/domain/ItemName.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ladder.domain;

public class ItemName {
private static final int NAME_LENGTH_UPPER_BOUND = 5;
static final String INVALID_NAME_LENGTH_MESSAGE =
"실행 결과명은 1자 이상, " + NAME_LENGTH_UPPER_BOUND + "자 이하여야 합니다.";

private final String value;

public ItemName(final String name) {
validate(name);
this.value = name;
}

private void validate(final String name) {
if (isInvalidNameLength(name)) {
throw new IllegalArgumentException(INVALID_NAME_LENGTH_MESSAGE);
}
}

private boolean isInvalidNameLength(final String name) {
return name == null || name.isBlank() || NAME_LENGTH_UPPER_BOUND < name.length();
}

public String getValue() {
return value;
}
}
44 changes: 44 additions & 0 deletions src/main/java/ladder/domain/Items.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ladder.domain;

import static java.util.stream.Collectors.toUnmodifiableList;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Items {
static final String INVALID_ITEM_COUNT_MESSAGE = "참가인원과 동일한 개수의 실행결과를 입력해야 합니다.";
static final String INVALID_ITEM_MESSAGE = "해당 위치에 있는 아이템이 존재하지 않습니다.";

private final List<Item> items;

private Items(final List<Item> items) {
this.items = items;
}

public static Items of(final List<String> names, int playerCount) {
validateItemCount(names, playerCount);
return IntStream.range(0, names.size())
.mapToObj(index -> Item.of(names.get(index), index))
.collect(Collectors.collectingAndThen(Collectors.toList(), Items::new));
}

private static void validateItemCount(final List<String> items, final int playerCount) {
if (items.size() != playerCount) {
throw new IllegalArgumentException(INVALID_ITEM_COUNT_MESSAGE);
}
}

public Item findByPosition(final Position position) {
return items.stream()
.filter(item -> item.isSamePosition(position))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException(INVALID_ITEM_MESSAGE));
}

public List<String> getNames() {
return items.stream()
.map(Item::getName)
.collect(toUnmodifiableList());
}
}
Loading