Skip to content

Commit

Permalink
[1단계 사다리 생성] 다즐(최우창) 미션 제출합니다. (#70)
Browse files Browse the repository at this point in the history
* docs: 기능 목록 작성

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 사람 이름 영문자 검증 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 사람 이름 길이 검증 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* docs: 요구사항 명세서 수정

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 플레이어 이름 앞, 뒤 공백 제거 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 플레이어 수 검증 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 플레이어 이름 중복 검증 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* chore: TDD 이후 클래스 위치 이동

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 특정 이동값을 가지는 방향 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 발판을 위한 숫자 생성 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 값에 알맞은 방향 반환 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 방향 생성 전략 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 방향들의 집합인 선 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 선 생성 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 사다리 생성 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 플레이어들의 이름 입력 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 최대 사다리 높이 입력 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 사다리 생성 결과 출력 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 높이 검증 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* refactor: 플레이어 이름 역할 분리

Co-authored-by: 70825 <hello70825@gmail.com>

* feat: 사다리 애플리케이션 기능 구현

Co-authored-by: 70825 <hello70825@gmail.com>

* refactor: 상수 추가 및 네이밍 수정

Co-authored-by: 70825 <hello70825@gmail.com>

* refactor: 사다리 높이 역할 분리에 따른 리팩토링

Co-authored-by: 70825 <hello70825@gmail.com>

* refactor: 네이밍 수정 및 불필요한 파라미터와 메서드 삭제

Co-authored-by: 70825 <hello70825@gmail.com>

* refactor: 메서드 결합도와 복잡성을 높이는 메서드 전달자 제거

* refactor: 의미가 모호한 메서드명, 시그니처 수정

* refactor: 사다리 생성 역할 분리

* refactor: for -> while 사용하도록 수정

* refactor: 한번만 사용되는 예외 메시지인 경우 상수화 하지 않는 것으로 수정

* refactor: 공백이 포함되면 유효하지 않은 이름으로 처리하도록 수정

* refactor: format 비용을 고려하여 string 연산을 사용하도록 수정

* refactor: 의미있는 추상화를 위한 메서드명 수정

* refactor: 생성자에서 의존성 주입이 아닌 메서드에서 의존성 주입하도록 수정

* refactor: 라인 생성 메소드 재귀 -> while 방법으로 수정

* refactor: 발판에 대한 책임은 Direction이 가지도록 수정

* refactor: 출력 요구사항에 맞게 개행 추가

---------

Co-authored-by: 70825 <hello70825@gmail.com>
  • Loading branch information
woo-chang and 70825 committed Feb 20, 2023
1 parent b4f2a8d commit 4d93483
Show file tree
Hide file tree
Showing 23 changed files with 840 additions and 0 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,49 @@
## 우아한테크코스 코드리뷰

- [온라인 코드 리뷰 과정](https://github.com/woowacourse/woowacourse-docs/blob/master/maincourse/README.md)

## 개요

해당 저장소는 사다리 생성을 구현한 저장소입니다. `n`명의 사람 이름과 높이 `m`을 입력하면 사다리가 생성됩니다.

## 세부사항

플레이어

- 플레이어는 여러 명 존재할 수 있다.
- [x] [제한사항] 플레이어는 2명 이상, 10명 이하만 가능하다.
- [x] [제한사항] 플레이어의 이름은 중복될 수 없다.
- 플레이어는 이름을 가집니다.
- [x] [제한사항] 이름은 영문자만 가능하다.
- [x] [제한사항] 이름은 최대 5글자까지 가능하다.

방향

- [x] 왼쪽, 오른쪽, 정지를 가진다.
- [x] 값에 알맞은 방향을 반환한다.


- [x] 방향들의 집합이다.

사다리

- [x] 선들의 집합이다.
- [x] 높이는 2이상, 10이하만 가능합니다.

방향 생성

- [x] 랜덤 방향을 생성한다.

선 생성

- [x] 방향 생성 전략에 따라 선을 생성한다.

입력

- [x] 참여할 플레이어들의 이름을 입력한다.
- [x] 최대 사다리 높이를 입력한다.

출력

- [x] 사다리 생성 결과를 출력한다.
19 changes: 19 additions & 0 deletions src/main/java/ladder/LadderApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package ladder;

import java.util.Scanner;
import ladder.controller.LadderController;
import ladder.domain.generator.LadderGenerator;
import ladder.view.InputView;
import ladder.view.OutputView;

public class LadderApplication {

public static void main(String[] args) {
final var inputView = new InputView(new Scanner(System.in));
final var outputView = new OutputView();
final var ladderGenerator = new LadderGenerator();

LadderController ladderController = new LadderController(inputView, outputView, ladderGenerator);
ladderController.run();
}
}
41 changes: 41 additions & 0 deletions src/main/java/ladder/controller/LadderController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package ladder.controller;

import java.util.function.Function;
import java.util.function.Supplier;
import ladder.domain.Height;
import ladder.domain.Ladder;
import ladder.domain.Players;
import ladder.domain.generator.LadderGenerator;
import ladder.domain.generator.LineGenerator;
import ladder.view.InputView;
import ladder.view.OutputView;

public class LadderController {

private final InputView inputView;
private final OutputView outputView;
private final LadderGenerator ladderGenerator;

public LadderController(final InputView inputView, final OutputView outputView,
final LadderGenerator ladderGenerator) {
this.inputView = inputView;
this.outputView = outputView;
this.ladderGenerator = ladderGenerator;
}

public void run() {
final Players players = generate(inputView::readPlayerNames, Players::new);
final Height height = generate(inputView::readHeight, Height::new);
final Ladder ladder = ladderGenerator.generate(new LineGenerator(), players, height);
outputView.printLadderResult(players, ladder);
}

private <T, R> R generate(final Supplier<T> supplier, final Function<T, R> function) {
try {
return function.apply(supplier.get());
} catch (IllegalArgumentException e) {
outputView.printErrorMessage(e.getMessage());
return generate(supplier, function);
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/ladder/domain/Direction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ladder.domain;

import java.util.Arrays;

public enum Direction {

LEFT(-1, "-----"),
STAY(0, " "),
RIGHT(1, " "),
;

private final int move;
private final String foothold;

Direction(final int move, final String foothold) {
this.move = move;
this.foothold = foothold;
}

public static Direction from(final int value) {
return Arrays.stream(Direction.values())
.filter(direction -> direction.getMove() == value)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("유효하지 않은 값입니다."));
}

public int getMove() {
return move;
}

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

public class Height {

private static final int MINIMUM_HEIGHT = 2;
private static final int MAXIMUM_HEIGHT = 10;

private final int value;

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

private void validate(final int value) {
if (hasShort(value) || hasLong(value)) {
throw new IllegalArgumentException("높이는 " + MINIMUM_HEIGHT + "이상, " + MAXIMUM_HEIGHT + "이하여야 합니다."
+ " 현재 높이는 " + value + "입니다.");
}
}

private boolean hasShort(final int value) {
return value < MINIMUM_HEIGHT;
}

private boolean hasLong(final int value) {
return MAXIMUM_HEIGHT < value;
}

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

import java.util.Collections;
import java.util.List;

public class Ladder {

private final List<Line> lines;

public Ladder(final List<Line> lines) {
this.lines = lines;
}

public List<Line> getLines() {
return Collections.unmodifiableList(lines);
}
}

16 changes: 16 additions & 0 deletions src/main/java/ladder/domain/Line.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ladder.domain;

import java.util.List;

public class Line {

private final List<Direction> directions;

public Line(final List<Direction> directions) {
this.directions = directions;
}

public List<Direction> getDirections() {
return directions;
}
}
63 changes: 63 additions & 0 deletions src/main/java/ladder/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ladder.domain;

import java.util.Objects;
import java.util.regex.Pattern;

public class Name {

private static final Pattern NAME_FORMAT = Pattern.compile("[a-zA-Z]+");
private static final int NAME_MAX_LENGTH = 5;

private final String value;

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

private void validate(final String value) {
validateFormat(value);
validateLength(value);
}

private void validateFormat(final String value) {
if (isNotEnglish(value)) {
throw new IllegalArgumentException("사람 이름은 영문자만 가능합니다. 현재 입력은 " + value + " 입니다.");
}
}

private boolean isNotEnglish(final String value) {
return !NAME_FORMAT.matcher(value).matches();
}

private void validateLength(final String value) {
if (hasExceedLength(value)) {
throw new IllegalArgumentException("사람 이름은 " + NAME_MAX_LENGTH + "글자까지 가능합니다. 현재 입력은 " + value + " 입니다.");
}
}

private boolean hasExceedLength(final String value) {
return NAME_MAX_LENGTH < value.length();
}

public String getValue() {
return value;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Name name = (Name) o;
return Objects.equals(getValue(), name.getValue());
}

@Override
public int hashCode() {
return Objects.hash(getValue());
}
}
33 changes: 33 additions & 0 deletions src/main/java/ladder/domain/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ladder.domain;

import java.util.Objects;

public class Player {

private final Name name;

public Player(final String value) {
this.name = new Name(value);
}

public String getName() {
return name.getValue();
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final Player player = (Player) o;
return Objects.equals(name, player.name);
}

@Override
public int hashCode() {
return Objects.hash(name);
}
}
69 changes: 69 additions & 0 deletions src/main/java/ladder/domain/Players.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package ladder.domain;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class Players {

private static final int MINIMUM_PLAYER_SIZE = 2;
private static final int MAXIMUM_PLAYER_SIZE = 10;

private final List<Player> players;

public Players(final List<String> names) {
final List<Player> players = generatePlayers(names);
validate(players);
this.players = players;
}

private List<Player> generatePlayers(final List<String> names) {
return names.stream()
.map(Player::new)
.collect(Collectors.toList());
}

private void validate(final List<Player> players) {
validatePlayerSize(players);
validateDuplicatePlayer(players);
}

private void validatePlayerSize(final List<Player> players) {
if (hasSmallSize(players) || hasLargeSize(players)) {
throw new IllegalArgumentException(
"플레이어는 " + MINIMUM_PLAYER_SIZE + "명 이상, " + MAXIMUM_PLAYER_SIZE + "명 이하만 가능합니다."
+ " 현재 입력한 플레이어 수는 " + players.size() + "명 입니다.");
}
}

private boolean hasSmallSize(final List<Player> players) {
return players.size() < MINIMUM_PLAYER_SIZE;
}

private boolean hasLargeSize(final List<Player> players) {
return MAXIMUM_PLAYER_SIZE < players.size();
}

private void validateDuplicatePlayer(final List<Player> players) {
final Set<Player> uniquePlayers = new HashSet<>(players);

if (isDuplicate(players, uniquePlayers)) {
throw new IllegalArgumentException("플레이어 이름은 중복되면 안됩니다.");
}
}

private boolean isDuplicate(final List<Player> players, final Set<Player> uniquePlayers) {
return players.size() != uniquePlayers.size();
}

public List<String> getPlayerNames() {
return players.stream()
.map(Player::getName)
.collect(Collectors.toUnmodifiableList());
}

public int size() {
return players.size();
}
}
9 changes: 9 additions & 0 deletions src/main/java/ladder/domain/generator/DirectionGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ladder.domain.generator;

import ladder.domain.Direction;

@FunctionalInterface
public interface DirectionGenerator {

Direction generate();
}
Loading

0 comments on commit 4d93483

Please sign in to comment.