diff --git a/README.md b/README.md new file mode 100644 index 00000000..50da2c8a --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# 사다리 - 함수형 프로그래밍 + +## 네이버 사다리 게임 분석 +1. 인원수를 입력한다. +2. 인원수 만큼 이름과 당첨 항목을 입력한다. +3. 사다리를 그린다. +4. 사다리결과를 반환한다. + +## 1단계 - 요구사항 +- 사다리는 4x4 사이즈로 유지된다. +- 사다리 중간점은 중첩될 수 없다. + +## 1단계 구현 방법 고민 +1단계 같은경우 4x4 사이즈의 고정된 값을 가진 사다리를 만든다. + +사다리 전체의 정보를 가진 Ladder 객체는 내부에 가로줄 하나 하나의 정보를 담도록 해준다. +그렇다면 4x4의 경우 width가 4인 가로줄을 총 4개를 가지게 된다. + +그리고 각각의 가로줄은 Line으로 정의한다. Line은 내부에 사이사이에 연결점을 체크한다. + +예를 들어, 4를 기준으로 생각 했을 때, 출발하는 사람들은 총 4명, 4명이라면 줄을 나누는 경우 3가지가 될 것이다. + +그렇기 때문에 width - 1을 기준으로 내부에 boolean 리스트를 가진다 + +boolean 리스트는 바로 0번째가 true인 경우 - 뒤에 오는 두번째, 즉 2번 유저와 3번 유저의 사이에 오는 사다리는 true가 될 수 없다. + +connect를 랜덤으로 만드는 과정은 다음과 같은 과정을 따르게 된다. +- for문을 통한 반복으로 List에 값 작성 +- i가 0번째 라면, random generate를 통해 값을 추출하고 정해진 값에 따라 true, false를 넣는다. +- 그 이후 부터는 random generate를 하기 전에, 바로 앞 boolean 값이 true라면 반드시 false가 오고 +- false라면 random generate이후 로직을 진행한다. + +## 2단계 - 요구사항 +- 사다리는 크기를 입력받아 생성이 가능하다. + +## 2단계 구현 방법 고민 +- 2단계는 InputView를 통해 width와 height를 입력받게되면 쉽게 풀린다고 생각했습니다. + +## 3단계 - 요구사항 +- 사다리의 시작지점과 도착지점을 출력한다. + +## 3단계 구현 방법 고민 +- 일단 사다리를 가지는 사다리게임 객체를 생성 +- 사다리 게임의 진행 순서는 다음과 같이 해결해야됨. + +1. 사다리게임의 width는 곧 사다리 게임 참여자의 숫자와 같음 +2. 사다리게임이 실행되면 0번째 인덱스 부터시작 +3. 0번째 인덱스는 좌측으로 갈수 없음 우측에 길이있는지 검사 +4. 길이 없다면 그대로 유지후 다음 과정 수행 +5. 우측에 길이 있다면 현재 position + 1 +6. 좌측에 길이 있는 경우 position - 1 +7. 이 반복문을 height만큼 완료하고 완료된 값을 map에 저장 +8. map은 startindex - finalindex로 구성됨 +9. 결과를 OutputView에서 print해줌 \ No newline at end of file diff --git a/src/main/java/LadderMain.java b/src/main/java/LadderMain.java new file mode 100644 index 00000000..1eb8a4a5 --- /dev/null +++ b/src/main/java/LadderMain.java @@ -0,0 +1,10 @@ +import controller.LadderController; + +public class LadderMain { + + public static void main(String[] args) { + final LadderController ladderController = new LadderController(); + + ladderController.run(); + } +} diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java new file mode 100644 index 00000000..0572aaa8 --- /dev/null +++ b/src/main/java/controller/LadderController.java @@ -0,0 +1,58 @@ +package controller; + +import domain.*; + +import java.util.ArrayList; +import java.util.List; +import ui.InputView; +import ui.OutputView; +import util.InputParser; + +public class LadderController { + + public void run() { + final Players players = inputPlayers(); + final Rewards rewards = inputRewards(); + final int height = InputView.inputLadderHeight(); + final BooleanGenerator randomBooleanGenerator = new RandomBooleanGenerator(); + + final LadderGame game = createLadderGame(players, rewards, height, randomBooleanGenerator); + final LadderResult results = game.run(players, rewards); + + printResults(players, rewards, game, results); + } + + private Players inputPlayers() { + final String playersString = InputView.inputPlayers(); + return InputParser.parsePlayers(playersString); + } + + private Rewards inputRewards() { + final String rewardString = InputView.inputReward(); + return InputParser.parseRewards(rewardString); + } + + private LadderGame createLadderGame(final Players players, final Rewards rewards, final int height, final BooleanGenerator booleanGenerator) { + final int width = players.size(); + final List lines = createLines(width, height, booleanGenerator); + + final Ladder ladder = Ladder.of(lines); + + return new LadderGame(ladder, rewards); + } + + private List createLines(final int width, final int height, final BooleanGenerator booleanGenerator) { + List lines = new ArrayList<>(); + + for (int i = 0; i < height; i++) { + lines.add(new Line(width, booleanGenerator)); + } + + return lines; + } + + private void printResults(final Players players, final Rewards rewards, final LadderGame game, final LadderResult results) { + OutputView.printGameResult(players, game.getLadder(), rewards); + OutputView.printResults(results); + } +} diff --git a/src/main/java/domain/BooleanGenerator.java b/src/main/java/domain/BooleanGenerator.java new file mode 100644 index 00000000..b8ac7ede --- /dev/null +++ b/src/main/java/domain/BooleanGenerator.java @@ -0,0 +1,7 @@ +package domain; + +@FunctionalInterface +public interface BooleanGenerator { + + boolean nextBoolean(); +} diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java new file mode 100644 index 00000000..79951575 --- /dev/null +++ b/src/main/java/domain/Ladder.java @@ -0,0 +1,58 @@ +package domain; + +import java.util.List; + +public class Ladder { + + private final List lines; + + private Ladder(final List lines) { + validateLines(lines); + + this.lines = lines; + } + + private void validateLines(final List lines) { + validateEmpty(lines); + validateWidth(lines); + validateHeight(lines); + } + + public static Ladder of(final List lines) { + return new Ladder(lines); + } + + public List lines() { + return lines; + } + + public int width() { + return lines().get(0).size() + 1; + } + + private static void validateEmpty(final List lines) { + if (lines.isEmpty()) { + throw new RuntimeException("빈 라인은 들어올 수 없습니다."); + } + } + + private void validateWidth(List lines) { + int firstLineWidth = lines.get(0).size(); + + if (firstLineWidth < 1) { + throw new RuntimeException("사다리 폭은 최소 2 이상이어야 합니다."); + } + + for (Line line : lines) { + if (line.size() != firstLineWidth) { + throw new RuntimeException("모든 라인의 폭이 동일해야 합니다."); + } + } + } + + private void validateHeight(List lines) { + if (lines.isEmpty()) { + throw new RuntimeException("사다리 높이는 최소 1 이상이어야 합니다."); + } + } +} diff --git a/src/main/java/domain/LadderGame.java b/src/main/java/domain/LadderGame.java new file mode 100644 index 00000000..90b41022 --- /dev/null +++ b/src/main/java/domain/LadderGame.java @@ -0,0 +1,67 @@ +package domain; + +import java.util.HashMap; +import java.util.Map; + +public class LadderGame { + + private final Ladder ladder; + + public LadderGame(final Ladder ladder, final Rewards rewards) { + validateLadderGame(ladder, rewards); + this.ladder = ladder; + } + + public LadderResult run(Players players, Rewards rewards) { + Map results = new HashMap<>(); + + int width = ladder.width(); + + for (int startPosition = 0; startPosition < width; startPosition++) { + int finalPosition = runSinglePath(startPosition); + results.put(startPosition, finalPosition); + } + + return new LadderResult(results, players, rewards); + } + + public Ladder getLadder() { + return ladder; + } + + private int runSinglePath(final int startPosition) { + int currentPosition = startPosition; + + for (Line line : ladder.lines()) { + currentPosition = movePosition(currentPosition, line); + } + + return currentPosition; + } + + private boolean canMoveRight(final int position, final Line line) { + return position >= 0 && position < line.size() && line.isConnected(position); + } + + private boolean canMoveLeft(final int position, final Line line) { + return position > 0 && position <= line.size() && line.isConnected(position - 1); + } + + private int movePosition(final int currentPosition, final Line line) { + if (canMoveRight(currentPosition, line)) { + return currentPosition + 1; + } + + if (canMoveLeft(currentPosition, line)) { + return currentPosition - 1; + } + + return currentPosition; + } + + private void validateLadderGame(final Ladder ladder, final Rewards rewards) { + if (ladder.width() != rewards.size()) { + throw new RuntimeException("사용자 수와 리워드 수는 동일해야 합니다."); + } + } +} diff --git a/src/main/java/domain/LadderResult.java b/src/main/java/domain/LadderResult.java new file mode 100644 index 00000000..341c0e8a --- /dev/null +++ b/src/main/java/domain/LadderResult.java @@ -0,0 +1,37 @@ +package domain; + +import java.util.Map; + +public record LadderResult(Map results, Players players, Rewards rewards) { + + public String getReward(final String targetPlayerInput) { + final Player player = new Player(targetPlayerInput); + final int playerIndex = players.findPlayerIndexByName(player); + + final int resultIndex = getResult(playerIndex); + + return rewards.getReward(resultIndex); + } + + public int getResult(int index) { + if (results.get(index) == null) { + throw new RuntimeException("값이 존재하지 않습니다."); + } + return results.get(index); + } + + @Override + public Map results() { + return results; + } + + @Override + public Players players() { + return players; + } + + @Override + public Rewards rewards() { + return rewards; + } +} diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java new file mode 100644 index 00000000..801a76cc --- /dev/null +++ b/src/main/java/domain/Line.java @@ -0,0 +1,48 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class Line { + + private final List connects; + + public Line(final int width, final BooleanGenerator booleanGenerator) { + this.connects = new ArrayList<>(); + + for (int i = 0; i < width - 1; i++) { + final boolean canConnect = !isPreviousConnected(); + final boolean connectStatus = canConnect && booleanGenerator.nextBoolean(); + connects.add(connectStatus); + } + } + + public Line(final List connects) { + validateConnects(connects); + this.connects = connects; + } + + private boolean isPreviousConnected() { + if (connects.isEmpty()) { + return false; + } + + return connects.get(connects.size() - 1); + } + + public boolean isConnected(final int index) { + return connects.get(index); + } + + public int size() { + return connects.size(); + } + + private void validateConnects(List connections) { + for (int i = 0; i < connections.size() - 1; i++) { + if (connections.get(i) && connections.get(i + 1)) { + throw new RuntimeException("연속된 연결은 허용되지 않습니다."); + } + } + } +} diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java new file mode 100644 index 00000000..3108a550 --- /dev/null +++ b/src/main/java/domain/Player.java @@ -0,0 +1,14 @@ +package domain; + +public record Player(String name) { + + public Player { + validateName(name); + } + + private void validateName(final String name) { + if (name.length() > 5) { + throw new RuntimeException("이름은 5글자를 초과할 수 없습니다."); + } + } +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java new file mode 100644 index 00000000..7510250a --- /dev/null +++ b/src/main/java/domain/Players.java @@ -0,0 +1,41 @@ +package domain; + +import java.util.Iterator; +import java.util.List; + +public record Players(List players) implements Iterable { + + public Players { + validatePlayers(players); + } + + public int findPlayerIndexByName(final Player player) { + validateContainsPlayer(player); + return players.indexOf(player); + } + + public int size() { + return players.size(); + } + + @Override + public Iterator iterator() { + return players.iterator(); + } + + private void validatePlayers(final List players) { + if (players == null) { + throw new RuntimeException("플레이어 목록은 null일 수 없습니다."); + } + } + + private void validateContainsPlayer(final Player player) { + if (player == null) { + throw new RuntimeException("검색할 플레이어는 null일 수 없습니다."); + } + + if (!players.contains(player)) { + throw new RuntimeException("존재하지 않는 플레이어 입니다."); + } + } +} diff --git a/src/main/java/domain/RandomBooleanGenerator.java b/src/main/java/domain/RandomBooleanGenerator.java new file mode 100644 index 00000000..145e7fed --- /dev/null +++ b/src/main/java/domain/RandomBooleanGenerator.java @@ -0,0 +1,13 @@ +package domain; + +import java.util.Random; + +public class RandomBooleanGenerator implements BooleanGenerator{ + + private static final Random random = new Random(); + + @Override + public boolean nextBoolean() { + return random.nextBoolean(); + } +} diff --git a/src/main/java/domain/Rewards.java b/src/main/java/domain/Rewards.java new file mode 100644 index 00000000..1ce0fb41 --- /dev/null +++ b/src/main/java/domain/Rewards.java @@ -0,0 +1,14 @@ +package domain; + +import java.util.List; + +public record Rewards(List rewards) { + + public String getReward(final int index) { + return rewards.get(index); + } + + public int size() { + return rewards.size(); + } +} diff --git a/src/main/java/ui/InputView.java b/src/main/java/ui/InputView.java new file mode 100644 index 00000000..eb73cb31 --- /dev/null +++ b/src/main/java/ui/InputView.java @@ -0,0 +1,32 @@ +package ui; + +import java.util.Scanner; + +public class InputView { + + private static final Scanner scanner = new Scanner(System.in); + + private InputView() { + + } + + public static int inputLadderHeight() { + System.out.println("사다리의 높이는 몇 개인가요?"); + return Integer.parseInt(scanner.nextLine()); + } + + public static String inputPlayers() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + return scanner.nextLine().trim(); + } + + public static String inputReward() { + System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); + return scanner.nextLine().trim(); + } + + public static String inputResultTarget() { + System.out.println("결과를 보고 싶은 사람은?"); + return scanner.nextLine().trim(); + } +} diff --git a/src/main/java/ui/OutputView.java b/src/main/java/ui/OutputView.java new file mode 100644 index 00000000..0d1408a1 --- /dev/null +++ b/src/main/java/ui/OutputView.java @@ -0,0 +1,100 @@ +package ui; + +import domain.Ladder; +import domain.LadderResult; +import domain.Line; +import domain.Player; +import domain.Players; +import domain.Rewards; +import java.util.List; + +public class OutputView { + + public static final String VERTICAL_LINE = "|"; + public static final String CONNECTED_LINE = "-----"; + public static final String BLANK_SPACE = " "; + public static final String ALL = "all"; + + private OutputView() { + + } + + public static void printGameResult(Players players, Ladder ladder, Rewards rewards) { + System.out.println("사다리 결과 \n"); + + printPlayersName(players); + printLadder(ladder); + printRewards(rewards); + } + + public static void printResults(LadderResult results) { + while (true) { + final String targetPlayerInput = InputView.inputResultTarget(); + + if (targetPlayerInput.equals(ALL)) { + OutputView.printAllResults(results); + break; + } + + final String reward = results.getReward(targetPlayerInput); + + OutputView.printReward(reward); + } + } + + private static void printReward(final String reward) { + System.out.println("실행 결과"); + System.out.println(reward); + } + + private static void printAllResults(LadderResult results) { + System.out.println("실행 결과"); + for (int i = 0; i < results.players().size(); i++) { + Player player = results.players().players().get(i); + int resultIndex = results.getResult(i); + String reward = results.rewards().getReward(resultIndex); + System.out.println(player.name() + " : " + reward); + } + } + + private static void printPlayersName(Players players) { + for (Player player : players) { + System.out.print(player.name() + "\t"); + } + System.out.println(); + } + + private static void printLadder(final Ladder ladder) { + final StringBuilder ladderBuilder = new StringBuilder(); + + for (Line line : ladder.lines()) { + final String lineString = printSingleLine(line); + ladderBuilder.append(lineString); + } + + System.out.print(ladderBuilder); + } + + private static void printRewards(Rewards rewards) { + final List item = rewards.rewards(); + for (String reward : item) { + System.out.print(reward + "\t"); + } + System.out.println(); + } + + private static String printSingleLine(final Line line) { + final StringBuilder lineBuilder = new StringBuilder(); + + lineBuilder.append(VERTICAL_LINE); + + for (int i = 0; i < line.size(); i++) { + lineBuilder.append(line.isConnected(i) ? CONNECTED_LINE : BLANK_SPACE); + lineBuilder.append(VERTICAL_LINE); + } + + lineBuilder.append("\n"); + + return lineBuilder.toString(); + } +} diff --git a/src/main/java/util/InputParser.java b/src/main/java/util/InputParser.java new file mode 100644 index 00000000..db8e356a --- /dev/null +++ b/src/main/java/util/InputParser.java @@ -0,0 +1,25 @@ +package util; + +import domain.Player; +import domain.Players; +import domain.Rewards; + +import java.util.Arrays; + +public class InputParser { + + private InputParser() { + } + + public static Players parsePlayers(String players) { + return new Players(Arrays.stream(players.split(",")) + .map(player -> new Player(player.trim())) + .toList()); + } + + public static Rewards parseRewards(String rewards) { + return new Rewards(Arrays.stream(rewards.split(",")) + .map(String::trim) + .toList()); + } +} diff --git a/src/test/java/domain/BooleanGeneratorTest.java b/src/test/java/domain/BooleanGeneratorTest.java new file mode 100644 index 00000000..d3884a20 --- /dev/null +++ b/src/test/java/domain/BooleanGeneratorTest.java @@ -0,0 +1,26 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +class BooleanGeneratorTest { + + @Test + void 항상_true_반환() { + BooleanGenerator alwaysTrue = () -> true; + + for (int i = 0; i < 10; i++) { + assertThat(alwaysTrue.nextBoolean()).isTrue(); + } + } + + @Test + void 항상_false_반환() { + BooleanGenerator alwaysFalse = () -> false; + + for (int i = 0; i < 10; i++) { + assertThat(alwaysFalse.nextBoolean()).isFalse(); + } + } +} \ No newline at end of file diff --git a/src/test/java/domain/LadderGameTest.java b/src/test/java/domain/LadderGameTest.java new file mode 100644 index 00000000..86c2bbbd --- /dev/null +++ b/src/test/java/domain/LadderGameTest.java @@ -0,0 +1,50 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +class LadderGameTest { + + @Test + void 연결이_없는_사다리_테스트() { + List lines = List.of( + new Line(List.of(false, false, false)), + new Line(List.of(false, false, false)), + new Line(List.of(false, false, false)) + ); + + Ladder ladder = Ladder.of(lines); + Players players = new Players(Stream.of("kang", "min", "hyuk").map(Player::new).toList()); + Rewards rewards = new Rewards(List.of("1000","2000","3000","4000")); + LadderGame game = new LadderGame(ladder, rewards); + + LadderResult result = game.run(players, rewards); + + assertThat(result.results()).hasSize(4); + assertThat(result.getResult(0)).isEqualTo(0); + assertThat(result.getResult(1)).isEqualTo(1); + assertThat(result.getResult(2)).isEqualTo(2); + assertThat(result.getResult(3)).isEqualTo(3); + } + + @Test + void 모든_연결이_있는_사다리_테스트() { + List lines = List.of( + new Line(List.of(true, false, true)) + ); + + Ladder ladder = Ladder.of(lines); + Players players = new Players(Stream.of("kang", "min", "hyuk").map(Player::new).toList()); + Rewards rewards = new Rewards(List.of("1000","2000","3000","4000")); + LadderGame game = new LadderGame(ladder, rewards); + + LadderResult result = game.run(players, rewards); + + assertThat(result.results()).hasSize(4); + } +} \ No newline at end of file diff --git a/src/test/java/domain/LadderResultTest.java b/src/test/java/domain/LadderResultTest.java new file mode 100644 index 00000000..8ff834d9 --- /dev/null +++ b/src/test/java/domain/LadderResultTest.java @@ -0,0 +1,48 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class LadderResultTest { + + private Players players; + private Rewards rewards; + + @BeforeEach + void setUp() { + this.players = new Players(Stream.of("kang", "min", "hyuk").map(Player::new).toList()); + this.rewards = new Rewards(List.of("1000", "2000", "꽝")); + } + + @Test + void 정상적인_인덱스_결과_조회() { + Map results = new HashMap<>(); + results.put(0, 2); + results.put(1, 0); + results.put(2, 3); + results.put(3, 1); + + LadderResult ladderResult = new LadderResult(results, players, rewards); + + assertThat(ladderResult.getResult(0)).isEqualTo(2); + assertThat(ladderResult.getResult(1)).isEqualTo(0); + assertThat(ladderResult.getResult(2)).isEqualTo(3); + assertThat(ladderResult.getResult(3)).isEqualTo(1); + } + + @Test + void 존재하지_않는_인덱스_조회() { + Map results = Map.of(0, 1, 1, 0); + LadderResult ladderResult = new LadderResult(results, players, rewards); + + assertThatThrownBy(() -> ladderResult.getResult(2)).isInstanceOf(RuntimeException.class); + } +} \ No newline at end of file diff --git a/src/test/java/domain/LadderTest.java b/src/test/java/domain/LadderTest.java new file mode 100644 index 00000000..775c9a19 --- /dev/null +++ b/src/test/java/domain/LadderTest.java @@ -0,0 +1,103 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import java.util.ArrayList; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class LadderTest { + + @Nested + @DisplayName("사다리 생성 테스트 - 성공 케이스") + class NormalLadderTest { + + @ParameterizedTest + @ValueSource(ints = {2, 3, 4, 5, 10}) + void 사다리_생성_테스트(final int width) { + int height = 5; + List lines = createTestLines(width - 1, height); + + Ladder ladder = Ladder.of(lines); + + assertThat(ladder.lines()).hasSize(height); + assertThat(ladder.lines()).isNotNull(); + + for (Line line : ladder.lines()) { + assertThat(line.size()).isEqualTo(width - 1); + } + } + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3, 5, 10}) + void 다양한_높이_사다리_생성(final int height) { + int width = 4; + List lines = createTestLines(width - 1, height); + + Ladder ladder = Ladder.of(lines); + + assertThat(ladder.lines()).hasSize(height); + } + + @Test + void 최소_크기_사다리_생성() { + List lines = List.of(new Line(List.of(true))); + + Ladder ladder = Ladder.of(lines); + + assertThat(ladder.lines()).hasSize(1); + assertThat(ladder.lines().get(0).size()).isEqualTo(1); + } + + private List createTestLines(int connectionCount, int height) { + List lines = new ArrayList<>(); + List connections = new ArrayList<>(); + + for (int i = 0; i < connectionCount; i++) { + connections.add(i % 2 == 0); + } + + for (int i = 0; i < height; i++) { + lines.add(new Line(connections)); + } + return lines; + } + } + + @Nested + @DisplayName("사다리 생성 테스트 - 실패 케이스") + class FailureLadderTest { + + @Test + void 빈_라인_리스트일_때_예외_발생() { + List emptyLines = List.of(); + + assertThatThrownBy(() -> Ladder.of(emptyLines)) + .isInstanceOf(RuntimeException.class); + } + + @Test + void 폭이_너무_작을_때_예외_발생() { + List lines = List.of(new Line(List.of())); + + assertThatThrownBy(() -> Ladder.of(lines)) + .isInstanceOf(RuntimeException.class); + } + + @Test + void 라인들의_폭이_다를_때_예외_발생() { + List lines = List.of( + new Line(List.of(true, false)), + new Line(List.of(false)) + ); + + assertThatThrownBy(() -> Ladder.of(lines)) + .isInstanceOf(RuntimeException.class); + } + } +} \ No newline at end of file diff --git a/src/test/java/domain/LineTest.java b/src/test/java/domain/LineTest.java new file mode 100644 index 00000000..21f5f55f --- /dev/null +++ b/src/test/java/domain/LineTest.java @@ -0,0 +1,61 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class LineTest { + + @ParameterizedTest + @ValueSource(ints = {2, 3, 4, 5, 10}) + void 라인_생성_테스트(final int width) { + // given + BooleanGenerator generator = () -> false; + + // when + final Line line = new Line(width, generator); + + // then + assertThat(line.size()).isEqualTo(width - 1); + assertThat(line).isNotNull(); + } + + @Test + void 모든_연결이_true인_경우_연속_방지() { + BooleanGenerator generatorTrue = () -> true; + + Line line = new Line(4, generatorTrue); + + assertThat(line.isConnected(0)).isTrue(); + assertThat(line.isConnected(1)).isFalse(); + assertThat(line.isConnected(2)).isTrue(); + } + + @Test + void 모든_연결이_false인_경우() { + BooleanGenerator alwaysFalse = () -> false; + + Line line = new Line(4, alwaysFalse); + + for (int i = 0; i < line.size(); i++) { + assertThat(line.isConnected(i)).isFalse(); + } + } + + @Test + void 인덱스_범위_초과_예외_테스트() { + // given + BooleanGenerator generator = () -> false; + final Line line = new Line(4, generator); + + // when & then + assertThatThrownBy(() -> line.isConnected(-1)) + .isInstanceOf(IndexOutOfBoundsException.class); + + assertThatThrownBy(() -> line.isConnected(line.size())) + .isInstanceOf(IndexOutOfBoundsException.class); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java new file mode 100644 index 00000000..f205b1ac --- /dev/null +++ b/src/test/java/domain/PlayerTest.java @@ -0,0 +1,43 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.Test; + +class PlayerTest { + + @Test + void 플레이어_이름이_정상적으로_생성된다() { + String name = "홍길동"; + + Player player = new Player(name); + + assertThat(player.name()).isEqualTo("홍길동"); + } + + @Test + void 플레이어_이름이_5글자_이상이면_예외가_발생한다() { + String longName = "매우긴이름입니다"; + + assertThatThrownBy(() -> new Player(longName)) + .isInstanceOf(RuntimeException.class); + } + + @Test + void 플레이어_이름이_4글자면_정상_생성된다() { + String name = "김철수박"; + + Player player = new Player(name); + + assertThat(player.name()).isEqualTo("김철수박"); + } + + @Test + void 같은_이름의_플레이어는_동일하다() { + Player player1 = new Player("홍길동"); + Player player2 = new Player("홍길동"); + + assertThat(player1).isEqualTo(player2); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java new file mode 100644 index 00000000..066f9c61 --- /dev/null +++ b/src/test/java/domain/PlayersTest.java @@ -0,0 +1,42 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class PlayersTest { + + @Test + void 플레이어_목록이_정상적으로_생성된다() { + List playerList = List.of( + new Player("홍길동"), + new Player("김철수") + ); + + Players players = new Players(playerList); + + assertThat(players.size()).isEqualTo(2); + } + + @Test + void 플레이어_목록이_null이면_예외가_발생한다() { + assertThatThrownBy(() -> new Players(null)) + .isInstanceOf(RuntimeException.class); + } + + @Test + void 플레이어_이름으로_인덱스를_찾는다() { + List playerList = List.of( + new Player("홍길동"), + new Player("김철수") + ); + Players players = new Players(playerList); + Player target = new Player("김철수"); + + int index = players.findPlayerIndexByName(target); + + assertThat(index).isEqualTo(1); + } +} \ No newline at end of file diff --git a/src/test/java/domain/RewardsTest.java b/src/test/java/domain/RewardsTest.java new file mode 100644 index 00000000..48335c06 --- /dev/null +++ b/src/test/java/domain/RewardsTest.java @@ -0,0 +1,28 @@ +package domain; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.Test; + +class RewardsTest { + + @Test + void 보상_목록이_정상적으로_생성된다() { + List rewardList = List.of("꽝", "5000", "3000"); + + Rewards rewards = new Rewards(rewardList); + + assertThat(rewards.getReward(0)).isEqualTo("꽝"); + } + + @Test + void 인덱스로_보상을_조회할_수_있다() { + List rewardList = List.of("꽝", "5000", "3000"); + Rewards rewards = new Rewards(rewardList); + + String reward = rewards.getReward(1); + + assertThat(reward).isEqualTo("5000"); + } +} \ No newline at end of file