diff --git a/src/main/java/LadderApplication.java b/src/main/java/LadderApplication.java new file mode 100644 index 0000000..3014400 --- /dev/null +++ b/src/main/java/LadderApplication.java @@ -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(); + } +} diff --git a/src/main/java/controller/LadderGameController.java b/src/main/java/controller/LadderGameController.java new file mode 100644 index 0000000..f8fc921 --- /dev/null +++ b/src/main/java/controller/LadderGameController.java @@ -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()); + + 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() { + while (true) { + PlayerName playerNameForResult = InputView.inputPlayerNameForResult(); + + if (playerNameForResult.getName().equals("all")) { + OutputView.printAllPlayersResult(ladderGame.getAllPlayersResult()); + continue; + } + + if (playerNameForResult.getName().equals("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()); + } + } + } + + 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() { + while (true) { + try { + return inputPlayerNameForResult(); + } catch (IllegalArgumentException e) { + OutputView.printErrorMessage(e.getMessage()); + } + } + } +} diff --git a/src/main/java/model/BooleanValueGenerator.java b/src/main/java/model/BooleanValueGenerator.java new file mode 100644 index 0000000..4ddb1bc --- /dev/null +++ b/src/main/java/model/BooleanValueGenerator.java @@ -0,0 +1,5 @@ +package model; + +public interface BooleanValueGenerator { + boolean generate(); +} diff --git a/src/main/java/model/Ladder.java b/src/main/java/model/Ladder.java new file mode 100644 index 0000000..37d4735 --- /dev/null +++ b/src/main/java/model/Ladder.java @@ -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 ladder; + private final int rowCount; + private final int columnCount; + + public Ladder(List ladder) { + validateLadder(ladder); + this.ladder = new ArrayList<>(ladder); + this.rowCount = ladder.size(); + this.columnCount = ladder.get(0).size() + 1; + } + + private void validateLadder(List 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 getConnections() { + return IntStream.range(0, columnCount) + .mapToObj((topIndex) -> getBottomIndex(topIndex)) + .collect(Collectors.toList()); + } + + public List getLadder() { + return Collections.unmodifiableList(ladder); + } +} diff --git a/src/main/java/model/LadderConnectionGenerator.java b/src/main/java/model/LadderConnectionGenerator.java new file mode 100644 index 0000000..cbc22ac --- /dev/null +++ b/src/main/java/model/LadderConnectionGenerator.java @@ -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(); + } +} diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java new file mode 100644 index 0000000..957d42d --- /dev/null +++ b/src/main/java/model/LadderGame.java @@ -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 ladderConnections; + + 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 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()); + } +} diff --git a/src/main/java/model/LadderGamePlayerResult.java b/src/main/java/model/LadderGamePlayerResult.java new file mode 100644 index 0000000..5f53d7b --- /dev/null +++ b/src/main/java/model/LadderGamePlayerResult.java @@ -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(); + } +} diff --git a/src/main/java/model/LadderGameStatus.java b/src/main/java/model/LadderGameStatus.java new file mode 100644 index 0000000..4c2b691 --- /dev/null +++ b/src/main/java/model/LadderGameStatus.java @@ -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 getLadder() { + return ladder.getLadder(); + } + + public List getPlayerNames() { + return playerNames.getNames(); + } + + public List getPrizeNames() { + return prizeNames.getNames(); + } +} diff --git a/src/main/java/model/LadderGenerator.java b/src/main/java/model/LadderGenerator.java new file mode 100644 index 0000000..6aa2502 --- /dev/null +++ b/src/main/java/model/LadderGenerator.java @@ -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 ladder = IntStream.range(0, rowCount) + .mapToObj((index) -> generateRow(columnCount - 1)) + .collect(Collectors.toList()); + + return new Ladder(ladder); + } + + private LadderRow generateRow(int ladderRowSize) { + List 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); + } +} diff --git a/src/main/java/model/LadderRow.java b/src/main/java/model/LadderRow.java new file mode 100644 index 0000000..818b585 --- /dev/null +++ b/src/main/java/model/LadderRow.java @@ -0,0 +1,38 @@ +package model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LadderRow { + private final List ladderRow; + + public LadderRow(List ladderRow) { + validateLadderLine(ladderRow); + this.ladderRow = new ArrayList<>(ladderRow); + } + + private void validateLadderLine(List ladderRow) { + 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 getRow() { + return Collections.unmodifiableList(ladderRow); + } + + public boolean get(int index) { + return ladderRow.get(index); + } + + public int size() { + return ladderRow.size(); + } +} diff --git a/src/main/java/model/PlayerName.java b/src/main/java/model/PlayerName.java new file mode 100644 index 0000000..fd6eafc --- /dev/null +++ b/src/main/java/model/PlayerName.java @@ -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; + } +} diff --git a/src/main/java/model/PlayerNames.java b/src/main/java/model/PlayerNames.java new file mode 100644 index 0000000..a875775 --- /dev/null +++ b/src/main/java/model/PlayerNames.java @@ -0,0 +1,55 @@ +package model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class PlayerNames { + private final List playerNames; + + private static int MINIMUM_PLAYER_COUNT = 2; + private static List BANNED_PLAYER_NAMES = List.of("all", "exit"); + + public PlayerNames(List playerNames) { + validatePlayerNames(playerNames); + this.playerNames = new ArrayList<>(playerNames); + } + + private void validatePlayerNames(List playerNames) { + if (playerNames.size() < MINIMUM_PLAYER_COUNT) { + throw new IllegalArgumentException("참가자 수는 최소 " + MINIMUM_PLAYER_COUNT + "명이어야 합니다."); + } + + boolean hasDuplicates = playerNames + .stream() + .map(PlayerName::getName) + .distinct() + .count() != playerNames.size(); + + if (hasDuplicates) { + throw new IllegalArgumentException("참가자 이름이 중복됩니다."); + } + + playerNames.forEach((playerName) -> { + if (BANNED_PLAYER_NAMES.contains(playerName.getName())) { + throw new IllegalArgumentException(playerName.getName() + + "은 참가자의 이름으로 정하실 수 없습니다. 다른 이름을 골라주세요."); + } + }); + } + + public List getNames() { + return playerNames.stream() + .map(PlayerName::getName) + .collect(Collectors.toUnmodifiableList()); + } + + public String get(int index) { + return playerNames.get(index).getName(); + } + + public int size() { + return playerNames.size(); + } +} diff --git a/src/main/java/model/PrizeName.java b/src/main/java/model/PrizeName.java new file mode 100644 index 0000000..176cd82 --- /dev/null +++ b/src/main/java/model/PrizeName.java @@ -0,0 +1,26 @@ +package model; + +import java.util.List; + +public class PrizeName { + private final String prizeName; + + private static final int MIN_PRIZE_NAME_LENGTH = 1; + private static final int MAX_PRIZE_NAME_LENGTH = 5; + + public PrizeName(String prizeName) { + validatePrizeName(prizeName); + this.prizeName = prizeName; + } + + private void validatePrizeName(String prizeName) { + if (prizeName.length() < MIN_PRIZE_NAME_LENGTH || prizeName.length() > MAX_PRIZE_NAME_LENGTH) { + throw new IllegalArgumentException("실행 결과의 길이는 " + MIN_PRIZE_NAME_LENGTH + "글자 이상 " + + MAX_PRIZE_NAME_LENGTH + "이하여야 합니다."); + } + } + + public String getName() { + return prizeName; + } +} diff --git a/src/main/java/model/PrizeNames.java b/src/main/java/model/PrizeNames.java new file mode 100644 index 0000000..128858b --- /dev/null +++ b/src/main/java/model/PrizeNames.java @@ -0,0 +1,37 @@ +package model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class PrizeNames { + private final List prizeNames; + + private static int MINIMUM_PRIZE_COUNT = 2; + + public PrizeNames(List prizeNames) { + validatePrizeNames(prizeNames); + this.prizeNames = new ArrayList<>(prizeNames); + } + + private void validatePrizeNames(List prizeNames) { + if (prizeNames.size() < MINIMUM_PRIZE_COUNT) { + throw new IllegalArgumentException("실행 결과의 수는 최소 " + MINIMUM_PRIZE_COUNT + "개여야 합니다."); + } + } + + public List getNames() { + return prizeNames.stream() + .map(PrizeName::getName) + .collect(Collectors.toUnmodifiableList()); + } + + public String get(int index) { + return prizeNames.get(index).getName(); + } + + public int size() { + return prizeNames.size(); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000..d6456e3 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,44 @@ +package view; + +import model.PlayerName; +import model.PlayerNames; +import model.PrizeName; +import model.PrizeNames; + +import java.util.Arrays; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + private static final Scanner scanner = new Scanner(System.in); + + public static PlayerNames inputPlayerNames() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + PlayerNames playerNames = new PlayerNames(Arrays.stream(scanner.nextLine().split(",")) + .map((playerName) -> new PlayerName(playerName.trim())) + .collect(Collectors.toList())); + + return playerNames; + } + + public static PrizeNames inputPrizeNames() { + System.out.println("\n실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); + PrizeNames prizeNames = new PrizeNames(Arrays.stream(scanner.nextLine().split(",")) + .map((prizeName) -> new PrizeName(prizeName.trim())) + .collect(Collectors.toList())); + + return prizeNames; + } + + public static int inputLadderHeight() { + System.out.println("\n최대 사다리 높이는 몇 개인가요?"); + + return Integer.parseInt(scanner.nextLine()); + } + + public static PlayerName inputPlayerNameForResult() { + System.out.println("\n결과를 보고 싶은 사람은? (all: 전체 / exit: 게임 종료)"); + + return new PlayerName(scanner.nextLine().trim()); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 0000000..ba5533c --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,66 @@ +package view; + +import model.LadderGamePlayerResult; +import model.LadderGameStatus; +import model.PlayerName; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class OutputView { + public static void printErrorMessage(String errorMessage) { + System.out.println("\n[ERROR!] " + errorMessage); + System.out.println("[i] 다시 입력해 주세요...\n"); + } + + public static void printGameStatus(LadderGameStatus ladderGameStatus) { + System.out.println("\n사다리 결과\n"); + + ladderGameStatus.getPlayerNames().forEach((playerName) -> { + System.out.printf("%6s", playerName); + }); + System.out.println(); + + ladderGameStatus.getLadder().forEach(((ladderRow) -> { + String asciiLadder = " |" + ladderRow.getRow().stream() + .map(ladderConnection -> { + if (ladderConnection) { + return "-----"; + } + return " "; + }) + .collect(Collectors.joining("|")) + "|"; + System.out.println(asciiLadder); + })); + + + ladderGameStatus.getPrizeNames().forEach((prizeName) -> { + System.out.printf("%6s", prizeName); + }); + System.out.println(); + } + + public static void printAllPlayersResult(List ladderGamePlayerResults) { + System.out.println("\n실행 결과"); + + ladderGamePlayerResults.forEach(((ladderGamePlayerResult) -> { + System.out.printf("%s : %s\n", ladderGamePlayerResult.getPlayerName(), + ladderGamePlayerResult.getPrizeName()); + })); + } + + public static void printPlayerResult(String playerResult) { + if (playerResult == null) { + System.out.println("\n해당 참가자의 이름이 존재하지 않습니다."); + return; + } + + System.out.println("\n실행 결과"); + System.out.println(playerResult); + } + + public static void printExitMessage() { + System.out.println("\n사다리 게임을 종료합니다..."); + } +} diff --git a/src/test/java/LadderGameTest.java b/src/test/java/LadderGameTest.java new file mode 100644 index 0000000..8b6a4b6 --- /dev/null +++ b/src/test/java/LadderGameTest.java @@ -0,0 +1,88 @@ +import model.*; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class LadderGameTest { + @Nested + @DisplayName("Test #1 - 게임 결과 반환 테스트") + class LadderGameResultTest { + private LadderGame ladderGame; + + /** + * 사다리 모양 및 관계는 아래와 같습니다. + * + * Alice Bob Cara Drew Elsa + * | |-----| | | + * |-----| | |-----| + * |-----| | | | + * | | |-----| | + * |-----| | |-----| + * | | | |-----| + * 30$ 0$ 1000$ 10$ 150$ + * + * Alice -> 0$ + * Bob -> 10$ + * Cara -> 30$ + * Drew -> 150$ + * Elsa -> 1000$ + */ + @BeforeEach + void setupLadder() { + TestLadderConnectionGenerator testLadderConnectionGenerator = + new TestLadderConnectionGenerator(List.of( + false, true, false, true, false, true, true, false, false, false, + false, true, true, false, true, false, false, false, true + )); + LadderGenerator ladderGenerator = new LadderGenerator(testLadderConnectionGenerator); + PlayerNames playerNames = new PlayerNames(List.of( + new PlayerName("Alice"), + new PlayerName("Bob"), + new PlayerName("Cara"), + new PlayerName("Drew"), + new PlayerName("Elsa") + )); + PrizeNames prizeNames = new PrizeNames(List.of( + new PrizeName("30$"), + new PrizeName("0$"), + new PrizeName("1000$"), + new PrizeName("10$"), + new PrizeName("150$") + )); + int ladderHeight = 6; + + ladderGame = new LadderGame(ladderGenerator, playerNames, prizeNames, ladderHeight); + } + + @Test + @DisplayName("전체 참가자의 결과를 조회할 경우 전체 참가자의 결과가 올바르게 짝지어 반환되어야 한다.") + void should_returnCorrectConnectionOfAllPlayers_IfCalled() { + List ladderGamePlayerResults = List.of( + new LadderGamePlayerResult(new PlayerName("Alice"), new PrizeName("0$")), + new LadderGamePlayerResult(new PlayerName("Bob"), new PrizeName("10$")), + new LadderGamePlayerResult(new PlayerName("Cara"), new PrizeName("30$")), + new LadderGamePlayerResult(new PlayerName("Drew"), new PrizeName("150$")), + new LadderGamePlayerResult(new PlayerName("Elsa"), new PrizeName("1000$")) + ); + + assertThat(ladderGame.getAllPlayersResult()) + .usingRecursiveComparison() + .isEqualTo(ladderGamePlayerResults); + } + + @Test + @DisplayName("각 참가자의 결과를 조회할 경우 각 참가자의 결과가 올바르게 짝지어 반환되어야 한다.") + void should_returnCorrectConnectionOfPlayer_IfCalled() { + assertThat(ladderGame.getPlayerPrize(new PlayerName("Cara"))) + .isEqualTo("30$"); + + assertThat(ladderGame.getPlayerPrize(new PlayerName("Elsa"))) + .isEqualTo("1000$"); + } + } +} diff --git a/src/test/java/LadderGeneratorTest.java b/src/test/java/LadderGeneratorTest.java new file mode 100644 index 0000000..2ffde37 --- /dev/null +++ b/src/test/java/LadderGeneratorTest.java @@ -0,0 +1,36 @@ +import model.*; +import org.assertj.core.util.Arrays; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class LadderGeneratorTest { + @Nested + @DisplayName("Test #1 - 사다리 생성 테스트") + class LadderCreationTest { + @Test + @DisplayName("랜덤 값을 이용해 사다리를 생성할 경우 그 값이 반환되어야 한다.") + void should_returnLadderWithoutException_IfValidLadderRandomValueGiven() { + TestLadderConnectionGenerator testLadderConnectionGenerator = + new TestLadderConnectionGenerator(List.of( + true, false, true, false, true, true, + false, false, false, false, true + )); + LadderGenerator ladderGenerator = new LadderGenerator(testLadderConnectionGenerator); + Ladder expectedLadder = new Ladder(List.of( + new LadderRow(List.of(true, false, false, true, false)), + new LadderRow(List.of(false, true, false, true, false)), + new LadderRow(List.of(false, false, false, false, true)) + )); + + assertThat(ladderGenerator.generateLadder(3, 6)) + .usingRecursiveComparison() + .isEqualTo(expectedLadder); + } + } +} diff --git a/src/test/java/LadderTest.java b/src/test/java/LadderTest.java new file mode 100644 index 0000000..12e882f --- /dev/null +++ b/src/test/java/LadderTest.java @@ -0,0 +1,99 @@ +import model.Ladder; +import model.LadderGenerator; +import model.LadderRow; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +public class LadderTest { + @Nested + @DisplayName("Test #1 - 사다리 생성 검증 테스트") + class LadderValidationTest { + @Test + @DisplayName("주어지는 사다리가 올바르다면 예외를 발생시켜서는 안 된다.") + void should_notThrowException_If_ValidLadderRowGiven() { + assertDoesNotThrow(() -> { + Ladder ladder = new Ladder(List.of( + new LadderRow(List.of(false, true, false)), + new LadderRow(List.of(true, false, true)), + new LadderRow(List.of(false, false, true)), + new LadderRow(List.of(true, false, false)) + )); + }); + } + + @Test + @DisplayName("사다리의 행이 빌 경우 관련 예외를 설명하는 예외를 발생시켜야 한다.") + void should_throwException_If_EmptyLadderRowGiven() { + assertThatIllegalArgumentException().isThrownBy(() -> { + Ladder ladder = new Ladder(List.of( + new LadderRow(List.of()) + )); + }).withMessage("사다리를 이루는 행은 비어서는 안 됩니다."); + } + + @Test + @DisplayName("사다리의 가로 라인이 겹치는 사다리가 주어질 경우 관련 예외를 설명하는 예외를 발생시켜야 한다.") + void should_throwException_If_InvalidLadderRowGiven() { + assertThatIllegalArgumentException().isThrownBy(() -> { + Ladder ladder = new Ladder(List.of( + new LadderRow(List.of(false, false, false)), + new LadderRow(List.of(false, true, true)), + new LadderRow(List.of(true, false, false)) + )); + }).withMessage("사다리를 이루는 행의 연결선은 겹칠 수 없습니다."); + } + + @Test + @DisplayName("크기가 서로 다른 사다리 행으로 구성된 사다리가 주어질 경우 관련 예외를 설명하는 예외를 발생시켜야 한다.") + void should_throwException_If_DifferentLengthLadderRowGiven() { + assertThatIllegalArgumentException().isThrownBy(() -> { + Ladder ladder = new Ladder(List.of( + new LadderRow(List.of(false, true, false)), + new LadderRow(List.of(true, false, true, false)) + )); + }).withMessage("사다리를 이루는 행의 크기는 모두 같아야 합니다."); + } + } + + @Nested + @DisplayName("Test #2 - 사다리 관계 연결 테스트") + class LadderConnectionTest { + /** + * 사다리 모양 및 관계는 아래와 같습니다. + * + * 0 1 2 3 + * | |-----| | + * |-----| |-----| + * | | |-----| + * |-----| | | + * 0 1 2 3 + * + * 0 -> 0 + * 1 -> 2 + * 2 -> 1 + * 3 -> 3 + */ + @Test + @DisplayName("사다리가 주어질 경우 참가자와 실행 결과를 올바르게 짝지어야 한다.") + void should_returnPlayerAndPrizeConnection_If_LadderGiven() { + Ladder ladder = new Ladder(List.of( + new LadderRow(List.of(false, true, false)), + new LadderRow(List.of(true, false, true)), + new LadderRow(List.of(false, false, true)), + new LadderRow(List.of(true, false, false)) + )); + List expectedConnection = List.of(0, 2, 1, 3); + + assertThat(ladder.getConnections()).isEqualTo(expectedConnection); + } + } +} diff --git a/src/test/java/TestLadderConnectionGenerator.java b/src/test/java/TestLadderConnectionGenerator.java new file mode 100644 index 0000000..4294ddb --- /dev/null +++ b/src/test/java/TestLadderConnectionGenerator.java @@ -0,0 +1,25 @@ +import model.BooleanValueGenerator; + +import java.util.ArrayList; +import java.util.List; + +class TestLadderConnectionGenerator implements BooleanValueGenerator { + private int mockValueIndex = 0; + private final List mockValues; + + TestLadderConnectionGenerator(List mockValues) { + this.mockValues = new ArrayList<>(mockValues); + } + + @Override + public boolean generate() { + if (mockValueIndex >= mockValues.size()) { + throw new IllegalStateException("더 이상 사용할 모의 랜덤 값이 없습니다."); + } + + boolean currentMockValue = mockValues.get(mockValueIndex); + mockValueIndex += 1; + + return currentMockValue; + } +}