diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..f155431d --- /dev/null +++ b/src/README.md @@ -0,0 +1,42 @@ +# 사다리 게임 + +콘솔 환경에서 실행되는 사다리 타기 애플리케이션입니다. 사용자로부터 참여자 이름, 실행 결과, 사다리 높이를 입력받아 사다리를 무작위로 생성하고 결과를 계산합니다. + +## 기능 목록 + +* **입력 기능** + * 참여할 사람의 이름을 쉼표(,)를 기준으로 입력받는다. (이름은 최대 5자) + * 게임 실행 결과를 쉼표(,)를 기준으로 입력받는다. (결과는 최대 5자, 참여자 수와 개수가 일치해야 함) + * 최대 사다리 높이를 입력받는다. + * 결과를 확인할 대상의 이름을 입력받는다. ('all' 입력 시 전체 결과 확인) + +* **사다리 생성 로직** + * 주어진 참여자 수와 사다리 높이에 맞춰 사다리 라인을 생성한다. + * 가로 라인이 연속으로 겹치지 않도록 제어한다. + * 사다리 생성 시 사다리를 건너갈 수 없는(가로 라인이 하나도 없는) 수직 구간이 발생할 경우, 조건이 충족될 때까지 사다리를 재생성한다. + +* **결과 계산 로직** + * 각 참여자의 시작 위치에서 사다리 라인을 타고 내려가 최종 도착 위치를 연산한다. + * 최종 도착 위치에 해당하는 실행 결과를 플레이어에게 매핑한다. + +* **출력 기능** + * 생성된 사다리의 형태를 참여자 이름, 실행 결과와 함께 정렬하여 출력한다. + * 특정 플레이어의 이름을 입력하면 매핑된 실행 결과를 단건 출력한다. + * 'all'을 입력하면 모든 플레이어의 실행 결과를 전체 출력한다. + +## 패키지 구조 + +* `controller` + * `LadderController` : 사용자 입력, 도메인 로직 실행, 뷰 출력 흐름을 제어합니다. +* `domain` + * `Ladder`, `Line` : 사다리의 형태 유지 및 이동 경로 데이터 관리를 담당합니다. + * `LadderGenerator`, `LineGenerator` : 무작위 값(Boolean)을 이용한 사다리 생성 책임을 가집니다. + * `Player`, `Players`, `Reward`, `Rewards` : 참여자와 결과에 대한 값 객체 및 일급 컬렉션입니다. + * `GameResult` : 사다리 이동 결과와 보상을 매핑하여 최종 게임 결과를 보관합니다. +* `view` + * `InputView` : 콘솔을 통한 데이터 입력을 담당합니다. + * `OutputView` : 사다리 형태 및 게임 결과 출력을 담당합니다. + +## 실행 방법 + +`Application` 클래스의 `main` 메서드를 통해 애플리케이션을 실행합니다. \ No newline at end of file diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..e948443b --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,12 @@ +import controller.LadderController; +import view.InputView; +import view.OutputView; + +public class Application { + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + LadderController controller = new LadderController(inputView, outputView); + controller.run(); + } +} diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java new file mode 100644 index 00000000..eb8fb961 --- /dev/null +++ b/src/main/java/controller/LadderController.java @@ -0,0 +1,65 @@ +package controller; +import domain.LadderGenerator; +import domain.LadderHeight; +import domain.Players; +import domain.Rewards; +import domain.GameResult; +import domain.Ladder; +import domain.LadderWidth; +import domain.LadderResult; +import domain.RandomBooleanGenerator; +import view.InputView; +import view.OutputView; + +public class LadderController { + private final InputView inputView; + private final OutputView outputView; + + public LadderController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + Players players = inputView.readPlayers(); + Rewards rewards = inputRewards(players); + LadderHeight height = new LadderHeight(inputView.readHeight()); + + Ladder ladder = LadderGenerator.generate(new LadderWidth(players.size()), height, new RandomBooleanGenerator()); + outputView.printLadderBoard(players, ladder, rewards); + + GameResult gameResult = createGameResult(players, rewards, ladder); + printTargetResults(gameResult); + } + + private Rewards inputRewards(Players players) { + Rewards rewards = inputView.readRewards(); + if (players.size() != rewards.size()) { + throw new IllegalArgumentException("사람 수와 결과 수가 일치하지 않습니다."); + } + return rewards; + } + + private GameResult createGameResult(Players players, Rewards rewards, Ladder ladder) { + LadderResult ladderResult = ladder.play(new LadderWidth(players.size())); + return GameResult.of(players, rewards, ladderResult); + } + + private void printTargetResults(GameResult gameResult) { + while (true) { + String target = inputView.readTargetPerson(); + if (processTarget(target, gameResult)) { + break; + } + } + } + + private boolean processTarget(String target, GameResult gameResult) { + if ("all".equals(target)) { + outputView.printAllResults(gameResult); + return true; + } + outputView.printSingleResult(gameResult.findByName(target)); + return false; + } +} diff --git a/src/main/java/domain/BooleanGenerator.java b/src/main/java/domain/BooleanGenerator.java new file mode 100644 index 00000000..92ad2cab --- /dev/null +++ b/src/main/java/domain/BooleanGenerator.java @@ -0,0 +1,6 @@ +package domain; + + +public interface BooleanGenerator { + boolean generate(); +} diff --git a/src/main/java/domain/GameResult.java b/src/main/java/domain/GameResult.java new file mode 100644 index 00000000..dd7d5236 --- /dev/null +++ b/src/main/java/domain/GameResult.java @@ -0,0 +1,38 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GameResult { + private final List players; + + public GameResult(List players) { + this.players = players; + } + + public static GameResult of(Players players, Rewards rewards, LadderResult ladderResult) { + List playerList = new ArrayList<>(); + for (int i = 0; i < players.size(); i++) { + playerList.add(createPlayer(i, players, rewards, ladderResult)); + } + return new GameResult(playerList); + } + + private static Player createPlayer(int index, Players players, Rewards rewards, LadderResult result) { + Position start = new Position(index); + Position end = result.getEndPosition(start); + return new Player(players.getName(index), rewards.getReward(end.getValue())); + } + + public Player findByName(String targetName) { + return players.stream() + .filter(player -> player.hasName(targetName)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사람입니다.")); + } + + public List getAll() { + return Collections.unmodifiableList(players); + } +} diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java new file mode 100644 index 00000000..3a056719 --- /dev/null +++ b/src/main/java/domain/Ladder.java @@ -0,0 +1,35 @@ +package domain; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class Ladder { + private final List lines; + + public Ladder(List lines) { + this.lines = lines; + } + + public LadderResult play(LadderWidth width) { + Map results = new LinkedHashMap<>(); + for (int i = 0; i < width.getValue(); i++) { + Position startPosition = new Position(i); + results.put(startPosition, playOne(startPosition)); + } + return new LadderResult(results); + } + + private Position playOne(Position startPosition) { + Position current = startPosition; + for (Line line : lines) { + current = line.move(current); + } + return current; + } + + public List getLines() { + return Collections.unmodifiableList(lines); + } +} diff --git a/src/main/java/domain/LadderGenerator.java b/src/main/java/domain/LadderGenerator.java new file mode 100644 index 00000000..6dfb4311 --- /dev/null +++ b/src/main/java/domain/LadderGenerator.java @@ -0,0 +1,45 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + +public class LadderGenerator { + + private LadderGenerator() { + } + + public static Ladder generate(LadderWidth width, LadderHeight height, BooleanGenerator generator) { + Ladder ladder = createLadder(width, height, generator); + while (hasEmptyInterval(ladder, width)) { + ladder = createLadder(width, height, generator); + } + return ladder; + } + + private static Ladder createLadder(LadderWidth width, LadderHeight height, BooleanGenerator generator) { + List lines = new ArrayList<>(); + Line currentLine = Line.generateFirst(width, generator); + lines.add(currentLine); + return new Ladder(addRemainingLines(lines, width, height, generator, currentLine)); + } + + private static List addRemainingLines(List lines, LadderWidth width, LadderHeight height, BooleanGenerator generator, Line firstLine) { + Line currentLine = firstLine; + for (int i = 1; i < height.getValue(); i++) { + currentLine = Line.generateNext(width, generator, currentLine); + lines.add(currentLine); + } + return lines; + } + + private static boolean hasEmptyInterval(Ladder ladder, LadderWidth width) { + return IntStream.range(0, width.getIntervalCount()) + .anyMatch(index -> isEmptyInterval(ladder, index)); + } + + private static boolean isEmptyInterval(Ladder ladder, int index) { + return ladder.getLines().stream().noneMatch(line -> line.isConnectedAt(index)); + } + +} diff --git a/src/main/java/domain/LadderHeight.java b/src/main/java/domain/LadderHeight.java new file mode 100644 index 00000000..07ebabf2 --- /dev/null +++ b/src/main/java/domain/LadderHeight.java @@ -0,0 +1,24 @@ +package domain; + +public class LadderHeight { + private static final int MINIMUM_HEIGHT = 1; + private static final String ERROR_MESSAGE = "사다리 높이는 1 이상이어야 합니다."; + + private final int value; + + public LadderHeight(int value) { + validate(value); + this.value = value; + } + + private void validate(int value) { + if (value < MINIMUM_HEIGHT) { + throw new IllegalArgumentException(ERROR_MESSAGE); + } + } + + + public int getValue() { + return value; + } +} diff --git a/src/main/java/domain/LadderResult.java b/src/main/java/domain/LadderResult.java new file mode 100644 index 00000000..0a5dd113 --- /dev/null +++ b/src/main/java/domain/LadderResult.java @@ -0,0 +1,15 @@ +package domain; +import java.util.Map; + + +public class LadderResult { + private final Map results; + + public LadderResult(Map results) { + this.results = results; + } + + public Position getEndPosition(Position start) { + return results.get(start); + } +} diff --git a/src/main/java/domain/LadderWidth.java b/src/main/java/domain/LadderWidth.java new file mode 100644 index 00000000..cd6586fc --- /dev/null +++ b/src/main/java/domain/LadderWidth.java @@ -0,0 +1,28 @@ +package domain; + +public class LadderWidth { + private static final int MINIMUM_WIDTH = 2; + private static final String ERROR_MESSAGE = "사다리 폭은 2 이상이어야 합니다."; + + private final int value; + + public LadderWidth(int value) { + validate(value); + this.value = value; + } + + private void validate(int value) { + if (value < MINIMUM_WIDTH) { + throw new IllegalArgumentException(ERROR_MESSAGE); + } + } + + public int getValue() { + return value; + } + + public int getIntervalCount() { + return value - 1; + } + +} diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java new file mode 100644 index 00000000..5e2805f4 --- /dev/null +++ b/src/main/java/domain/Line.java @@ -0,0 +1,81 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Line { + private final List points; + + public Line(List points) { + this.points = points; + } + + public static Line generateFirst(LadderWidth width, BooleanGenerator generator) { + List points = new ArrayList<>(); + boolean previous = false; + for (int i = 0; i < width.getIntervalCount(); i++) { + previous = addPoint(points, previous, false, generator); + } + return new Line(points); + } + + public static Line generateNext(LadderWidth width, BooleanGenerator generator, Line previousLine) { + List points = new ArrayList<>(); + boolean isConnectedLeft = false; + for (int i = 0; i < width.getIntervalCount(); i++) { + boolean isConnectedAbove = previousLine.isConnectedAt(i); + isConnectedLeft = addPoint(points, isConnectedLeft, isConnectedAbove, generator); + } + return new Line(points); + } + + private static boolean addPoint(List points, boolean isConnectedLeft, boolean isConnectedAbove, BooleanGenerator gen) { + boolean nextPoint = determineNext(isConnectedLeft, isConnectedAbove, gen); + points.add(nextPoint); + + return nextPoint; + } + + private static boolean determineNext(boolean isConnectedLeft, boolean isConnectedAbove, BooleanGenerator generator + ) { + if (isConnectedLeft || isConnectedAbove) { + return false; + } + + return generator.generate(); + } + + public boolean isConnectedAt(int index) { + return points.get(index); + } + + public Position move(Position position) { + int currentIndex = position.getValue(); + if (canMoveLeft(currentIndex)) { + return position.moveLeft(); + } + if (canMoveRight(currentIndex)) { + return position.moveRight(); + } + return position; + } + + private boolean canMoveLeft(int currentIndex) { + if (currentIndex <= 0) { + return false; + } + return points.get(currentIndex - 1); + } + + private boolean canMoveRight(int currentIndex) { + if (currentIndex >= points.size()) { + return false; + } + return points.get(currentIndex); + } + + public List getPoints() { + return Collections.unmodifiableList(points); + } +} diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java new file mode 100644 index 00000000..01bdc9e8 --- /dev/null +++ b/src/main/java/domain/Player.java @@ -0,0 +1,23 @@ +package domain; + +public class Player { + private final PlayerName name; + private final Reward reward; + + public Player(PlayerName name, Reward reward) { + this.name = name; + this.reward = reward; + } + + public boolean hasName(String targetName) { + return this.name.equals(new PlayerName(targetName)); + } + + public PlayerName getName() { + return name; + } + + public Reward getReward() { + return reward; + } +} diff --git a/src/main/java/domain/PlayerName.java b/src/main/java/domain/PlayerName.java new file mode 100644 index 00000000..cac2edf8 --- /dev/null +++ b/src/main/java/domain/PlayerName.java @@ -0,0 +1,32 @@ +package domain; + +import java.util.Objects; + +public class PlayerName { + private static final int MAX_LENGTH = 5; + private final String value; + + public PlayerName(String value) { + if (value.length() > MAX_LENGTH) { + throw new IllegalArgumentException("이름은 5자를 초과할 수 없습니다."); + } + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlayerName that = (PlayerName) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java new file mode 100644 index 00000000..ecdcbbc1 --- /dev/null +++ b/src/main/java/domain/Players.java @@ -0,0 +1,24 @@ +package domain; + +import java.util.Collections; +import java.util.List; + +public class Players { + private final List names; + + public Players(List names) { + this.names = names; + } + + public int size() { + return names.size(); + } + + public PlayerName getName(int index) { + return names.get(index); + } + + public List getNames() { + return Collections.unmodifiableList(names); + } +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java new file mode 100644 index 00000000..a8c0f2ba --- /dev/null +++ b/src/main/java/domain/Position.java @@ -0,0 +1,33 @@ +package domain; +public class Position { + private final int value; + + public Position(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public Position moveLeft() { + return new Position(value - 1); + } + + public Position moveRight() { + return new Position(value + 1); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Position position = (Position) o; + return value == position.value; + } + + @Override + public int hashCode() { + return value; + } +} diff --git a/src/main/java/domain/RandomBooleanGenerator.java b/src/main/java/domain/RandomBooleanGenerator.java new file mode 100644 index 00000000..857e12b5 --- /dev/null +++ b/src/main/java/domain/RandomBooleanGenerator.java @@ -0,0 +1,12 @@ +package domain; + +import java.util.Random; + +public class RandomBooleanGenerator implements BooleanGenerator { + private static final Random RANDOM = new Random(); + + @Override + public boolean generate() { + return RANDOM.nextBoolean(); + } +} diff --git a/src/main/java/domain/Reward.java b/src/main/java/domain/Reward.java new file mode 100644 index 00000000..f97829ed --- /dev/null +++ b/src/main/java/domain/Reward.java @@ -0,0 +1,16 @@ +package domain; +public class Reward { + private static final int MAX_LENGTH = 5; + private final String value; + + public Reward(String value) { + if (value.length() > MAX_LENGTH) { + throw new IllegalArgumentException("결과는 5자를 초과할 수 없습니다."); + } + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/domain/Rewards.java b/src/main/java/domain/Rewards.java new file mode 100644 index 00000000..8ecf6bc5 --- /dev/null +++ b/src/main/java/domain/Rewards.java @@ -0,0 +1,24 @@ +package domain; + +import java.util.Collections; +import java.util.List; + +public class Rewards { + private final List items; + + public Rewards(List items) { + this.items = items; + } + + public int size() { + return items.size(); + } + + public Reward getReward(int index) { + return items.get(index); + } + + public List getItems() { + return Collections.unmodifiableList(items); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..5eeae536 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,62 @@ +package view; + +import domain.PlayerName; +import domain.Players; +import domain.Reward; +import domain.Rewards; + +import java.util.Scanner; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class InputView { + private static final Scanner SCANNER = new Scanner(System.in); + + public Players readPlayers() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + String input = SCANNER.nextLine(); + validateInputFormat(input); + return new Players(parseNames(input)); + } + + private List parseNames(String input) { + return Arrays.stream(input.split(",")) + .map(String::trim) + .map(PlayerName::new) + .collect(Collectors.toList()); + } + + public Rewards readRewards() { + System.out.println("\n실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); + String input = SCANNER.nextLine(); + validateInputFormat(input); + return new Rewards(parseRewards(input)); + } + + private List parseRewards(String input) { + return Arrays.stream(input.split(",")) + .map(String::trim) + .map(Reward::new) + .collect(Collectors.toList()); + } + + private void validateInputFormat(String input) { + if (input == null || input.trim().isEmpty()) { + throw new IllegalArgumentException("입력값이 비어있습니다."); + } + if (input.startsWith(",") || input.endsWith(",")) { + throw new IllegalArgumentException("입력값은 쉼표(,)로 시작하거나 끝날 수 없습니다."); + } + } + + public int readHeight() { + System.out.println("\n최대 사다리 높이는 몇 개인가요?"); + return Integer.parseInt(SCANNER.nextLine().trim()); + } + + public String readTargetPerson() { + System.out.println("\n결과를 보고 싶은 사람은?"); + return SCANNER.nextLine().trim(); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..498be687 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,64 @@ +package view; +import domain.*; + +import java.util.stream.Collectors; + +public class OutputView { + private static final String VERTICAL_LINE = "|"; + private static final String CONNECTED_LINE = "-----"; + private static final String DISCONNECTED_LINE = " "; + + public void printLadderBoard(Players players, Ladder ladder, Rewards rewards) { + System.out.println("\n사다리 결과\n"); + printNames(players); + ladder.getLines().forEach(this::printLine); + printRewards(rewards); + } + + private void printNames(Players players) { + String names = players.getNames().stream() + .map(name -> String.format("%-6s", name.getValue())) + .collect(Collectors.joining()); + System.out.println(names); + } + + private void printRewards(Rewards rewards) { + String items = rewards.getItems().stream() + .map(reward -> String.format("%-6s", reward.getValue())) + .collect(Collectors.joining()); + System.out.println(items); + } + + private void printLine(Line line) { + StringBuilder builder = new StringBuilder(); + builder.append(VERTICAL_LINE); + line.getPoints().forEach(point -> appendPoint(builder, point)); + System.out.println(builder.toString()); + } + + private void appendPoint(StringBuilder builder, boolean isConnected) { + builder.append(getLineShape(isConnected)); + builder.append(VERTICAL_LINE); + } + + private String getLineShape(boolean isConnected) { + if (isConnected) { + return CONNECTED_LINE; + } + return DISCONNECTED_LINE; + } + + public void printSingleResult(Player player) { + System.out.println("\n실행 결과"); + System.out.println(player.getReward().getValue()); + } + + public void printAllResults(GameResult gameResult) { + System.out.println("\n실행 결과"); + gameResult.getAll().forEach(this::printFormattedResult); + } + + private void printFormattedResult(Player player) { + System.out.println(player.getName().getValue() + " : " + player.getReward().getValue()); + } +} diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java new file mode 100644 index 00000000..a7c1e222 --- /dev/null +++ b/src/test/java/domain/GameResultTest.java @@ -0,0 +1,28 @@ +package domain; + +import org.junit.jupiter.api.Test; +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +class GameResultTest { + @Test + void 존재하는_이름으로_검색하면_해당_플레이어를_반환한다() { + Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); + GameResult gameResult = new GameResult(List.of(pobi)); + + assertThat(gameResult.findByName("pobi")).isEqualTo(pobi); + } + + @Test + void 존재하지_않는_이름으로_검색하면_예외가_발생한다() { + Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); + GameResult gameResult = new GameResult(List.of(pobi)); + + assertThatThrownBy(() -> gameResult.findByName("crong")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("존재하지 않는 사람입니다."); + } + +} diff --git a/src/test/java/domain/LadderGeneratorTest.java b/src/test/java/domain/LadderGeneratorTest.java new file mode 100644 index 00000000..e3a6e13a --- /dev/null +++ b/src/test/java/domain/LadderGeneratorTest.java @@ -0,0 +1,30 @@ +package domain; + +import org.assertj.core.api.AssertionsForInterfaceTypes; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + + +class LadderGeneratorTest { + @Test + void 빈_공간_발생_시_사다리가_재생성된다() { + BooleanGenerator customGenerator = new BooleanGenerator() { + private int callCount = 0; + + @Override + public boolean generate() { + callCount++; + // 폭이 4(간격 3)이고 높이가 2일 때, 1회 생성 시 6번(3 * 2) 호출됨 + // 첫 6번은 false를 반환하여 모든 간격이 빈 상태를 유도 + // 두 번째 시도부터 true를 반환하여 정상 생성 + return callCount > 6; + } + }; + + Ladder ladder = LadderGenerator.generate(new LadderWidth(4), new LadderHeight(2), customGenerator); + + AssertionsForInterfaceTypes.assertThat(ladder.getLines()).hasSize(2); + assertThat(ladder.getLines().get(0).isConnectedAt(0)).isTrue(); + } + +} diff --git a/src/test/java/domain/LadderTest.java b/src/test/java/domain/LadderTest.java new file mode 100644 index 00000000..a1762b3d --- /dev/null +++ b/src/test/java/domain/LadderTest.java @@ -0,0 +1,25 @@ +package domain; + +import org.junit.jupiter.api.Test; +import java.util.List; +import static org.assertj.core.api.Assertions.*; + +class LadderTest { + + @Test + void 정상적인_사다리를_실행하면_계산된_결과를_반환한다() { + // given + Line line1 = new Line(List.of(true, false)); // 0-1 연결 + Line line2 = new Line(List.of(false, true)); // 1-2 연결 + Ladder ladder = new Ladder(List.of(line1, line2)); + LadderWidth width = new LadderWidth(3); + + // when + LadderResult result = ladder.play(width); + + // then + assertThat(result.getEndPosition(new Position(0))).isEqualTo(new Position(2)); + assertThat(result.getEndPosition(new Position(1))).isEqualTo(new Position(0)); + assertThat(result.getEndPosition(new Position(2))).isEqualTo(new Position(1)); + } +} diff --git a/src/test/java/domain/LineTest.java b/src/test/java/domain/LineTest.java new file mode 100644 index 00000000..51c38cd2 --- /dev/null +++ b/src/test/java/domain/LineTest.java @@ -0,0 +1,29 @@ +package domain; + +import org.junit.jupiter.api.Test; +import java.util.List; +import static org.assertj.core.api.Assertions.*; + +class LineTest { + + @Test + void 왼쪽이_연결되어_있으면_왼쪽으로_이동한다() { + Line line = new Line(List.of(true, false)); + Position current = new Position(1); + assertThat(line.move(current)).isEqualTo(new Position(0)); + } + + @Test + void 오른쪽이_연결되어_있으면_오른쪽으로_이동한다() { + Line line = new Line(List.of(true, false)); + Position current = new Position(0); + assertThat(line.move(current)).isEqualTo(new Position(1)); + } + + @Test + void 양쪽_모두_연결되어_있지_않으면_그대로_머문다() { + Line line = new Line(List.of(false, false)); + Position current = new Position(1); + assertThat(line.move(current)).isEqualTo(new Position(1)); + } +} diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java new file mode 100644 index 00000000..717f6606 --- /dev/null +++ b/src/test/java/domain/PositionTest.java @@ -0,0 +1,19 @@ +package domain; + +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; + +class PositionTest { + + @Test + void 왼쪽으로_이동하면_값이_1_감소한다() { + Position position = new Position(1); + assertThat(position.moveLeft()).isEqualTo(new Position(0)); + } + + @Test + void 오른쪽으로_이동하면_값이_1_증가한다() { + Position position = new Position(1); + assertThat(position.moveRight()).isEqualTo(new Position(2)); + } +}