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

[사다리 타기] 김나윤 미션 제출합니다. #11

Open
wants to merge 20 commits into
base: bbggr1209
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ out/

### VS Code ###
.vscode/

### DS_Store ###
*.DS_Store
46 changes: 46 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## 구현할 기능 목록

- [x] 플레이어 이름 입력
- [x] 이름을 입력 받을 메세지 출력
- [x] 이름을 입력 받음
- [x] 이름을 쉼표(,)를 기준으로 분리
- [x] 이름의 유효성 검사
- [x] 이름이 5글자 이하여야 한다.
- [x] 이름에는 공백이 들어갈 수 없다.
- [x] 이름이 중복되어서는 안된다.

- [x] 사다리 높이 입력
- [x] 사다리 높이 입력 메세지 출력
- [x] 사다리 높이 입력 받음
- [x] 사다리 높이의 유효성 검사
- [x] 사다리 높이는 1 이상이어야 한다.
- [x] 사다리 높이는 0~9 사이의 숫자여야 한다.

- [x] 결과 출력
- [x] 플레이어 이름 출력
- [x] 사다리 출력

---

## 필요한 객체

### Player
- 이름을 입력받고 유효성 검사를 수행하는 객체

### Players
- Player 객체를 관리하는 객체

### Line
- 사다리의 선을 관리하는 객체

### Point
- 선의 시작점과 끝점을 관리하는 객체

### Line Generator
- Line을 랜덤으로 생성하는 객체

### Ladder
- 여러 개의 선 객체를 관리하는 객체

### 입출력
- 입력을 받고 출력하는 객체
Comment on lines +1 to +46

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

구현 기능 목록 작성 👍

Empty file removed src/main/java/.gitkeep
Empty file.
8 changes: 8 additions & 0 deletions src/main/java/LadderGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import controller.LadderGameController;

public class LadderGame {
public static void main(String[] args) {
LadderGameController ladderGameController = new LadderGameController();
ladderGameController.run();
}
}
26 changes: 26 additions & 0 deletions src/main/java/controller/LadderGameController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package controller;

import model.Ladder;
import model.Players;
import view.InputView;
import view.ResultView;

public class LadderGameController {

public void run() {
Players players = initPlayer();
int playerCount = players.getPlayerCount();
int height = InputView.getLadderHeight();
Ladder ladder = initLadder(playerCount, height);
ResultView.printLadder(ladder.getLines(), players.getPlayerNames());
}

private Players initPlayer() {
return new Players(InputView.getPlayerNames());
}

private Ladder initLadder(int playerCount, int height) {
return new Ladder(playerCount, height);
}

}
22 changes: 22 additions & 0 deletions src/main/java/model/Ladder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package model;

import java.util.ArrayList;
import java.util.List;
import util.LineGenerator;

public class Ladder {

private final List<Line> lines;

public Ladder(int numberOfPlayers, int height) {
lines = new ArrayList<>();
for (int i = 0; i < height; i++) {
lines.add(LineGenerator.generateLine(numberOfPlayers));
}
}

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

}
Comment on lines +7 to +22

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

일급 컬렉션 활용 👍

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

import java.util.List;

public class Line {

private List<Point> points;

public Line(List<Point> points) {
this.points = points;
}

public List<Point> getPoints() {
return points;
}

}
37 changes: 37 additions & 0 deletions src/main/java/model/Player.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package model;

public class Player {
private final static int MAX_NAME_LENGTH = 5;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Java Language Specification에 따르면 private static final이 더 올바른 순서입니다!


private final String name;

public Player(String name) {
validateNameNull(name);
validateNameEmpty(name);
validateNameLength(name);
this.name = name;
}

public String getName() {
return name;
}

public void validateNameNull(String name) {
if (name == null) {
throw new IllegalArgumentException("이름은 null이 될 수 없습니다.");
}
}

public void validateNameEmpty(String name) {
if (name.isEmpty()) {
throw new IllegalArgumentException("이름은 빈 문자열이 될 수 없습니다.");
}
}

public void validateNameLength(String name) {
if (name.length() > MAX_NAME_LENGTH) {
throw new IllegalArgumentException("이름 길이를 초과할 수 없습니다.");
}
}

}
45 changes: 45 additions & 0 deletions src/main/java/model/Players.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package model;

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

public class Players {
private static final int MINIMUM_PLAYER_COUNT = 2;

private final List<Player> players;

public Players(List<String> playerNames) {
validatePlayerCount(playerNames);
validateDuplicatePlayerName(playerNames);
this.players = generatePlayers(playerNames);
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toList()만 사용해도 List 전환 가능합니다!

}

public int getPlayerCount() {
return players.size();
}

public void validatePlayerCount(List<String> playerNames) {
if (playerNames.size() < MINIMUM_PLAYER_COUNT) {
throw new IllegalArgumentException("플레이어는 2명 이상이어야 합니다.");
}
}

public void validateDuplicatePlayerName(List<String> playerNames) {
if (playerNames.size() != playerNames.stream().distinct().count()) {
throw new IllegalArgumentException("중복된 이름이 존재합니다.");
}
}

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

}
15 changes: 15 additions & 0 deletions src/main/java/model/Point.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package model;

public class Point {

private final boolean hasLine;

public Point(boolean hasLine) {
this.hasLine = hasLine;
}

public boolean hasLine() {
return hasLine;
}

}
44 changes: 44 additions & 0 deletions src/main/java/util/LineGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package util;

import model.Line;
import model.Point;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class LineGenerator {

private static boolean previous = false;
private static Random random = new Random();

public static Line generateLine(int numberOfPlayers) {
List<Point> points = new ArrayList<>();
for (int i = 0; i < numberOfPlayers - 1; i++) {
boolean next = random.nextBoolean() && !previous;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

부정 연산자 !은 가독성을 해친다는 의견이 있습니다.

조건문으로 리팩토링 하거나 다른 방법이 있다면 해당 방법으로 구현하는 편이 나을 수 있습니다.
다만, 현재 코드는 그렇게까지 가독성을 해치진 않는 것 같습니다. 참고만 해주시고, 리팩토링은 나윤의 선택입니다!

points.add(new Point(next));
previous = next;
}
return new Line(points);
}

public static List<Point> createPointsForLine(int numberOfPoints) {
List<Point> points = new ArrayList<>();
for (int i = 0; i < numberOfPoints; i++) {
boolean current = random.nextDouble() > 0.5 && !previous;
points.add(new Point(current));
previous = current;
}
return points;
}

public static boolean hasSerialTrue(List<Point> points) {
for (int i = 0; i < points.size() - 1; i++) {
if (points.get(i).hasLine() && points.get(i + 1).hasLine()) {
return true;
}
}
return false;
}
bbggr1209 marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +35 to +42

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요구 사항에도 적혀있지만 이번 미션에서 메소드 indent(들여쓰기)는 1단계까지만 허용하고 있습니다.
메소드 분리, stream 활용 등으로 해당 메소드의 들여쓰기 단계를 줄여주세요!


}
49 changes: 49 additions & 0 deletions src/main/java/view/InputView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package view;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

public class InputView {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 클래스는 Util 클래스로 보입니다.
모든 메소드가 static이기 때문에 private 기본 생성자가 필요합니다. (인스턴스화가 필요 없습니다!)

이 클래스 뿐만 아니라 모든 메소드가 static이라면 private 기본 생성자를 기본으로 생성해주세요.
추가로, SonarLint라는 IntelliJ 플러그인을 활용하면 이런 수정 사항을 미리 알려줍니다!

private static final String HEIGHT_INPUT_REGEX = "[0-9]+";

private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

public static List<String> getPlayerNames() {
System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)");
try {
String input = reader.readLine();
return List.of(input.split(","));
} catch (IOException e) {
throw new IllegalArgumentException("잘못된 입력입니다.");
}
}

private static boolean isNotValidLadderHeight(String input) {
return !input.matches(HEIGHT_INPUT_REGEX);
}

private static boolean isNotValidLadderHeightRange(int height) {
return height < 1;
}

public static int getLadderHeight() {
System.out.println("최대 사다리 높이는 몇 개인가요?");
try {
String input = reader.readLine();

if (isNotValidLadderHeight(input)) {
throw new IllegalArgumentException("사다리 높이는 숫자여야 합니다.");
}
if (isNotValidLadderHeightRange(Integer.parseInt(input))) {
throw new IllegalArgumentException("사다리 높이는 1 이상이어야 합니다.");
}
Comment on lines +36 to +41

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 로직 자체를 해당 메소드들에게 넘겨줘도 무방하지 않을까요?
메소드가 스스로 값에 대해 판단하고, 예외를 던져도 충분히 같은 동작을 할 수 있을 것 같습니다.

indent 단계까지 덤으로 낮출 수 있겠죠 😁


return Integer.parseInt(input);
} catch (IOException e) {
throw new IllegalArgumentException("잘못된 입력입니다.");
}
}

}
46 changes: 46 additions & 0 deletions src/main/java/view/ResultView.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package view;

import java.util.List;
import model.Line;
import model.Point;

public class ResultView {

private static final int NAME_WIDTH = 6;

public static void printLadder(List<Line> ladder, List<String> playerNames) {
System.out.println("실행 결과");
printPlayerNames(playerNames);
for (Line line : ladder) {
printLine(line);
}
}
Comment on lines +11 to +17

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ladder라는 일급 컬렉션을 구현했음에도 List<Line>으로 매개변수를 전달한 이유가 있을까요?
또한, View에 직접 Domain을 전달했을 때는 어떤 문제가 일어날 수 있나요?


private static void printPlayerNames(List<String> playerNames) {
for (String playerName : playerNames) {
System.out.printf("%-" + NAME_WIDTH + "s", playerName);
}
System.out.println();
}

private static void printLine(Line line) {
List<Point> points = line.getPoints();
for (Point point : points) {
if (point.hasLine()) {
drawLine();
} else {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else는 이전 미션들에서도 사용을 지양했었습니다!
앞으로는 Java에 else는 없다고 생각하고 코드를 작성해봅시다!

drawEmptyLine();
}
}
System.out.println("|");
}

private static void drawLine() {
System.out.print("|-----");
}

private static void drawEmptyLine() {
System.out.print("| ");
}

}
Empty file removed src/test/java/.gitkeep
Empty file.
Loading