Skip to content

[사다리] 김의천 미션 제출합니다. #34

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 18 commits into
base: wzrabbit
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
52d07e8
✨ feat: 사다리 행 클래스를 구현
wzrabbit Feb 24, 2025
ed36c10
✨ feat: 사다리 클래스를 구현
wzrabbit Feb 24, 2025
7488fa2
✨ feat: 불리언 값을 생성하는 메서드가 포함되는 인터페이스를 구현
wzrabbit Feb 24, 2025
61db22a
✨ feat: 단일 불리언 값을 랜덤으로 생성하는 클래스를 구현
wzrabbit Feb 24, 2025
4cf72cc
🧪 test: 단일 불리언 값을 모킹하여 생성하는 클래스를 구현
wzrabbit Feb 24, 2025
b53b159
✨ feat: 사다리를 무작위로 생성해 반환하는 클래스를 구현
wzrabbit Feb 24, 2025
9fd10c3
✨ feat: 참가자 이름 / 참가자 이름 목록을 관리하는 클래스 구현
wzrabbit Feb 24, 2025
291d0a7
✨ feat: 실행 결과 / 실행 결과 목록을 관리하는 클래스 구현
wzrabbit Feb 24, 2025
dbf81cd
✨ feat: 사다리 게임의 결과를 저장하는 DTO 구현
wzrabbit Feb 24, 2025
273efea
✨ feat: 사다리 게임의 상태를 저장하는 DTO 구현
wzrabbit Feb 24, 2025
1c1faaf
✨ feat: 사다리 게임 클래스를 구현
wzrabbit Feb 24, 2025
5a69f09
✨ feat: 사다리 게임의 입력을 담당하는 View 클래스 구현
wzrabbit Feb 24, 2025
78c4c89
✨ feat: 사다리 게임의 출력을 담당하는 View 클래스 구현
wzrabbit Feb 24, 2025
bb897a0
✨ feat: 사다리 게임에서 model과 view를 이어주는 컨트롤러 구현
wzrabbit Feb 24, 2025
c947713
✨ feat: 사다리 게임을 진행하는 시작점 클래스 구현
wzrabbit Feb 24, 2025
7263db0
🧪 test: LadderGenerator에 대응하는 테스트 작성
wzrabbit Feb 24, 2025
5a588ed
🧪 test: Ladder에 대응하는 테스트 작성
wzrabbit Feb 24, 2025
4a85f14
🧪 test: LadderGame에 대응하는 테스트 작성
wzrabbit Feb 24, 2025
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
11 changes: 11 additions & 0 deletions src/main/java/LadderApplication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import controller.LadderGameController;

public class LadderApplication {
public static void main(String[] args) {
final LadderGameController ladderGameController = new LadderGameController();

ladderGameController.inputGameInfos();
ladderGameController.showGameStatus();
ladderGameController.showGameResult();
}
}
91 changes: 91 additions & 0 deletions src/main/java/controller/LadderGameController.java

Choose a reason for hiding this comment

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

가독성을 위해 자잘하게 함수를 나눈거죠? 좋네요 확인하기!
컨트롤러에서 input output에 대한 처리도 좀 하는걸로 보이는데 유효성 검사 때문에 상단에서 몰아서 유효한지 확인하는건가요?

Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package controller;

import model.*;
import view.InputView;
import view.OutputView;

import java.util.InputMismatchException;

public class LadderGameController {
private LadderGame ladderGame;
private final LadderGenerator ladderGenerator = new LadderGenerator(new LadderConnectionGenerator());

Choose a reason for hiding this comment

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

이거 코드 생성자에서 주입하는 방식도 좋을 것 같아요


public void inputGameInfos() {
PlayerNames playerNames = inputPlayerNames();
PrizeNames prizeNames = inputPrizeNames(playerNames.size());
int ladderHeight = inputLadderHeight();

ladderGame = new LadderGame(ladderGenerator, playerNames, prizeNames, ladderHeight);
}

public void showGameStatus() {
OutputView.printGameStatus(ladderGame.getGameStatus());
}

public void showGameResult() {

Choose a reason for hiding this comment

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

혹시 이쪽에 enum을 사용해보실 생각이 있으실까요? ENUM을 직접 활용한 부분이 없어서 아쉬워요
이런식으로? 사실 좀 억지로 넣는 것 같긴해도 이왕 배운거 사용해보면 좋지않을까 싶네요!
물론 여기말고 다른쪽에 활용할 부분이 있다면 거기서 enum을 사용해도 좋아요

Suggested change
public void showGameResult() {
public enum ResultCommand {
ALL("all"),
EXIT("exit"),
SINGLE("");
private final String command;
ResultCommand(String command) {
this.command = command;
}
public static ResultCommand from(String input) {
if (input.equalsIgnoreCase("all")) {
return ALL;
}
if (input.equalsIgnoreCase("exit")) {
return EXIT;
}
return SINGLE;
}
}

while (true) {
PlayerName playerNameForResult = InputView.inputPlayerNameForResult();

if (playerNameForResult.getName().equals("all")) {

Choose a reason for hiding this comment

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

all키워드는 자주 사용되는 것 같아서 상수로 추출해도 좋을 것 같아요

OutputView.printAllPlayersResult(ladderGame.getAllPlayersResult());
continue;
}

if (playerNameForResult.getName().equals("exit")) {

Choose a reason for hiding this comment

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

exit키워드도 상수로 추출해도 좋을 것 같아여

OutputView.printExitMessage();
break;
}

OutputView.printPlayerResult(ladderGame.getPlayerPrize(playerNameForResult));
}
}


private PlayerNames inputPlayerNames() {
while (true) {
try {
return InputView.inputPlayerNames();
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e.getMessage());
}
}
}
Comment on lines +45 to +52

Choose a reason for hiding this comment

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

while-try-catch 로직이 자주 등장하는데. 뭔가 메서드로 추상화해서 사용해도 좋을 것 같아요


private PrizeNames inputPrizeNames(int prizeCount) {
while (true) {
try {
return InputView.inputPrizeNames();
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e.getMessage());
}
}
}

private int inputLadderHeight() {
while (true) {
try {
int ladderHeight = InputView.inputLadderHeight();

if (ladderHeight <= 0) {
throw new IllegalArgumentException("사다리 높이를 양수로 입력해주세요.");
}

return ladderHeight;
} catch (NumberFormatException e) {
OutputView.printErrorMessage("사다리 높이를 정수로 입력해주세요!");
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e.getMessage());
}
}
}

private PlayerName inputPlayerNameForResult() {

Choose a reason for hiding this comment

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

이친구는 왜 무한으로 자기를 호출하고 있죠..?

while (true) {
try {
return inputPlayerNameForResult();
} catch (IllegalArgumentException e) {
OutputView.printErrorMessage(e.getMessage());
}
}
}
}
5 changes: 5 additions & 0 deletions src/main/java/model/BooleanValueGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package model;

public interface BooleanValueGenerator {
boolean generate();
}
58 changes: 58 additions & 0 deletions src/main/java/model/Ladder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package model;

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

public class Ladder {
private final List<LadderRow> ladder;
private final int rowCount;
private final int columnCount;

public Ladder(List<LadderRow> ladder) {
validateLadder(ladder);
this.ladder = new ArrayList<>(ladder);
this.rowCount = ladder.size();
this.columnCount = ladder.get(0).size() + 1;
}

private void validateLadder(List<LadderRow> ladder) {
boolean isAllLadderRowSizeSame = ladder.stream()
.map(LadderRow::size)
.distinct()
.count() == 1;

if (!isAllLadderRowSizeSame) {
throw new IllegalArgumentException("사다리를 이루는 행의 크기는 모두 같아야 합니다.");
}
}

private int getBottomIndex(int topIndex) {
int column = topIndex;

for (int row = 0; row < rowCount; row += 1) {
if (column > 0 && ladder.get(row).get(column - 1)) {
column -= 1;
continue;
}

if (column < columnCount - 1 && ladder.get(row).get(column)) {
column += 1;
}
}

return column;
}

public List<Integer> getConnections() {
return IntStream.range(0, columnCount)
.mapToObj((topIndex) -> getBottomIndex(topIndex))
.collect(Collectors.toList());
}

public List<LadderRow> getLadder() {
return Collections.unmodifiableList(ladder);

Choose a reason for hiding this comment

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

오 고오급 문법!

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

import java.util.Random;

public class LadderConnectionGenerator implements BooleanValueGenerator {
private final Random random = new Random();

@Override
public boolean generate() {
return random.nextBoolean();
}
}
45 changes: 45 additions & 0 deletions src/main/java/model/LadderGame.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;
import java.util.stream.IntStream;

public class LadderGame {
private final Ladder ladder;
private final PlayerNames playerNames;
private final PrizeNames prizeNames;
private final List<Integer> ladderConnections;
Comment on lines +8 to +11

Choose a reason for hiding this comment

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

마이너한 리뷰 추가하자면
private final PlayerNames playerNames;
private final PrizeNames prizeNames;
이거 두개 묶어서 또 클래스 분리하면 인스턴스 변수를 하나 줄일 수 있겠네요!


public LadderGame(LadderGenerator ladderGenerator, PlayerNames playerNames, PrizeNames prizeNames,
int ladderHeight) {
this.ladder = ladderGenerator.generateLadder(ladderHeight, playerNames.size());
this.playerNames = playerNames;
this.prizeNames = prizeNames;
this.ladderConnections = ladder.getConnections();
}

public LadderGameStatus getGameStatus() {
return new LadderGameStatus(ladder, playerNames, prizeNames);
}

public String getPlayerPrize(PlayerName playerName) {
int playerIndex = playerNames.getNames().indexOf(playerName.getName());

if (playerIndex == -1) {
return null;
}

return prizeNames.get(ladderConnections.get(playerIndex));
}

public List<LadderGamePlayerResult> getAllPlayersResult() {
return playerNames
.getNames()
.stream()
.map(playerName -> {
String prizeName = getPlayerPrize(new PlayerName(playerName));
return new LadderGamePlayerResult(new PlayerName(playerName), new PrizeName(prizeName));
})
.collect(Collectors.toList());
}
}
19 changes: 19 additions & 0 deletions src/main/java/model/LadderGamePlayerResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package model;

public class LadderGamePlayerResult {
private final PlayerName playerName;
private final PrizeName prizeName;

public LadderGamePlayerResult(PlayerName playerName, PrizeName prizeName) {
this.playerName = playerName;
this.prizeName = prizeName;
}

public String getPlayerName() {
return this.playerName.getName();
}

public String getPrizeName() {
return this.prizeName.getName();
}
}
27 changes: 27 additions & 0 deletions src/main/java/model/LadderGameStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package model;

import java.util.List;

public class LadderGameStatus {
private final Ladder ladder;
private final PlayerNames playerNames;
private final PrizeNames prizeNames;

public LadderGameStatus(Ladder ladder, PlayerNames playerNames, PrizeNames prizeNames) {
this.ladder = ladder;
this.playerNames = playerNames;
this.prizeNames = prizeNames;
}

public List<LadderRow> getLadder() {
return ladder.getLadder();
}

public List<String> getPlayerNames() {
return playerNames.getNames();
}

public List<String> getPrizeNames() {
return prizeNames.getNames();
}
}
37 changes: 37 additions & 0 deletions src/main/java/model/LadderGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package model;

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

public class LadderGenerator {
private final BooleanValueGenerator booleanValueGenerator;

public LadderGenerator(BooleanValueGenerator booleanValueGenerator) {
this.booleanValueGenerator = booleanValueGenerator;
}

public Ladder generateLadder(int rowCount, int columnCount) {
List<LadderRow> ladder = IntStream.range(0, rowCount)
.mapToObj((index) -> generateRow(columnCount - 1))
.collect(Collectors.toList());

return new Ladder(ladder);
}

private LadderRow generateRow(int ladderRowSize) {
List<Boolean> ladderRow = new ArrayList<>();

while (ladderRow.size() < ladderRowSize) {
if (ladderRow.size() == 0 || !ladderRow.get(ladderRow.size() - 1)) {
ladderRow.add(booleanValueGenerator.generate());
continue;
}

ladderRow.add(false);
}

return new LadderRow(ladderRow);
}
}
38 changes: 38 additions & 0 deletions src/main/java/model/LadderRow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package model;

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

public class LadderRow {
private final List<Boolean> ladderRow;

public LadderRow(List<Boolean> ladderRow) {
validateLadderLine(ladderRow);
this.ladderRow = new ArrayList<>(ladderRow);
}

private void validateLadderLine(List<Boolean> ladderRow) {

Choose a reason for hiding this comment

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

올 연결선 겹치는거 유효성 처리는 완전 굿인데요

if (ladderRow.isEmpty()) {
throw new IllegalArgumentException("사다리를 이루는 행은 비어서는 안 됩니다.");
}

for (int i = 0; i < ladderRow.size() - 1; i++) {
if (ladderRow.get(i) && ladderRow.get(i + 1)) {
throw new IllegalArgumentException("사다리를 이루는 행의 연결선은 겹칠 수 없습니다.");
}
}
}

public List<Boolean> getRow() {
return Collections.unmodifiableList(ladderRow);
}

public boolean get(int index) {
return ladderRow.get(index);
}

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

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

public class PlayerName {
private final String playerName;

private static final int MIN_PLAYER_NAME_LENGTH = 1;
private static final int MAX_PLAYER_NAME_LENGTH = 5;

public PlayerName(String playerName) {
validatePlayerName(playerName);
this.playerName = playerName;
}

private void validatePlayerName(String playerName) {
if (playerName.length() < MIN_PLAYER_NAME_LENGTH || playerName.length() > MAX_PLAYER_NAME_LENGTH) {
throw new IllegalArgumentException("참가자의 이름은 " + MIN_PLAYER_NAME_LENGTH + "글자 이상 " +
MAX_PLAYER_NAME_LENGTH + "이하여야 합니다.");
}
}

public String getName() {
return playerName;
}
}
Loading