Skip to content

[송지은] 사다리타기 제출합니다. #38

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

Open
wants to merge 5 commits into
base: hafnium1923
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
31 changes: 31 additions & 0 deletions src/main/java/controller/LadderController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package controller;

import domain.Ladder;
import domain.LadderGame;
import domain.LadderHeight;
import domain.LadderWidth;
import domain.Players;
import domain.Prizes;
import domain.GameResult;
import view.InputView;
import view.OutputView;

public class LadderController {
public static void main(String[] args) {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
Players players = inputView.askPlayers();
Prizes prizes = inputView.askPrizes();
LadderHeight height = inputView.askHeight();
LadderWidth width = new LadderWidth(players.size());
LadderGame ladderGame = new LadderGame(players, prizes, new Ladder(height, width));
outputView.printLadderGameBoard(ladderGame);
GameResult gameResult = ladderGame.play();
String query = inputView.askResultName();
if (query.equals("all")) {
outputView.printResultAll(gameResult);
return;
}
outputView.printResultSingle(gameResult.getResultByPlayerName(query).getPrize());
}
}
Comment on lines +13 to +31

Choose a reason for hiding this comment

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

  1. 전반적으로 덩치가 꽤 큰 Controller라는 생각이 들었는데, 관심사나 상황별로 분리해 보시는 것은 어떨까요?
  2. 사용자가 잘못된 값을 입력한 경우 다시 입력받게 하는 것까지는 선택사항으로 볼 수 있어보이지만, 적어도 예외가 발생했을 경우 사용자에게 전용 예외 메시지를 보여주고 종료하면 좋을 것 같다는 생각도 들었는데, 어떻게 생각하세요?
  3. 사용자가 잘못된 값을 입력한 타이밍과 예외가 발생하는 시점의 타이밍도 서로 다른 것 같아요! 입력받는 시점과 컬렉션을 선언하는 타이밍이 다를 경우에 생길 수 있는 문제로 보이는데, 이건 어떻게 해결해 볼 수 있을까요? 저도 자주 고민하는 토픽이네요
    image

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

public enum Bridge {
CONNECTED,
NOT_CONNECTED;

public String display() {
if (this == CONNECTED) {
return "-----";
}
return " ";
}

public static Bridge fromBoolean(boolean connected) {
if (connected) {
return CONNECTED;
}
return NOT_CONNECTED;
}
}
24 changes: 24 additions & 0 deletions src/main/java/domain/GameResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package domain;

import java.util.List;

public class GameResult {
private final List<Result> results;

public GameResult(List<Result> results) {
this.results = results;
}

public List<Result> getResults() {
return results;
}

public Result getResultByPlayerName(String name) {
for (Result result : results) {
if (result.getPlayerName().equals(name)) {
return result;
}
}
throw new IllegalArgumentException("해당 이름이 없습니다.");
}
}
36 changes: 36 additions & 0 deletions src/main/java/domain/Ladder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package domain;

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

public class Ladder {
private final Lines lines;

public Ladder(LadderHeight height, LadderWidth width) {
this.lines = new Lines(createLines(height, width));
}

private List<Line> createLines(LadderHeight height, LadderWidth width) {
List<Line> list = new ArrayList<>();
Line previousLine = null;
for (int i = 0; i < height.getValue(); i++) {
Line current = new Line(width, previousLine);
list.add(current);
previousLine = current;
}
return list;
}

public List<String> getLadderBody() {
return lines.drawAll();
}

public LadderResult play() {
int columnCount = lines.getColumnCount();
List<Position> positions = new ArrayList<>();
for (int i = 0; i < columnCount; i++) {
positions.add(lines.moveAll(new Position(i)));
}
return new LadderResult(positions);
}
}
43 changes: 43 additions & 0 deletions src/main/java/domain/LadderGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package domain;

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

public class LadderGame {
private final Players players;
private final Prizes prizes;
private final Ladder ladder;

public LadderGame(Players players, Prizes prizes, Ladder ladder) {
if (players.size() != prizes.getPrizes().size()) {
throw new IllegalArgumentException("참여자 수와 결과 수가 일치해야 합니다.");
}
this.players = players;
this.prizes = prizes;
this.ladder = ladder;
}

public GameResult play() {
LadderResult ladderResult = ladder.play();
List<Result> results = new ArrayList<>();
for (int i = 0; i < players.size(); i++) {
int finalIndex = ladderResult.getPositions().get(i).getValue();
String playerName = players.getPlayers().get(i).getName().getValue();
String prize = prizes.getPrizeAt(finalIndex).getValue();
results.add(new Result(playerName, prize));
}
return new GameResult(results);
}

public Ladder getLadder() {
return ladder;
}

public Players getPlayers() {
return players;
}

public Prizes getPrizes() {
return prizes;
}
}
16 changes: 16 additions & 0 deletions src/main/java/domain/LadderHeight.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package domain;

public class LadderHeight {
private final int value;

public LadderHeight(int value) {
if (value < 1) {
throw new IllegalArgumentException("사다리의 높이는 1 이상이어야 합니다.");
}
this.value = value;
}

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

import java.util.List;

public class LadderResult {
private final List<Position> positions;

public LadderResult(List<Position> positions) {
this.positions = positions;

Choose a reason for hiding this comment

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

별도의 보호 조치 없이 얕은 복사가 일어날 만한 부분의 코드처럼 보여요! LadderResult의 인스턴스를 만들기 위해 positions를 주입해주었는데 이후 외부에서 positions가 바뀔 경우 이 인스턴스 내의 positions 또한 바뀌는 현상은 아마도 원치 않으실 것 같아요.

ArrayList<>()의 인자로 넣는 방법 또는 List.of() 등을 활용해 방어적 복사 가 되도록 개선해 보시는 것에 대해서는 어떻게 생각하세요? 마침 블로그도 루루가 아는 사람의 블로그입니다 😈

}

public List<Position> getPositions() {
return positions;
}
}
16 changes: 16 additions & 0 deletions src/main/java/domain/LadderWidth.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package domain;

public class LadderWidth {
private final int value;

public LadderWidth(int value) {
if (value < 2) {
throw new IllegalArgumentException("사다리의 넓이는 2 이상이어야 합니다.");

Choose a reason for hiding this comment

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

넓이 라고 하니까 뭔가 사다리의 가로 길이와 세로 길이를 곱한 개념처럼 느껴졌는데, LadderWidthwidth는 주로 가로 길이를 의미하는 만큼 이에 맞는 예외 메시지를 작성해 보시는 것은 어떨까요?

}
this.value = value;
}

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

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

public class Line {
private final List<Bridge> bridges;

public Line(LadderWidth ladderWidth, Line previousLine) {
this.bridges = createBridges(ladderWidth, previousLine);
}

private List<Bridge> createBridges(LadderWidth ladderWidth, Line previousLine) {
List<Bridge> list = new ArrayList<>();
Random random = new Random();
boolean previousConnected = false;
List<Bridge> previousBridges = null;
if (previousLine != null) {
previousBridges = previousLine.getBridges();
}
for (int i = 0; i < ladderWidth.getValue() - 1; i++) {
boolean connected = determineConnection(previousConnected, random, previousBridges, i);
list.add(Bridge.fromBoolean(connected));
previousConnected = connected;
}
return list;
}

private boolean determineConnection(boolean previousConnected, Random random,
List<Bridge> previousBridges, int index) {
if (previousConnected) {
return false;
}
if (previousBridges != null && previousBridges.get(index) == Bridge.CONNECTED) {
return false;
}
return random.nextBoolean();
}

public List<Bridge> getBridges() {
return bridges;
}

public String draw() {
StringBuilder builder = new StringBuilder();
builder.append("|");
for (Bridge bridge : bridges) {
builder.append(bridge.display());
builder.append("|");
}
return builder.toString();
}

public Position move(Position position) {
int current = position.getValue();
if (canMoveLeft(current)) {
return new Position(current - 1);
}
if (canMoveRight(current)) {
return new Position(current + 1);
}
return position;
}

private boolean canMoveLeft(int current) {
return current > 0 && bridges.get(current - 1) == Bridge.CONNECTED;
}

private boolean canMoveRight(int current) {
int columnCount = bridges.size() + 1;
return current < columnCount - 1 && bridges.get(current) == Bridge.CONNECTED;
}
Comment on lines +55 to +73

Choose a reason for hiding this comment

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

사다리를 해석하고 연결 여부에 따라 아래로 따라가는 식으로 시뮬레이션 하는 코드군요? 직접 살펴봤는데 범위를 벗어날 만한 상황도 잘 처리되어 있네요
역시 일일이 따라가는 식으로 시뮬레이션 하는 방법이 그나마 직관적인 것 같아요, 다른 방법은 정말 안 떠오르더라고요

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

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

public class Lines {
private final List<Line> lines;

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

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

public List<String> drawAll() {
List<String> drawn = new ArrayList<>();
for (Line line : lines) {
drawn.add(line.draw());
}
return drawn;
}

public Position moveAll(Position position) {
Position result = position;
for (Line line : lines) {
result = line.move(result);
}
return result;
}

public int getColumnCount() {
if (lines.isEmpty()) {
return 0;
}
return lines.get(0).getBridges().size() + 1;
}
}
16 changes: 16 additions & 0 deletions src/main/java/domain/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package domain;

public class Name {
private final String value;

public Name(String value) {
if (value.length() > 5) {
throw new IllegalArgumentException("이름은 최대 5글자여야 합니다.");
}
this.value = value;
}
Comment on lines +6 to +11

Choose a reason for hiding this comment

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

이런 상황과 같이 이름이 0글자인 경우 통과할 수도 있으니 수정해 주시면 좋을 것 같아요
image


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

public class Player {
private final Name name;

public Player(Name name) {
this.name = name;
}

public Name getName() {
return name;
}
}
Comment on lines +3 to +13

Choose a reason for hiding this comment

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

마지막 부분에서 결과 조회할 때 all을 치면 전체 결과가 떠요. 그러면 플레이어명이 all일 경우 이 명령어와 겹칠 수 있으니 별도의 처리가 필요할 것 같아요

이미 글자 수 확인 로직은 하위 클래스인 Name에서 하고 있으니 여기에서 별도로 예외 처리 해보시는 것은 어떨까요?

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

import java.util.List;

public class Players {
private final List<Player> players;

public Players(List<Player> players) {
this.players = players;
}

public List<Player> getPlayers() {
return players;
}

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

public class Position {
private final int value;

public Position(int value) {
if (value < 0) {
throw new IllegalArgumentException("Position은 음수일 수 없습니다.");
}
this.value = value;
}

public int getValue() {
return value;
}

public Position moveLeft() {
return new Position(value - 1);
}

public Position moveRight() {
return new Position(value + 1);
}
}
Loading