diff --git a/README.md b/README.md new file mode 100644 index 00000000..598ec25d --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# ๐Ÿชœ ์‚ฌ๋‹ค๋ฆฌ ํƒ€๊ธฐ ๊ฒŒ์ž„ +์ฐธ๊ฐ€์ž์˜ ์ด๋ฆ„๊ณผ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋žœ๋คํ•œ ์‚ฌ๋‹ค๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , +๊ฐ ์‚ฌ๋žŒ์ด ์–ด๋–ค ๊ฒฐ๊ณผ์— ๋„์ฐฉํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” **์‚ฌ๋‹ค๋ฆฌ ๊ฒŒ์ž„**์ž…๋‹ˆ๋‹ค. + +--- + +## ๐Ÿ•น๏ธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• + +### 1. ์ฐธ์—ฌ์ž ์ด๋ฆ„ ์ž…๋ ฅ +- ์ตœ๋Œ€ 5๊ธ€์ž๊นŒ์ง€ ์ž…๋ ฅ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. +- ์ด๋ฆ„์€ ์‰ผํ‘œ `,`๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ์ž…๋ ฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +- ์ž…๋ ฅํ•œ ์ˆœ์„œ๋Œ€๋กœ ์‚ฌ๋‹ค๋ฆฌ ์‹œ์ž‘ ์œ„์น˜๊ฐ€ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. + +### 2. ์‹คํ–‰ ๊ฒฐ๊ณผ ์ž…๋ ฅ +- ์ฐธ์—ฌ์ž ์ˆ˜์™€ ๊ฐ™์€ ๊ฐœ์ˆ˜์˜ ๊ฒฐ๊ณผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”. +- ์ˆœ์„œ๋Š” ์ด๋ฆ„๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. +- ์ž…๋ ฅํ•œ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ ๊ฒฐ๊ณผ ์œ„์น˜๊ฐ€ ์ง€์ •๋ฉ๋‹ˆ๋‹ค. + +### 3. ์‚ฌ๋‹ค๋ฆฌ ๋†’์ด ์ž…๋ ฅ +- ์‚ฌ๋‹ค๋ฆฌ์˜ ์„ธ๋กœ ์ค„ ์ˆ˜๋ฅผ ์ˆซ์ž๋กœ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”. + +### 4. ์ƒ์„ฑ๋œ ์‚ฌ๋‹ค๋ฆฌ ํ™•์ธ +- ๊ฐ ์ฐธ์—ฌ์ž์˜ ์‹œ์ž‘ ์ง€์ , ์‹คํ–‰ ๊ฒฐ๊ณผ ์œ„์น˜๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. + +### 5. ๊ฒฐ๊ณผ ํ™•์ธ + +- ํŠน์ • ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜๋ฉด ํ•ด๋‹น ์‚ฌ๋žŒ์˜ ๊ฒฐ๊ณผ๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. +- `"all"`์„ ์ž…๋ ฅํ•˜๋ฉด ์ „์ฒด ๊ฒฐ๊ณผ๋ฅผ ํ•œ ๋ฒˆ์— ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. +- `"all"`์„ ์ž…๋ ฅํ•˜๋ฉด ๋ชจ๋“  ์ฐธ์—ฌ์ž์˜ ์ตœ์ข… ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค. + +--- +## ๐Ÿ–ฅ๏ธ ์‹คํ–‰ ์˜ˆ์‹œ +``` +์ฐธ์—ฌํ•  ์‚ฌ๋žŒ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”. (์ด๋ฆ„์€ ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์„ธ์š”) +neo,brown,brie,tommy + +์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”. (๊ฒฐ๊ณผ๋Š” ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์„ธ์š”) +๊ฝ,5000,๊ฝ,3000 + +์ตœ๋Œ€ ์‚ฌ๋‹ค๋ฆฌ ๋†’์ด๋Š” ๋ช‡ ๊ฐœ์ธ๊ฐ€์š”? +5 + +์‚ฌ๋‹ค๋ฆฌ ๊ฒฐ๊ณผ + + neo brown brie tommy + |-----| |-----| + | |-----| | + |-----| | | + | |-----| | + |-----| |-----| + ๊ฝ 5000 ๊ฝ 3000 + +๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์€? +neo + +์‹คํ–‰ ๊ฒฐ๊ณผ +๊ฝ + +๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์€? +all + +์‹คํ–‰ ๊ฒฐ๊ณผ +neo : ๊ฝ +brown : 3000 +brie : ๊ฝ +tommy : 5000 +``` diff --git a/src/main/java/LadderApplication.java b/src/main/java/LadderApplication.java new file mode 100644 index 00000000..af1c3707 --- /dev/null +++ b/src/main/java/LadderApplication.java @@ -0,0 +1,14 @@ +import controller.LadderController; +import view.InputView; +import view.OutputView; + +public class LadderApplication { + + public static void main(String[] args) { + InputView inputview = new InputView(); + OutputView outputview = new OutputView(); + + LadderController ladderController = new LadderController(inputview, outputview); + ladderController.run(); + } +} diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java new file mode 100644 index 00000000..936c7732 --- /dev/null +++ b/src/main/java/controller/LadderController.java @@ -0,0 +1,74 @@ +package controller; + +import domain.*; +import view.InputView; +import view.OutputView; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +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() { + System.out.println("Starting Ladder Game..."); // ์ดˆ๊ธฐ ์ง„์ž… ํ™•์ธ + + Players players = readPlayers(); + ResultItems resultItems = readResultItems(players.count()); + LadderHeight height = inputView.readHeight(); + LadderGame ladderGame = LadderGame.of(players.count(), height, new RandomGenerator()); + + List playerNames = players.extractNames(); + List resultItemNames = resultItems.extractNames(); + outputView.printLadder(playerNames, ladderGame, resultItemNames); + + String requestName = inputView.readResultRequest(); + handleResultRequest(requestName, players, ladderGame, resultItems); + } + + private Players readPlayers() { + List names = inputView.readPlayerNames(); + List players = names.stream() + .map(Player::new) + .toList(); + return new Players(players); + } + + private ResultItems readResultItems(int expectedSize) { + List results = inputView.readResultItems(); + List resultItems = results.stream() + .map(ResultItem::new) + .toList(); + return new ResultItems(resultItems, expectedSize); + } + + private void handleResultRequest(String request, Players players, LadderGame ladder, ResultItems resultItems) { + LadderGameResult gameResult = new LadderGameResult(players, resultItems, ladder); + + while (!request.equals("all")) { + try { + Player player = new Player(request); + outputView.printSingleResult(player.getName(), gameResult.getSingleResultFor(player).getItem()); + } catch (IllegalArgumentException e) { + System.out.println("์ž˜๋ชป๋œ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ๋‹ค์‹œ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”."); + } + request = inputView.readResultRequest(); + } + + Map resultMap = gameResult.getAllResults().entrySet().stream() + .collect(Collectors.toMap( + entry -> entry.getKey().getName(), + entry -> entry.getValue().getItem() + )); + + outputView.printAllResults(resultMap); + } +} diff --git a/src/main/java/domain/LadderGame.java b/src/main/java/domain/LadderGame.java new file mode 100644 index 00000000..dddbc76c --- /dev/null +++ b/src/main/java/domain/LadderGame.java @@ -0,0 +1,24 @@ +package domain; + +import java.util.List; + +public class LadderGame { + + private final LadderLines ladderLines; + + public LadderGame(LadderLines ladderLines) { + this.ladderLines = ladderLines; + } + + public static LadderGame of(int width, LadderHeight height, RandomStrategy strategy) { + return new LadderGame(LadderLines.of(width, height, strategy)); + } + + public int getFinalPosition(int startPosition) { + return ladderLines.getFinalPosition(startPosition); + } + + public List getLadderStructure() { + return ladderLines.getLines(); + } +} diff --git a/src/main/java/domain/LadderGameResult.java b/src/main/java/domain/LadderGameResult.java new file mode 100644 index 00000000..93d01124 --- /dev/null +++ b/src/main/java/domain/LadderGameResult.java @@ -0,0 +1,44 @@ +package domain; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class LadderGameResult { + + private final Map results = new LinkedHashMap<>(); + + public LadderGameResult(Players players, ResultItems resultItems, LadderGame ladder) { + List playerList = players.extractPlayers(); + List resultList = resultItems.extractItems(); + + for (int i = 0; i < playerList.size(); i++) { + int finalPosition = ladder.getFinalPosition(i); + + if (finalPosition >= resultItems.count()) { + throw new IllegalArgumentException("์ตœ์ข… ์œ„์น˜๊ฐ€ ๊ฒฐ๊ณผ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค."); + } + + results.put(playerList.get(i), resultList.get(finalPosition)); + } + } + + public ResultItem getSingleResultFor(Player player) { + if (!results.containsKey(player)) { + throw new IllegalArgumentException("์กด์žฌํ•˜์ง€ ์•Š๋Š” ํ”Œ๋ ˆ์ด์–ด์ž…๋‹ˆ๋‹ค: " + player.getName()); + } + return results.get(player); + } + + public Map getAllResults() { + return results.entrySet() + .stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (e1, e2) -> e1, + LinkedHashMap::new + )); + } +} diff --git a/src/main/java/domain/LadderHeight.java b/src/main/java/domain/LadderHeight.java new file mode 100644 index 00000000..d1b33fdc --- /dev/null +++ b/src/main/java/domain/LadderHeight.java @@ -0,0 +1,12 @@ +package domain; + +public record LadderHeight(int value) { + + private static final int MIN_HEIGHT_VALUE = 1; + + public LadderHeight { + if (value < MIN_HEIGHT_VALUE) { + throw new IllegalArgumentException("์‚ฌ๋‹ค๋ฆฌ์˜ ๋†’์ด๋Š” 1 ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } +} diff --git a/src/main/java/domain/LadderLine.java b/src/main/java/domain/LadderLine.java new file mode 100644 index 00000000..b4722b76 --- /dev/null +++ b/src/main/java/domain/LadderLine.java @@ -0,0 +1,35 @@ +package domain; + +import java.util.List; +import java.util.stream.IntStream; + +public class LadderLine { + + private final List points; + + // ๋ผ์ธ ๊ฒน์นจ ๋กœ์ง ์ˆ˜์ • ํ•„์š” + // ์‚ผํ•ญ ์ œ๊ฑฐ, else ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅ, depth ์ฒดํฌ + public LadderLine(int width, RandomStrategy strategy) { + this.points = List.copyOf(IntStream.range(0, width) + .mapToObj(i -> { + if (i == width - 1) { + return Point.NOT_CONNECTED; + } + return strategy.nextBoolean() ? Point.CONNECTED_RIGHT : Point.NOT_CONNECTED; + }) + .toList()); + } + + public List getPoints() { + return List.copyOf(points); + } + + public int move(int currentPosition) { + if (currentPosition < 0 || currentPosition >= points.size()) { + return currentPosition; + } + + Point currentPoint = points.get(currentPosition); + return currentPoint.move(currentPosition, points.size()); + } +} diff --git a/src/main/java/domain/LadderLines.java b/src/main/java/domain/LadderLines.java new file mode 100644 index 00000000..aaea15d4 --- /dev/null +++ b/src/main/java/domain/LadderLines.java @@ -0,0 +1,35 @@ +package domain; + +import java.util.List; +import java.util.stream.IntStream; + +public class LadderLines { + + private final List lines; + + public LadderLines(List lines) { + this.lines = List.copyOf(lines); + } + + public static LadderLines of(int width, LadderHeight height, RandomStrategy strategy) { + return new LadderLines( + IntStream.range(0, height.value()) + .mapToObj(i -> new LadderLine(width, strategy)) + .toList() + ); + } + + public int getFinalPosition(int startPosition) { + int currentPosition = startPosition; + + for (LadderLine line : lines) { + currentPosition = line.move(currentPosition); + } + + return currentPosition; + } + + public List getLines() { + return List.copyOf(lines); + } +} diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java new file mode 100644 index 00000000..02c1e824 --- /dev/null +++ b/src/main/java/domain/Player.java @@ -0,0 +1,38 @@ +package domain; + +import java.util.Objects; + +public class Player { + + private static final int MAX_NAME_LENGTH = 5; + + private final String name; + + public Player(String name) { + validateInput(name); + this.name = name; + } + + private void validateInput(String name) { + if (name.isEmpty() || name.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException("์ฐธ์—ฌํ•  ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์€ 1์ž ์ด์ƒ " + MAX_NAME_LENGTH + "์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Player player = (Player) o; + return Objects.equals(name, player.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java new file mode 100644 index 00000000..7bdd1c74 --- /dev/null +++ b/src/main/java/domain/Players.java @@ -0,0 +1,35 @@ +package domain; + +import java.util.List; + +public class Players { + + private static final int MIN_PLAYERS_COUNT = 1; + + private final List players; + + public Players(List players) { + validateCount(players); + this.players = players; + } + + private void validateCount(List players) { + if (players.isEmpty()) { + throw new IllegalArgumentException("์ฐธ์—ฌ ์ธ์›์€ ์ตœ์†Œ " + MIN_PLAYERS_COUNT + "๋ช… ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."); + } + } + + public int count() { + return players.size(); + } + + public List extractPlayers() { + return List.copyOf(players); + } + + public List extractNames() { + return players.stream() + .map(Player::getName) + .toList(); + } +} diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java new file mode 100644 index 00000000..235ecb2c --- /dev/null +++ b/src/main/java/domain/Point.java @@ -0,0 +1,25 @@ +package domain; + +import java.util.function.BiFunction; + +public enum Point { + + // ์™ผ์ชฝ์œผ๋กœ ์—ฐ๊ฒฐ๋จ + CONNECTED_LEFT(-1, (current, size) -> Math.max(0, current - 1)), + // ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์—ฐ๊ฒฐ๋จ + CONNECTED_RIGHT(1, (current, size) -> Math.min(size - 1, current + 1)), + // ์–‘์ชฝ ์•„๋ฌด ๊ณณ์—๋„ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์Œ + NOT_CONNECTED(0, (current, size) -> current); + + private final int offset; + private final BiFunction moveLogic; + + Point(int offset, BiFunction moveLogic) { + this.offset = offset; + this.moveLogic = moveLogic; + } + + public int move(int currentPosition, int size) { + return moveLogic.apply(currentPosition, size); + } +} diff --git a/src/main/java/domain/RandomGenerator.java b/src/main/java/domain/RandomGenerator.java new file mode 100644 index 00000000..c1af500e --- /dev/null +++ b/src/main/java/domain/RandomGenerator.java @@ -0,0 +1,21 @@ +package domain; + +import java.util.Random; + +public class RandomGenerator implements RandomStrategy { + + private final Random random; + + public RandomGenerator() { + this.random = new Random(); + } + + public RandomGenerator(long seed) { + this.random = new Random(seed); + } + + @Override + public boolean nextBoolean() { + return random.nextBoolean(); + } +} diff --git a/src/main/java/domain/RandomStrategy.java b/src/main/java/domain/RandomStrategy.java new file mode 100644 index 00000000..a7f59209 --- /dev/null +++ b/src/main/java/domain/RandomStrategy.java @@ -0,0 +1,5 @@ +package domain; + +public interface RandomStrategy { + boolean nextBoolean(); +} diff --git a/src/main/java/domain/ResultItem.java b/src/main/java/domain/ResultItem.java new file mode 100644 index 00000000..a52e41a9 --- /dev/null +++ b/src/main/java/domain/ResultItem.java @@ -0,0 +1,21 @@ +package domain; + +public class ResultItem { + + private final String item; + + public ResultItem(String item) { + validate(item); + this.item = item; + } + + private void validate(String item) { + if (item.isEmpty()) { + throw new IllegalArgumentException("์‹คํ–‰ ๊ฒฐ๊ณผ ๊ฐ’์€ ํ•„์ˆ˜ ์ž…๋ ฅ ๊ฐ’์ž…๋‹ˆ๋‹ค."); + } + } + + public String getItem() { + return item; + } +} diff --git a/src/main/java/domain/ResultItems.java b/src/main/java/domain/ResultItems.java new file mode 100644 index 00000000..aa4ce82a --- /dev/null +++ b/src/main/java/domain/ResultItems.java @@ -0,0 +1,33 @@ +package domain; + +import java.util.List; + +public class ResultItems { + + private final List items; + + public ResultItems(List items, int expectedSize) { + validateCount(items, expectedSize); + this.items = items; + } + + private void validateCount(List items, int expectedSize) { + if (items.size() != expectedSize) { + throw new IllegalArgumentException("์ฐธ์—ฌ์ž์˜ ์ˆ˜์™€ ์‹คํ–‰ ๊ฒฐ๊ณผ ๊ฐœ์ˆ˜๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); + } + } + + public int count() { + return items.size(); + } + + public List extractItems() { + return List.copyOf(items); + } + + public List extractNames() { + return items.stream() + .map(ResultItem::getItem) + .toList(); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..d1b47db0 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,46 @@ +package view; + +import domain.LadderHeight; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class InputView { + + private static final Scanner scanner = new Scanner(System.in); + + public List readPlayerNames() { + System.out.println("์ฐธ์—ฌํ•  ์‚ฌ๋žŒ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”. (์ด๋ฆ„์€ ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์„ธ์š”): "); + + String userInput = scanner.nextLine(); + return Arrays.stream(userInput.split(",")) + .map(String::trim) + .filter(name -> !name.isEmpty()) + .collect(Collectors.toList()); + } + + public List readResultItems() { + System.out.println(); + System.out.println("์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”. (๊ฒฐ๊ณผ๋Š” ์‰ผํ‘œ(,)๋กœ ๊ตฌ๋ถ„ํ•˜์„ธ์š”): "); + + String userInput = scanner.nextLine(); + return new ArrayList<>(Arrays.asList(userInput.split(","))); + } + + public LadderHeight readHeight() { + System.out.println(); + System.out.println("์ตœ๋Œ€ ์‚ฌ๋‹ค๋ฆฌ ๋†’์ด๋Š” ๋ช‡ ๊ฐœ์ธ๊ฐ€์š”?"); + int height = scanner.nextInt(); + scanner.nextLine(); + return new LadderHeight(height); + } + + public String readResultRequest() { + System.out.println(); + System.out.println("๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์€?"); + return scanner.nextLine().trim(); + } +} diff --git a/src/main/java/view/LadderPrinter.java b/src/main/java/view/LadderPrinter.java new file mode 100644 index 00000000..e418df77 --- /dev/null +++ b/src/main/java/view/LadderPrinter.java @@ -0,0 +1,40 @@ +package view; + +import domain.LadderGame; +import domain.LadderLine; +import domain.Point; + +import java.util.List; + +public class LadderPrinter { + + private static final String POINT = "|"; + private static final String CONNECT_LINE = "-"; + private static final String NO_CONNECT = " "; + private static final int CONNECTION_WIDTH = 5; + + public static void printLadder(LadderGame ladderGame) { + List ladderLines = ladderGame.getLadderStructure(); + ladderLines.forEach(line -> { + StringBuilder lineBuilder = new StringBuilder(); + lineBuilder.append(POINT); // ์ฒซ ๋ฒˆ์งธ ํฌ์ธํŠธ + + List points = line.getPoints(); + int lastIndex = points.size() - 1; + + for (int i = 0; i < lastIndex; i++) { + appendConnection(lineBuilder, points.get(i)); + lineBuilder.append(POINT); // ๋‹ค์Œ ํฌ์ธํŠธ + } + System.out.println(lineBuilder); // ํ•œ ์ค„ ์ถœ๋ ฅ + }); + } + + private static void appendConnection(StringBuilder lineBuilder, Point point) { + if (point.move(0, CONNECTION_WIDTH) == 1) { + lineBuilder.append(CONNECT_LINE.repeat(CONNECTION_WIDTH)); + return; + } + lineBuilder.append(NO_CONNECT.repeat(CONNECTION_WIDTH)); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..b39d188a --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,44 @@ +package view; + +import domain.LadderGame; + +import java.util.List; +import java.util.Map; + +public class OutputView { + + private static final int SPACE_WIDTH = 6; + private final LadderPrinter ladderPrinter = new LadderPrinter(); + + public void printLadder(List playerNames, LadderGame ladderGame, List resultItems) { + System.out.println(); + System.out.println("์‚ฌ๋‹ค๋ฆฌ ๊ฒฐ๊ณผ"); + System.out.println(); + + printNames(playerNames); + ladderPrinter.printLadder(ladderGame); + printNames(resultItems); + } + + private void printNames(List names) { + for (String name : names) { + System.out.print(String.format("%-" + SPACE_WIDTH + "s", name)); + } + System.out.println(); + } + + public void printSingleResult(String player, String resultItem) { + System.out.println(); + System.out.println("์‹คํ–‰ ๊ฒฐ๊ณผ"); + System.out.println(player + " : " + resultItem); + } + + public void printAllResults(Map ladderGameResult) { + System.out.println(); + System.out.println("์‹คํ–‰ ๊ฒฐ๊ณผ"); + + ladderGameResult.forEach((player, result) -> + System.out.println(player + " : " + result) + ); + } +} diff --git a/src/test/java/domain/LadderPrinterTest.java b/src/test/java/domain/LadderPrinterTest.java new file mode 100644 index 00000000..64c7bb59 --- /dev/null +++ b/src/test/java/domain/LadderPrinterTest.java @@ -0,0 +1,30 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import view.LadderPrinter; + +public class LadderPrinterTest { + + LadderGame ladderGame; + + @BeforeEach + @DisplayName("์‚ฌ๋‹ค๋ฆฌ ๊ฒŒ์ž„ ์ดˆ๊ธฐํ™”") + void setUp() { + // ๊ณ ์ •๋œ ์ „๋žต์œผ๋กœ ํ…Œ์ŠคํŠธ (ํ•ญ์ƒ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์—ฐ๊ฒฐ๋จ) + RandomStrategy fixedStrategy = () -> true; + // ๊ฐ€๋กœ 5, ๋†’์ด 3, ์ „๋žต ์ฃผ์ž… + ladderGame = LadderGame.of(5, new LadderHeight(3), fixedStrategy); + } + + @Test + @DisplayName("์ „์ฒด ์‚ฌ๋‹ค๋ฆฌ ์ถœ๋ ฅ ํ…Œ์ŠคํŠธ") + void printLadderStructure() { + System.out.println("\n=== Ladder Structure ==="); + LadderPrinter.printLadder(ladderGame); + } + + // ์ถœ๋ ฅ ๋กœ์ง ์˜ค๋ฅ˜ + // 1. line ๊ฒน์นจ +} diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java new file mode 100644 index 00000000..9a1969bb --- /dev/null +++ b/src/test/java/domain/PlayerTest.java @@ -0,0 +1,43 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class PlayerTest { + + @Test + @DisplayName("์ •์ƒ์ ์ธ ์ด๋ฆ„์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค.") + void create() { + Player player = new Player("Tom"); + assertEquals("Tom", player.getName()); + } + + @Test + @DisplayName("์ด๋ฆ„์ด ๋น„์–ด ์žˆ์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.") + void emptyNameThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Player(""); + }); + assertEquals("์ฐธ์—ฌํ•  ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์€ 1์ž ์ด์ƒ 5์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", exception.getMessage()); + } + + @Test + @DisplayName("์ด๋ฆ„์ด 5์ž๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.") + void longNameThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Player("TommyLee"); + }); + assertEquals("์ฐธ์—ฌํ•  ์‚ฌ๋žŒ์˜ ์ด๋ฆ„์€ 1์ž ์ด์ƒ 5์ž ์ดํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.", exception.getMessage()); + } + + @Test + @DisplayName("๋‹ค๋ฅธ ์ด๋ฆ„์˜ ํ”Œ๋ ˆ์ด์–ด๋ฅผ ์„œ๋กœ ๋‹ค๋ฅธ ํ”Œ๋ ˆ์ด์–ด(๊ฐ์ฒด)๋กœ ํŒ๋‹จํ•ด์•ผ ํ•œ๋‹ค.") + void playersWithDifferentNamesShouldNotBeEqual() { + Player player1 = new Player("Tom"); + Player player2 = new Player("Jerry"); + + assertNotEquals(player1, player2); + } +} diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java new file mode 100644 index 00000000..d10ac2e6 --- /dev/null +++ b/src/test/java/domain/PlayersTest.java @@ -0,0 +1,54 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class PlayersTest { + + @Test + @DisplayName("์ •์ƒ์ ์ธ ํ”Œ๋ ˆ์ด์–ด ๋ชฉ๋ก์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.") + void create() { + List playerList = List.of(new Player("Tom"), new Player("Jerry"), new Player("Max")); + Players players = new Players(playerList); + + assertEquals(3, players.count()); + } + + @Test + @DisplayName("ํ”Œ๋ ˆ์ด์–ด ์ˆ˜๊ฐ€ 0๋ช…์ผ ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.") + void emptyThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Players(List.of()); + }); + assertEquals("์ฐธ์—ฌ ์ธ์›์€ ์ตœ์†Œ 1๋ช… ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.", exception.getMessage()); + } + + @Test + @DisplayName("ํ”Œ๋ ˆ์ด์–ด์˜ ์ด๋ฆ„ ๋ชฉ๋ก์„ ์ •ํ™•ํžˆ ์ถ”์ถœํ•œ๋‹ค.") + void extractNames() { + List playerList = List.of(new Player("Tom"), new Player("Jerry"), new Player("Max")); + Players players = new Players(playerList); + + List names = players.extractNames(); + assertEquals(List.of("Tom", "Jerry", "Max"), names); + } + + @Test + @DisplayName("ํ”Œ๋ ˆ์ด์–ด ๊ฐ์ฒด ๋ชฉ๋ก์„ ์ •ํ™•ํžˆ ๋ฐ˜ํ™˜ํ•œ๋‹ค.") + void extractPlayers() { + List playerList = List.of(new Player("Tom"), new Player("Jerry"), new Player("Max")); + Players players = new Players(playerList); + + List extractedPlayers = players.extractPlayers(); + assertEquals(3, extractedPlayers.size()); + assertEquals(playerList, extractedPlayers); + + assertThrows(UnsupportedOperationException.class, () -> { + extractedPlayers.add(new Player("John")); + }); + } +} diff --git a/src/test/java/domain/ResultItemTest.java b/src/test/java/domain/ResultItemTest.java new file mode 100644 index 00000000..d730ecd8 --- /dev/null +++ b/src/test/java/domain/ResultItemTest.java @@ -0,0 +1,25 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResultItemTest { + + @Test + @DisplayName("์ •์ƒ์ ์ธ ๊ฐ’์ด ์ฃผ์–ด์กŒ์„ ๋•Œ, ResultItem์ด ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค.") + void create() { + ResultItem resultItem = new ResultItem("1๋“ฑ"); + assertEquals("1๋“ฑ", resultItem.getItem()); + } + + @Test + @DisplayName("๊ฐ’์ด ๋น„์–ด ์žˆ์„ ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.") + void emptyThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new ResultItem(""); + }); + assertEquals("์‹คํ–‰ ๊ฒฐ๊ณผ ๊ฐ’์€ ํ•„์ˆ˜ ์ž…๋ ฅ ๊ฐ’์ž…๋‹ˆ๋‹ค.", exception.getMessage()); + } +} diff --git a/src/test/java/domain/ResultItemsTest.java b/src/test/java/domain/ResultItemsTest.java new file mode 100644 index 00000000..37cd8876 --- /dev/null +++ b/src/test/java/domain/ResultItemsTest.java @@ -0,0 +1,56 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResultItemsTest { + + @Test + @DisplayName("์ •์ƒ์ ์ธ ๊ฒฐ๊ณผ ๋ชฉ๋ก์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.") + void create() { + List items = List.of(new ResultItem("1๋“ฑ"), new ResultItem("2๋“ฑ"), new ResultItem("๊ฝ")); + ResultItems resultItems = new ResultItems(items, 3); + + assertEquals(3, resultItems.count()); + } + + @Test + @DisplayName("๊ฒฐ๊ณผ ๊ฐœ์ˆ˜๊ฐ€ ์˜ˆ์ƒ ๊ฐœ์ˆ˜์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.") + void sizeMismatchThrowsException() { + List items = List.of(new ResultItem("1๋“ฑ"), new ResultItem("๊ฝ")); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new ResultItems(items, 3); + }); + assertEquals("์ฐธ์—ฌ์ž์˜ ์ˆ˜์™€ ์‹คํ–‰ ๊ฒฐ๊ณผ ๊ฐœ์ˆ˜๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.", exception.getMessage()); + } + + @Test + @DisplayName("๊ฒฐ๊ณผ ๋ชฉ๋ก์˜ ๊ฐ’์„ ์ •ํ™•ํžˆ ์ถ”์ถœํ•œ๋‹ค.") + void extractNames() { + List items = List.of(new ResultItem("1๋“ฑ"), new ResultItem("2๋“ฑ"), new ResultItem("๊ฝ")); + ResultItems resultItems = new ResultItems(items, 3); + + List names = resultItems.extractNames(); + assertEquals(List.of("1๋“ฑ", "2๋“ฑ", "๊ฝ"), names); + } + + @Test + @DisplayName("๊ฒฐ๊ณผ ๊ฐ์ฒด ๋ชฉ๋ก์„ ์ •ํ™•ํžˆ ๋ฐ˜ํ™˜ํ•œ๋‹ค.") + void extractItems() { + List items = List.of(new ResultItem("1๋“ฑ"), new ResultItem("2๋“ฑ"), new ResultItem("๊ฝ")); + ResultItems resultItems = new ResultItems(items, 3); + + List extractedItems = resultItems.extractItems(); + assertEquals(3, extractedItems.size()); + assertEquals(items, extractedItems); + + assertThrows(UnsupportedOperationException.class, () -> { + extractedItems.add(new ResultItem("4๋“ฑ")); + }); + } +}