From d406e4e4080befb9151fb7c0249727c4bd76cfbc Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Tue, 29 Apr 2025 00:44:50 +0900 Subject: [PATCH 01/24] =?UTF-8?q?[=EA=B8=B0=EB=8A=A5=EC=B6=94=EA=B0=80][1-?= =?UTF-8?q?3=EB=8B=A8=EA=B3=84]=20=EA=B8=B0=EB=B3=B8=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 14 +++++++ .../java/controller/LadderController.java | 36 ++++++++++++++++++ src/main/java/model/LadderGame.java | 20 ++++++++++ src/main/java/model/LadderHeight.java | 24 ++++++++++++ src/main/java/model/LadderWidth.java | 23 +++++++++++ src/main/java/model/Line.java | 38 +++++++++++++++++++ src/main/java/model/Status.java | 23 +++++++++++ src/main/java/util/LadderGenerator.java | 6 +++ src/main/java/util/RandomLadderGenerator.java | 12 ++++++ src/main/java/view/InputView.java | 32 ++++++++++++++++ src/main/java/view/OutputView.java | 23 +++++++++++ 11 files changed, 251 insertions(+) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/controller/LadderController.java create mode 100644 src/main/java/model/LadderGame.java create mode 100644 src/main/java/model/LadderHeight.java create mode 100644 src/main/java/model/LadderWidth.java create mode 100644 src/main/java/model/Line.java create mode 100644 src/main/java/model/Status.java create mode 100644 src/main/java/util/LadderGenerator.java create mode 100644 src/main/java/util/RandomLadderGenerator.java create mode 100644 src/main/java/view/InputView.java create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..106d94f0 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,14 @@ +import controller.LadderController; +import util.RandomLadderGenerator; +import view.InputView; +import view.OutputView; + +public class Application { + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + RandomLadderGenerator generator = new RandomLadderGenerator(); + LadderController controller = new LadderController(inputView, outputView, generator); + controller.run(); + } +} diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java new file mode 100644 index 00000000..11304eb2 --- /dev/null +++ b/src/main/java/controller/LadderController.java @@ -0,0 +1,36 @@ +package controller; + +import model.Ladder; +import model.LadderGame; +import model.LadderHeight; +import model.LadderWidth; +import model.Line; +import java.util.ArrayList; +import java.util.List; +import util.LadderGenerator; +import view.InputView; +import view.OutputView; + +public class LadderController { + private final InputView inputView; + private final OutputView outputView; + private final LadderGenerator generator; + + public LadderController(InputView inputView, OutputView outputView, LadderGenerator generator) { + this.inputView = inputView; + this.outputView = outputView; + this.generator = generator; + } + + public void run() { + LadderWidth width = inputView.inputLadderWidth(); + LadderHeight height = inputView.inputLadderHeight(); + List lines = new ArrayList<>(); + for (int i = 0; i < height.getLadderHeight(); i++) { + lines.add(new Line(width.getLadderWidth(), generator)); + } + Ladder ladder = new Ladder(height, width, lines); + outputView.printLadder(ladder); + outputView.printResults(new LadderGame(ladder).play()); + } +} diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java new file mode 100644 index 00000000..e2808a70 --- /dev/null +++ b/src/main/java/model/LadderGame.java @@ -0,0 +1,20 @@ +package model; + +import java.util.HashMap; +import java.util.Map; + +public class LadderGame { + private final Ladder ladder; + + public LadderGame(Ladder ladder) { + this.ladder = ladder; + } + + public Map play() { + Map results = new HashMap<>(); + for (int start = 0; start < ladder.getLadderWidth(); start++) { + results.put(start, ladder.move(start)); + } + return results; + } +} diff --git a/src/main/java/model/LadderHeight.java b/src/main/java/model/LadderHeight.java new file mode 100644 index 00000000..69217ec2 --- /dev/null +++ b/src/main/java/model/LadderHeight.java @@ -0,0 +1,24 @@ +package model; + +public class LadderHeight { + + private static final int MAXIMUM_LADDER_HEIGHT = 20; + private static final int MINIMUM_LADDER_HEIGHT = 1; + + private final int height; + + public LadderHeight(int height) { + validateLadderHeight(height); + this.height = height; + } + + private void validateLadderHeight(int height) { + if (height < MINIMUM_LADDER_HEIGHT || height > MAXIMUM_LADDER_HEIGHT) { + throw new IllegalArgumentException("사다리의 높이는 1 이상, 20 이하의 숫자만 가능합니다."); + } + } + + public int getLadderHeight(){ + return height; + } +} diff --git a/src/main/java/model/LadderWidth.java b/src/main/java/model/LadderWidth.java new file mode 100644 index 00000000..6a852bc7 --- /dev/null +++ b/src/main/java/model/LadderWidth.java @@ -0,0 +1,23 @@ +package model; + +public class LadderWidth { + + private static final int MINIMUM_LADDER_WIDTH = 1; + private final int width; + + + public LadderWidth(int width) { + validateLadderWidth(width); + this.width = width; + } + + private void validateLadderWidth(int width) { + if(width <= MINIMUM_LADDER_WIDTH) { + throw new IllegalArgumentException("사다리의 넓이는 1보다 커야합니다."); + } + } + + public int getLadderWidth() { + return width; + } +} diff --git a/src/main/java/model/Line.java b/src/main/java/model/Line.java new file mode 100644 index 00000000..e11621f5 --- /dev/null +++ b/src/main/java/model/Line.java @@ -0,0 +1,38 @@ +package model; + +import java.util.ArrayList; +import java.util.List; +import util.LadderGenerator; + +public class Line { + private final List points; + + public Line(int width, LadderGenerator generator) { + this.points = new ArrayList<>(); + for (int column = 0; column < width - 1; column++) { + makeLine(column, generator); + } + } + + private void makeLine(int column, LadderGenerator generator) { + if (points.size() >= 1 && points.get(column - 1).getStatus()) { + points.add(Status.DISCONNECTED); + return; + } + points.add(Status.findStatus(generator.generate())); + } + + public int move(int position) { + if (position > 0 && points.get(position - 1).getStatus()) { + return position - 1; + } + if (position < points.size() && points.get(position).getStatus()) { + return position + 1; + } + return position; + } + + public List getPoints() { + return List.copyOf(points); + } +} diff --git a/src/main/java/model/Status.java b/src/main/java/model/Status.java new file mode 100644 index 00000000..6fdebc56 --- /dev/null +++ b/src/main/java/model/Status.java @@ -0,0 +1,23 @@ +package model; + +public enum Status { + CONNECTED(true), + DISCONNECTED(false); + + private boolean status; + + Status(boolean status) { + this.status = status; + } + + public boolean getStatus() { + return status; + } + + public static Status findStatus(boolean status) { + if (status) { + return CONNECTED; + } + return DISCONNECTED; + } +} diff --git a/src/main/java/util/LadderGenerator.java b/src/main/java/util/LadderGenerator.java new file mode 100644 index 00000000..0b602088 --- /dev/null +++ b/src/main/java/util/LadderGenerator.java @@ -0,0 +1,6 @@ +package util; + +public interface LadderGenerator { + + boolean generate(); +} diff --git a/src/main/java/util/RandomLadderGenerator.java b/src/main/java/util/RandomLadderGenerator.java new file mode 100644 index 00000000..0154850d --- /dev/null +++ b/src/main/java/util/RandomLadderGenerator.java @@ -0,0 +1,12 @@ +package util; + +import java.util.Random; + +public class RandomLadderGenerator implements LadderGenerator{ + + private final Random random = new Random(); + + public boolean generate() { + return random.nextBoolean(); + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..431aa932 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,32 @@ +package view; + +import model.LadderHeight; +import model.LadderWidth; +import java.util.Scanner; + +public class InputView { + + private static final Scanner scanner = new Scanner(System.in); + private static final String INPUT_EXCEPTION_MESSAGE = "올바른 입력 형식이 아닙니다. 다시 입력해주세요."; + + + public LadderHeight inputLadderHeight() { + try { + System.out.println("사다리의 높이는 몇 개인가요?"); + return new LadderHeight(Integer.parseInt(scanner.nextLine())); + } catch (IllegalArgumentException e) { + System.out.println(INPUT_EXCEPTION_MESSAGE); + return inputLadderHeight(); + } + } + + public LadderWidth inputLadderWidth() { + try { + System.out.println("사다리 넓이는 몇 개인가요?"); + return new LadderWidth(Integer.parseInt(scanner.nextLine())); + } catch (IllegalArgumentException e) { + System.out.println("INPUT_EXCEPTION_MESSAGE"); + return inputLadderWidth(); + } + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..7b72ac7a --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,23 @@ +package view; + +import model.Ladder; +import model.Status; +import java.util.Map; + +public class OutputView { + public void printLadder(Ladder ladder) { + for (var line : ladder.getLines()) { + System.out.print("|"); + for (Status status : line.getPoints()) { + System.out.print(status.getStatus() ? "----|" : " |"); + } + System.out.println(); + } + } + + public void printResults(Map results) { + for (var entry : results.entrySet()) { + System.out.println(entry.getKey() + " -> " + entry.getValue()); + } + } +} From 02e4f1be31e8abca39cb9f541b2fea608ae11a1d Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:50:45 +0900 Subject: [PATCH 02/24] =?UTF-8?q?feat:=204=EB=8B=A8=EA=B3=84=20input=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/InputView.java | 55 +++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 431aa932..685596c4 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,32 +1,53 @@ package view; -import model.LadderHeight; -import model.LadderWidth; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; import java.util.Scanner; +import model.player.Players; public class InputView { private static final Scanner scanner = new Scanner(System.in); - private static final String INPUT_EXCEPTION_MESSAGE = "올바른 입력 형식이 아닙니다. 다시 입력해주세요."; + public static final String INPUT_EXCEPTION_MESSAGE = "올바른 입력 형식이 아닙니다. 다시 입력해주세요."; + private static final String LADDER_HEIGHT_MESSAGE = "최대 사다리 높이는 몇 개인가요?"; + private static final String EXECUTION_GOAL_MESSAGE = "실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"; + private static final String EXECUTION_NAME_MESSAGE = "참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"; + private static final String PLAYER_FOR_RESULT_MESSAGE = "결과를 보고 싶은 사람은?"; + private static final String INPUT_DELIMITER = ","; + public int inputLadderHeight() { + System.out.println("\n" + LADDER_HEIGHT_MESSAGE); + String rawLadderHeight = scanner.nextLine(); + return parseInt(rawLadderHeight); + } - public LadderHeight inputLadderHeight() { + private int parseInt(String rawLadderHeight) { try { - System.out.println("사다리의 높이는 몇 개인가요?"); - return new LadderHeight(Integer.parseInt(scanner.nextLine())); - } catch (IllegalArgumentException e) { - System.out.println(INPUT_EXCEPTION_MESSAGE); - return inputLadderHeight(); + return Integer.parseInt(rawLadderHeight); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(INPUT_EXCEPTION_MESSAGE); } } - public LadderWidth inputLadderWidth() { - try { - System.out.println("사다리 넓이는 몇 개인가요?"); - return new LadderWidth(Integer.parseInt(scanner.nextLine())); - } catch (IllegalArgumentException e) { - System.out.println("INPUT_EXCEPTION_MESSAGE"); - return inputLadderWidth(); - } + public List inputPlayers() { + System.out.println("\n" +EXECUTION_NAME_MESSAGE); + String rawPlayerName = scanner.nextLine(); + return Arrays.stream(rawPlayerName.split(INPUT_DELIMITER)) + .map(String::trim) + .collect(Collectors.toList()); + } + + public List inputGoals(Players players) { + System.out.println("\n" + EXECUTION_GOAL_MESSAGE); + String rawGoals = scanner.nextLine(); + return Arrays.stream(rawGoals.split(INPUT_DELIMITER)) + .map(String::trim) + .collect(Collectors.toList()); + } + + public String inputPlayerForResult() { + System.out.println("\n" + PLAYER_FOR_RESULT_MESSAGE); + return scanner.nextLine(); } } From 822b95174ef17b6a3e888549a6b44c7e01f91bc3 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:51:17 +0900 Subject: [PATCH 03/24] =?UTF-8?q?feat:=204=EB=8B=A8=EA=B3=84=20=EC=8B=A4?= =?UTF-8?q?=ED=96=89=20=EA=B2=B0=EA=B3=BC=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/goal/Goal.java | 24 ++++++++++++++++++++++++ src/main/java/model/goal/Goals.java | 25 +++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 src/main/java/model/goal/Goal.java create mode 100644 src/main/java/model/goal/Goals.java diff --git a/src/main/java/model/goal/Goal.java b/src/main/java/model/goal/Goal.java new file mode 100644 index 00000000..0ff6572b --- /dev/null +++ b/src/main/java/model/goal/Goal.java @@ -0,0 +1,24 @@ +package model.goal; + +public class Goal { + + private final int MAXINUM_GOAL_LENGTH = 5; + private final String goal; + + public Goal(String goal) { + validateGoal(goal); + this.goal = goal; + } + + private void validateGoal(String goal) { + if (goal == null || goal.isBlank() || goal.length() > MAXINUM_GOAL_LENGTH) { + throw new IllegalArgumentException("실행 결과는 1~5글자여야 합니다."); + } + + } + + + public String getGoal() { + return goal; + } +} diff --git a/src/main/java/model/goal/Goals.java b/src/main/java/model/goal/Goals.java new file mode 100644 index 00000000..8290d930 --- /dev/null +++ b/src/main/java/model/goal/Goals.java @@ -0,0 +1,25 @@ +package model.goal; + +import java.util.ArrayList; +import java.util.List; + +public class Goals { + + private final List goals; + + public Goals(List goals, int playerCount) { + validateGoals(goals, playerCount); + this.goals = new ArrayList<>(goals); + + } + + private void validateGoals(List goals, int playerCount) { + if (goals.size() != playerCount) { + throw new IllegalArgumentException("실행 결과 수와 참여자 수는 같아야 합니다."); + } + } + + public List getGoals() { + return List.copyOf(goals); + } +} From b8890c36ca9281036372faefc6050374dde2c7ed Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:52:06 +0900 Subject: [PATCH 04/24] =?UTF-8?q?feat:=204=EB=8B=A8=EA=B3=84=20=ED=94=8C?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=96=B4=20=EA=B4=80=EB=A0=A8=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/player/Player.java | 39 ++++++++++++++++++++ src/main/java/model/player/PlayerName.java | 41 ++++++++++++++++++++++ src/main/java/model/player/Players.java | 39 ++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 src/main/java/model/player/Player.java create mode 100644 src/main/java/model/player/PlayerName.java create mode 100644 src/main/java/model/player/Players.java diff --git a/src/main/java/model/player/Player.java b/src/main/java/model/player/Player.java new file mode 100644 index 00000000..c490907a --- /dev/null +++ b/src/main/java/model/player/Player.java @@ -0,0 +1,39 @@ +package model.player; + +import java.util.Objects; + +public class Player { + + private final PlayerName name; + private final Position position; + + public Player(PlayerName name, Position position) { + this.name = name; + this.position = position; + } + + public PlayerName getName() { + return name; + } + + public Position getPosition() { + return position; + } + + @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) && Objects.equals(position, player.position); + } + + @Override + public int hashCode() { + return Objects.hash(name, position); + } +} diff --git a/src/main/java/model/player/PlayerName.java b/src/main/java/model/player/PlayerName.java new file mode 100644 index 00000000..fbd38370 --- /dev/null +++ b/src/main/java/model/player/PlayerName.java @@ -0,0 +1,41 @@ +package model.player; + +import java.util.Objects; + +public class PlayerName { + + private final int MAXINUM_NAME_LENGTH = 5; + private final String name; + + public PlayerName(String name) { + validateName(name); + this.name = name; + } + + private void validateName(String name) { + if (name == null || name.isBlank() || name.length() > MAXINUM_NAME_LENGTH) { + throw new IllegalArgumentException("플레이어의 이름은 1~5글자여야 합니다."); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlayerName that = (PlayerName) o; + return name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + public String getName() { + return name; + } +} diff --git a/src/main/java/model/player/Players.java b/src/main/java/model/player/Players.java new file mode 100644 index 00000000..03934051 --- /dev/null +++ b/src/main/java/model/player/Players.java @@ -0,0 +1,39 @@ +package model.player; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class Players { + + private final List players; + + public Players(List players) { + validatePlayerCount(players); + validateDuplicate(players); + this.players = players; + } + + private void validatePlayerCount(List players) { + if (players.size() < 2) { + throw new IllegalArgumentException("플레이어는 최소 2명 이상이어야 합니다."); + } + } + + private void validateDuplicate(List players) { + Set names = players.stream() + .map(Player::getName) + .collect(Collectors.toSet()); + if (names.size() != players.size()) { + throw new IllegalArgumentException("플레이어의 이름은 중복될 수 없습니다."); + } + } + + public int size() { + return players.size(); + } + + public List getPlayers() { + return List.copyOf(players); + } +} From a9280b936d5620a87b4a7ba91cef6f37e0ada158 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:53:02 +0900 Subject: [PATCH 05/24] =?UTF-8?q?feat:=20Enum=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20Point=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/LadderHeight.java | 24 ----------------- src/main/java/model/LadderWidth.java | 23 ---------------- src/main/java/model/Line.java | 38 --------------------------- src/main/java/model/Status.java | 23 ---------------- src/main/java/model/ladder/Point.java | 17 ++++++++++++ 5 files changed, 17 insertions(+), 108 deletions(-) delete mode 100644 src/main/java/model/LadderHeight.java delete mode 100644 src/main/java/model/LadderWidth.java delete mode 100644 src/main/java/model/Line.java delete mode 100644 src/main/java/model/Status.java create mode 100644 src/main/java/model/ladder/Point.java diff --git a/src/main/java/model/LadderHeight.java b/src/main/java/model/LadderHeight.java deleted file mode 100644 index 69217ec2..00000000 --- a/src/main/java/model/LadderHeight.java +++ /dev/null @@ -1,24 +0,0 @@ -package model; - -public class LadderHeight { - - private static final int MAXIMUM_LADDER_HEIGHT = 20; - private static final int MINIMUM_LADDER_HEIGHT = 1; - - private final int height; - - public LadderHeight(int height) { - validateLadderHeight(height); - this.height = height; - } - - private void validateLadderHeight(int height) { - if (height < MINIMUM_LADDER_HEIGHT || height > MAXIMUM_LADDER_HEIGHT) { - throw new IllegalArgumentException("사다리의 높이는 1 이상, 20 이하의 숫자만 가능합니다."); - } - } - - public int getLadderHeight(){ - return height; - } -} diff --git a/src/main/java/model/LadderWidth.java b/src/main/java/model/LadderWidth.java deleted file mode 100644 index 6a852bc7..00000000 --- a/src/main/java/model/LadderWidth.java +++ /dev/null @@ -1,23 +0,0 @@ -package model; - -public class LadderWidth { - - private static final int MINIMUM_LADDER_WIDTH = 1; - private final int width; - - - public LadderWidth(int width) { - validateLadderWidth(width); - this.width = width; - } - - private void validateLadderWidth(int width) { - if(width <= MINIMUM_LADDER_WIDTH) { - throw new IllegalArgumentException("사다리의 넓이는 1보다 커야합니다."); - } - } - - public int getLadderWidth() { - return width; - } -} diff --git a/src/main/java/model/Line.java b/src/main/java/model/Line.java deleted file mode 100644 index e11621f5..00000000 --- a/src/main/java/model/Line.java +++ /dev/null @@ -1,38 +0,0 @@ -package model; - -import java.util.ArrayList; -import java.util.List; -import util.LadderGenerator; - -public class Line { - private final List points; - - public Line(int width, LadderGenerator generator) { - this.points = new ArrayList<>(); - for (int column = 0; column < width - 1; column++) { - makeLine(column, generator); - } - } - - private void makeLine(int column, LadderGenerator generator) { - if (points.size() >= 1 && points.get(column - 1).getStatus()) { - points.add(Status.DISCONNECTED); - return; - } - points.add(Status.findStatus(generator.generate())); - } - - public int move(int position) { - if (position > 0 && points.get(position - 1).getStatus()) { - return position - 1; - } - if (position < points.size() && points.get(position).getStatus()) { - return position + 1; - } - return position; - } - - public List getPoints() { - return List.copyOf(points); - } -} diff --git a/src/main/java/model/Status.java b/src/main/java/model/Status.java deleted file mode 100644 index 6fdebc56..00000000 --- a/src/main/java/model/Status.java +++ /dev/null @@ -1,23 +0,0 @@ -package model; - -public enum Status { - CONNECTED(true), - DISCONNECTED(false); - - private boolean status; - - Status(boolean status) { - this.status = status; - } - - public boolean getStatus() { - return status; - } - - public static Status findStatus(boolean status) { - if (status) { - return CONNECTED; - } - return DISCONNECTED; - } -} diff --git a/src/main/java/model/ladder/Point.java b/src/main/java/model/ladder/Point.java new file mode 100644 index 00000000..9e471bcc --- /dev/null +++ b/src/main/java/model/ladder/Point.java @@ -0,0 +1,17 @@ +package model.ladder; + +public enum Point { + CONNECTED, + DISCONNECTED; + + public static Point of(boolean status) { + if (status) { + return CONNECTED; + } + return DISCONNECTED; + } + + public boolean isConnected() { + return this.equals(CONNECTED); + } +} From 5f22466a87f37bddf02ac09449213ec9f8e062b4 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:58:37 +0900 Subject: [PATCH 06/24] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20?= =?UTF-8?q?=EA=B2=8C=EC=9E=84=20=EC=A0=84=EC=B2=B4=20=EC=A0=9C=EC=96=B4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 78 ++++++++++++++++--- src/main/java/model/LadderGame.java | 19 ++++- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 11304eb2..6c6d1cd0 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,17 +1,26 @@ package controller; -import model.Ladder; +import static view.InputView.INPUT_EXCEPTION_MESSAGE; + +import java.util.Map; +import java.util.stream.Collectors; +import model.goal.Goal; +import model.goal.Goals; +import model.ladder.Ladder; import model.LadderGame; -import model.LadderHeight; -import model.LadderWidth; -import model.Line; +import model.ladder.LadderHeight; import java.util.ArrayList; import java.util.List; +import model.player.Player; +import model.player.PlayerName; +import model.player.Players; +import model.player.Position; import util.LadderGenerator; import view.InputView; import view.OutputView; public class LadderController { + private final InputView inputView; private final OutputView outputView; private final LadderGenerator generator; @@ -23,14 +32,59 @@ public LadderController(InputView inputView, OutputView outputView, LadderGenera } public void run() { - LadderWidth width = inputView.inputLadderWidth(); - LadderHeight height = inputView.inputLadderHeight(); - List lines = new ArrayList<>(); - for (int i = 0; i < height.getLadderHeight(); i++) { - lines.add(new Line(width.getLadderWidth(), generator)); + Players players = createPlayers(); + Goals goals = createGoals(players); + LadderHeight height = createLadderHeight(players.size()); + Ladder ladder = Ladder.of(players, height, generator); + LadderGame game = new LadderGame(ladder); + Map results = game.play(players, goals); + outputView.printLadder(ladder, players, goals); + showResults(players, results); + } + + private Players createPlayers() { + try{ + List rawNames = inputView.inputPlayers(); + List players = new ArrayList<>(); + for (int i = 0; i < rawNames.size(); i++) { + players.add(new Player(new PlayerName(rawNames.get(i)), + new Position(i))); + } + return new Players(players); + } catch (IllegalArgumentException e) { + System.out.println(INPUT_EXCEPTION_MESSAGE); + return createPlayers(); + } + } + + private Goals createGoals(Players players) { + try { + List rawGoals = inputView.inputGoals(players); + List goalList = rawGoals.stream() + .map(Goal::new) + .collect(Collectors.toList()); + return new Goals(goalList, players.size()); + } catch (IllegalArgumentException e) { + System.out.println(INPUT_EXCEPTION_MESSAGE); + return createGoals(players); + } + } + + private LadderHeight createLadderHeight(int playerCount) { + try{ + int height = inputView.inputLadderHeight(); + return new LadderHeight(height, playerCount); + } catch (IllegalArgumentException e) { + System.out.println(INPUT_EXCEPTION_MESSAGE); + return createLadderHeight(playerCount); + } + } + + private void showResults(Players players, Map results) { + String input = inputView.inputPlayerForResult(); + while (!input.isBlank()) { + outputView.printResult(input, players, results); + input = inputView.inputPlayerForResult(); } - Ladder ladder = new Ladder(height, width, lines); - outputView.printLadder(ladder); - outputView.printResults(new LadderGame(ladder).play()); } } diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java index e2808a70..b05cd608 100644 --- a/src/main/java/model/LadderGame.java +++ b/src/main/java/model/LadderGame.java @@ -1,19 +1,30 @@ package model; import java.util.HashMap; +import java.util.List; import java.util.Map; +import model.ladder.Ladder; +import model.player.Position; +import model.goal.Goal; +import model.goal.Goals; +import model.player.Player; +import model.player.Players; public class LadderGame { + private final Ladder ladder; public LadderGame(Ladder ladder) { this.ladder = ladder; } - public Map play() { - Map results = new HashMap<>(); - for (int start = 0; start < ladder.getLadderWidth(); start++) { - results.put(start, ladder.move(start)); + public Map play(Players players, Goals goals) { + Map results = new HashMap<>(); + List playerList = players.getPlayers(); + List goalList = goals.getGoals(); + for (int start = 0; start < playerList.size(); start++) { + Position end = ladder.getGoalsPosition(new Position(start)); + results.put(playerList.get(start), goalList.get(end.getValue())); } return results; } From 68a877d01edf77db4d9d9892d21b8fc8441f16dd Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:59:01 +0900 Subject: [PATCH 07/24] =?UTF-8?q?feat:=20Ladder=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/ladder/Ladder.java | 87 ++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/main/java/model/ladder/Ladder.java diff --git a/src/main/java/model/ladder/Ladder.java b/src/main/java/model/ladder/Ladder.java new file mode 100644 index 00000000..700619d0 --- /dev/null +++ b/src/main/java/model/ladder/Ladder.java @@ -0,0 +1,87 @@ +package model.ladder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import model.player.Players; +import model.player.Position; +import util.LadderGenerator; + +public class Ladder { + + private final LadderHeight height; + private final List lines; + + public Ladder(LadderHeight height, List lines) { + this.height = height; + this.lines = lines; + } + + public static Ladder of(Players players, LadderHeight height, LadderGenerator ladderGenerator) { + List lines = new ArrayList<>(); + Ladder ladder = new Ladder(height, lines); + ladder.addLines(players.size(), ladderGenerator); + return ladder; + } + + private void addLines(int playersCount, LadderGenerator ladderGenerator) { + for (int i = 0; i < getLadderHeight(); i++) { + lines.add(Line.create(playersCount, ladderGenerator)); + } + if (isLadderNotConnected(playersCount)) { + lines.clear(); + addLines(playersCount, ladderGenerator); + } + } + + // Line이 최소 한 번 연결되었는지 검증 + private boolean isLadderNotConnected(int playersCount) { + Boolean[] isConnectedAt = getLadderConnectionStatus(playersCount); + return Arrays.stream(isConnectedAt) + .collect(Collectors.toSet()) + .size() != 1; + } + + // 전체 Line별 연결 상태 확인 + private Boolean[] getLadderConnectionStatus(int playersCount) { + int width = playersCount - 1; + Boolean[] isConnectedAt = new Boolean[width]; + Arrays.fill(isConnectedAt, false); + lines.forEach(line -> getLineConnectionStatus(isConnectedAt, line)); + return isConnectedAt; + } + + // 특정 Line의 연결 상태 확인 + private void getLineConnectionStatus(Boolean[] isConnectedAt, Line line) { + for (int i = 0; i < line.getLadderWidth(); i++) { + getPointConnectionStatus(isConnectedAt, line, i); + } + } + + // 특정 Line의 특정 Point 연결 상태 확인 + private void getPointConnectionStatus(Boolean[] isConnectedAt, Line line, int i) { + if (line.getPoints().get(i).isConnected()) { + isConnectedAt[i] = true; + } + } + + public int getLadderHeight() { + return height.getLadderHeight(); + } + + public int getLadderWidth(Players players) { + return players.size(); + } + + public Position getGoalsPosition(Position position) { + for (Line line : lines) { + line.tryMoveAt(position); + } + return position; + } + + public List getLines() { + return List.copyOf(lines); + } +} From ea15772b5da7b8591201012b4c031b1a774b1c01 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:59:21 +0900 Subject: [PATCH 08/24] =?UTF-8?q?feat:=20Line=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/ladder/Line.java | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/model/ladder/Line.java diff --git a/src/main/java/model/ladder/Line.java b/src/main/java/model/ladder/Line.java new file mode 100644 index 00000000..27997b76 --- /dev/null +++ b/src/main/java/model/ladder/Line.java @@ -0,0 +1,67 @@ +package model.ladder; + +import java.util.ArrayList; +import java.util.List; +import model.player.Position; +import util.LadderGenerator; + +public class Line { + + private final List points; + + public Line(List points) { + this.points = new ArrayList<>(points); + } + + public static Line create(int PlayerCount, LadderGenerator ladderGenerator) { + List points = new ArrayList<>(); + for (int i = 0; i < PlayerCount - 1; i++) { + makeLine(points, ladderGenerator); + } + return new Line(points); + } + + private static void makeLine(List points, LadderGenerator ladderGenerator) { + if (points.isEmpty()) { // 비어 있을 땐, 랜덤 생성 + points.add(Point.of(ladderGenerator.generate())); + return; + } + if (points.get(points.size() - 1).isConnected()) { // 연속 연결 방지 + points.add(Point.DISCONNECTED); + return; + } + points.add(Point.of(ladderGenerator.generate())); // 다시 랜덤 생성 + } + + public void tryMoveAt(Position position) { + if (isRightPassable(position)) { + position.moveToRight(); + return; + } + if (isLeftPassable(position)) { + position.moveToLeft(); + } + } + + private boolean isRightPassable(Position position) { + if (position.getValue() == points.size()) { // 오른쪽 끝, 이동 불가 + return false; + } + return points.get(position.getValue()).isConnected(); + } + + private boolean isLeftPassable(Position position) { + if (position.getValue() == Position.MINIMUM_POSITION) { // 왼쪽 끝, 이동 불가 + return false; + } + return points.get(position.getValue() - 1).isConnected(); + } + + public List getPoints() { + return List.copyOf(points); + } + + public int getLadderWidth() { + return points.size(); + } +} From 8c3d3752369690c93acf0aa421f1721c21517c0c Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:59:42 +0900 Subject: [PATCH 09/24] =?UTF-8?q?readme=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..1bd5d5c5 --- /dev/null +++ b/README.md @@ -0,0 +1,46 @@ +# 사다리 게임(Ladder Game) + +## 🎯 게임 개요 + +이 게임은 참여 인원과 실행 결과를 입력하여 개인별 결과를 출력해주는 사다리 게임입니다! + +## 📌 게임 진행 방식 + +- **참여 인원 입력**: 참여 인원의 이름을 입력해주세요. (이름은 쉼표(,)를 기준으로 구분하고 최대 5글자) +- **실행 결과 입력**: 원하는 실행 결과를 입력해주세요. (쉼표(,)를 기준으로 구분, 예시-꽝, 5000 등) +- **사다리 높이 입력**: 원하는 사다리 높이를 입력해주세요. +- **전체 결과 발표**: 전체 사다리 결과가 나옵니다. +- **지목 결과 발표**: 지목한 사람의 실행 결과를 확인합니다. (예-tommy or all) + +## 🚀 실행 방법 + +1. 프로그램을 실행합니다. +2. 참여 인원과 실행 결과를 입력합니다. +3. 사다리 높이를 입력해 사다리를 만듭니다. +4. 궁금한 사람의 이름을 지목하여 그 결과를 확인하세요! 🎉 + +## 🛠 주요 기능 + +- **사다리 생성**: 원하는 높이의 사다리 생성. +- **결과 계산**: 각 인원의 사다리 타기 결과 계산. + +## ✅ 체크리스트 + +### 요구사항 +- [v] 게임 개요 및 진행 방식 정리 +- [v] 필요한 기능 도출 (입력, 번호 생성, 결과 처리) + +### 리팩토링 +- [v] enum 클래스 이용 +- [v] 매직 넘버 제거 +- [v] indent depth 1까지 허용 +- [v] 일급 컬렉션 사용 +- [v] 함수형 문법 사용 +- [v] 모든 엔티티 작게 유지 + +### 테스트 +- [v] 정상 입력값에 대한 동작 확인 +- [v] 잘못된 입력값 처리 테스트 +- [v] 사다리 생성 동작 확인 +- [v] 결과값 확인 + From b072ff6afd66ffd3d9a2df9717ca29767b8468ab Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 15:59:55 +0900 Subject: [PATCH 10/24] =?UTF-8?q?feat:=20Position=20=EA=B0=9D=EC=B2=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/player/Position.java | 46 ++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/model/player/Position.java diff --git a/src/main/java/model/player/Position.java b/src/main/java/model/player/Position.java new file mode 100644 index 00000000..22986488 --- /dev/null +++ b/src/main/java/model/player/Position.java @@ -0,0 +1,46 @@ +package model.player; + +import java.util.Objects; + +public class Position { + + public static final int MINIMUM_POSITION = 0; + private int value; + + public Position(int value) { + this.value = value; + } + + public void moveToRight() { + value++; + } + + public void moveToLeft() { + if (value <= MINIMUM_POSITION) { + throw new IllegalArgumentException("Position의 값은 음수가 될 수 없습니다."); + } + value--; + } + + public int getValue() { + return value; + } + + @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 Objects.hash(value); + } + +} From de6ab68d5d7b1c2ae2364b6fe4628092de572d1b Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:00:10 +0900 Subject: [PATCH 11/24] =?UTF-8?q?feat:=20LadderHeight=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/ladder/LadderHeight.java | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/model/ladder/LadderHeight.java diff --git a/src/main/java/model/ladder/LadderHeight.java b/src/main/java/model/ladder/LadderHeight.java new file mode 100644 index 00000000..c37b9983 --- /dev/null +++ b/src/main/java/model/ladder/LadderHeight.java @@ -0,0 +1,23 @@ +package model.ladder; + +public class LadderHeight { + + private static final int MAXIMUM_LADDER_HEIGHT = 20; + + private final int height; + + public LadderHeight(int height, int playerCount) { + validateLadderHeight(height, playerCount); + this.height = height; + } + + private void validateLadderHeight(int height, int playerCount) { + if (height < playerCount - 1 || height > MAXIMUM_LADDER_HEIGHT) { + throw new IllegalArgumentException("사다리의 높이는 (플레이어 수 - 1) 이상, 20 이하의 숫자만 가능합니다."); + } + } + + public int getLadderHeight() { + return height; + } +} From 17e5f240607cf0ade31d11d1e0ffa24d8459439a Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:01:53 +0900 Subject: [PATCH 12/24] =?UTF-8?q?feat:=204=EB=8B=A8=EA=B3=84=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/OutputView.java | 86 ++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 7b72ac7a..f420831f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,23 +1,89 @@ package view; -import model.Ladder; -import model.Status; +import java.util.List; +import model.goal.Goal; +import model.goal.Goals; +import model.ladder.Ladder; +import model.player.Player; +import model.player.Players; +import model.ladder.Point; import java.util.Map; public class OutputView { - public void printLadder(Ladder ladder) { + + private static final int MAXIMUM_PLAYER_NAME_SPACE = 6; + private static final String EXECUTION_RESULT = "실행 결과"; + private static final String CONNECTED_LINE="-----|"; + private static final String DISCONNECTED_LINE=" |"; + private static final String EDGE_OF_POINT="|"; + + public void printLadder(Ladder ladder, Players players, Goals goals) { + printPlayerNamers(players); + printLadderLines(ladder); + printGoals(goals); + } + + private void printPlayerNamers(Players players) { + for (Player player : players.getPlayers()) { + System.out.printf("%-" + MAXIMUM_PLAYER_NAME_SPACE + "s", player.getName().getName()); + } + System.out.println(); + } + + private void printLadderLines(Ladder ladder) { for (var line : ladder.getLines()) { - System.out.print("|"); - for (Status status : line.getPoints()) { - System.out.print(status.getStatus() ? "----|" : " |"); - } - System.out.println(); + printLine(line.getPoints()); + } + } + + private void printLine(List points) { + System.out.print(" "+EDGE_OF_POINT); + for (var point : points) { + printPoint(point); + } + System.out.println(); + } + + private void printPoint(Point point) { + if(point.isConnected()){ + System.out.print(CONNECTED_LINE); + return; } + System.out.print(DISCONNECTED_LINE); } - public void printResults(Map results) { + private void printGoals(Goals goals) { + System.out.print(" "); + for (Goal goal : goals.getGoals()) { + System.out.printf("%-" + MAXIMUM_PLAYER_NAME_SPACE + "s", goal.getGoal()); + } + System.out.println(); + } + + public void printResult(String input, Players players, Map results) { + System.out.println("\n" + EXECUTION_RESULT); + if (input.equals("all")) { + printAllResults(results); + return; + } + printSingleResult(input, players, results); + } + + private void printAllResults(Map results) { for (var entry : results.entrySet()) { - System.out.println(entry.getKey() + " -> " + entry.getValue()); + System.out.println(entry.getKey().getName().getName() + " : " + entry.getValue().getGoal()); + } + } + + private void printSingleResult(String name, Players players, Map results) { + for (Player player : players.getPlayers()) { + printPlayerResult(name, player, results); + } + } + + private void printPlayerResult(String name, Player player, Map results) { + if (player.getName().getName().equals(name)) { + System.out.println(results.get(player).getGoal()); } } } From 8ede05c397cd3effcfb41b12c55274ef9a8e6779 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:02:05 +0900 Subject: [PATCH 13/24] =?UTF-8?q?feat:=20test=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/model/goal/GoalTest.java | 27 ++++++ src/test/java/model/goal/GoalsTest.java | 23 +++++ .../java/model/ladder/LadderHeightTest.java | 37 ++++++++ src/test/java/model/ladder/LadderTest.java | 85 +++++++++++++++++++ src/test/java/model/ladder/LineTest.java | 45 ++++++++++ src/test/java/model/ladder/PositionTest.java | 44 ++++++++++ .../java/model/player/PlayerNameTest.java | 27 ++++++ src/test/java/model/player/PlayerTest.java | 38 +++++++++ src/test/java/model/player/PlayersTest.java | 36 ++++++++ 9 files changed, 362 insertions(+) create mode 100644 src/test/java/model/goal/GoalTest.java create mode 100644 src/test/java/model/goal/GoalsTest.java create mode 100644 src/test/java/model/ladder/LadderHeightTest.java create mode 100644 src/test/java/model/ladder/LadderTest.java create mode 100644 src/test/java/model/ladder/LineTest.java create mode 100644 src/test/java/model/ladder/PositionTest.java create mode 100644 src/test/java/model/player/PlayerNameTest.java create mode 100644 src/test/java/model/player/PlayerTest.java create mode 100644 src/test/java/model/player/PlayersTest.java diff --git a/src/test/java/model/goal/GoalTest.java b/src/test/java/model/goal/GoalTest.java new file mode 100644 index 00000000..cf15d54c --- /dev/null +++ b/src/test/java/model/goal/GoalTest.java @@ -0,0 +1,27 @@ +package model.goal; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class GoalTest { + + @DisplayName("정상적으로 Goal 객체를 생성한다") + @Test + void createGoal() { + assertDoesNotThrow(() -> new Goal("꽝")); + } + + @ParameterizedTest + @ValueSource(strings = {"결과가너무너무길때", " "}) + @DisplayName("플레이어 이름이 공백이거나 6글자 이상이면 예외가 발생한다") + void throwExceptionWhenExceedsFive(String goal) { + assertThatThrownBy(() -> new Goal(goal)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("실행 결과는 1~5글자여야 합니다."); + } +} diff --git a/src/test/java/model/goal/GoalsTest.java b/src/test/java/model/goal/GoalsTest.java new file mode 100644 index 00000000..42679ea4 --- /dev/null +++ b/src/test/java/model/goal/GoalsTest.java @@ -0,0 +1,23 @@ +package model.goal; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class GoalsTest { + + @Test + @DisplayName("플레이어의 수와 다른 갯수의 결과가 입력되면 예외를 반환한다") + void throwExceptionWhenNotMatches() { + // Given + List goals = List.of(new Goal("당첨"), new Goal("꽝")); + int playerCount = 3; + + // When & Then + assertThatThrownBy(() -> new Goals(goals, playerCount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행 결과 수와 참여자 수는 같아야 합니다."); + } +} diff --git a/src/test/java/model/ladder/LadderHeightTest.java b/src/test/java/model/ladder/LadderHeightTest.java new file mode 100644 index 00000000..92378c4e --- /dev/null +++ b/src/test/java/model/ladder/LadderHeightTest.java @@ -0,0 +1,37 @@ +package model.ladder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class LadderHeightTest { + + @Test + @DisplayName("정상적으로 LadderHeight 객체가 생성된다") + void createLadderHeight() { + // Given + int height = 5; + int player = 5; + + // When + LadderHeight ladderHeight = new LadderHeight(height, player); + + // Then + assertThat(ladderHeight.getLadderHeight()).isEqualTo(height); + } + + @Test + @DisplayName("사다리 높이가 (플레이어 - 1) 작거나 20보다 크면 예외가 발생한다") + void throwExceptionHeightWhenIsBetween() { + // Given + int invalidHeight = 10; + int playerCount = 15; + + // When & Then + assertThatThrownBy(() -> new LadderHeight(invalidHeight, playerCount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("사다리의 높이는 (플레이어 수 - 1) 이상, 20 이하의 숫자만 가능합니다."); + } +} diff --git a/src/test/java/model/ladder/LadderTest.java b/src/test/java/model/ladder/LadderTest.java new file mode 100644 index 00000000..de2f03b0 --- /dev/null +++ b/src/test/java/model/ladder/LadderTest.java @@ -0,0 +1,85 @@ +package model.ladder; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import model.TestLadderGenerator; +import model.player.Player; +import model.player.PlayerName; +import model.player.Players; +import model.player.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import util.RandomLadderGenerator; + +class LadderTest { + @Test + @DisplayName("Ladder는 올바른 높이와 플레이어 수에 맞는 라인을 생성한다") + void createLadder() { + // Given + int playerCount = 4; + LadderHeight height = new LadderHeight(5,playerCount); + + List playersList = List.of( + new Player(new PlayerName("a"), new Position(0)), + new Player(new PlayerName("b"), new Position(1)), + new Player(new PlayerName("c"), new Position(2)), + new Player(new PlayerName("d"), new Position(3)) + ); + Players players = new Players(playersList); + + // When + Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); + + // Then + assertThat(ladder.getLadderHeight()).isEqualTo(5); + assertThat(ladder.getLadderWidth(players)).isEqualTo(4); + assertThat(ladder.getLines().size()).isEqualTo(5); + } + + @Test + @DisplayName("플레이어가 다르다면 서로 다른 결과 위치를 반환해주어야 한다") + void getDifferentStartEndPosition(){ + // Given + LadderHeight height = new LadderHeight(2, 3); + List playersList = List.of( + new Player(new PlayerName("a"), new Position(0)), + new Player(new PlayerName("b"), new Position(1)), + new Player(new PlayerName("c"), new Position(2)) + ); + Players players = new Players(playersList); + Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); + + // When + Position first = ladder.getGoalsPosition(new Position(0)); + Position second = ladder.getGoalsPosition(new Position(1)); + + // Then + assertThat(first).isNotEqualTo(second); + } + + @ParameterizedTest + @CsvSource(value = {"0:3", "1:1", "2:2", "3:0"}, delimiter = ':') + @DisplayName("사다리의 결과에 맞는 시작 위치, 도착 위치를 반환해주어야 한다") + void getAppropriatePosition(int start, int end) { + // Given + List orderList = List.of(true, true, false, true, true, true); + LadderHeight height = new LadderHeight(3,4); + List playersList = List.of( + new Player(new PlayerName("a"), new Position(0)), + new Player(new PlayerName("b"), new Position(1)), + new Player(new PlayerName("c"), new Position(2)), + new Player(new PlayerName("d"), new Position(3)) + ); + Players players = new Players(playersList); + Ladder ladder = Ladder.of(players, height, new TestLadderGenerator(orderList)); + + // When + Position results = ladder.getGoalsPosition(new Position(start)); + + // Then + assertThat(results.getValue()).isEqualTo(end); + } +} diff --git a/src/test/java/model/ladder/LineTest.java b/src/test/java/model/ladder/LineTest.java new file mode 100644 index 00000000..9884c692 --- /dev/null +++ b/src/test/java/model/ladder/LineTest.java @@ -0,0 +1,45 @@ +package model.ladder; + +import static model.ladder.Point.CONNECTED; +import static model.ladder.Point.DISCONNECTED; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import model.TestLadderGenerator; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import util.RandomLadderGenerator; + +class LineTest { + + @Test + @DisplayName("인자값으로 받은 playerCount -1 개 만큼의 Point를 가진다") + void createLine() { + // Given + int playerCount = 3; + + // When + Line line = Line.create(3, new RandomLadderGenerator()); + List points = line.getPoints(); + + // Then + assertThat(points.size()).isEqualTo(playerCount - 1); + } + + @Test + @DisplayName("Point 들은 연속된 다리를 가질 수 없다") + void pointCanNotHaveDuplicate() { + int playerCount = 4; + List orderList = List.of( + true, + true, + true + ); + + Line line = Line.create(playerCount, new TestLadderGenerator(orderList)); + List points = line.getPoints(); + + assertThat(points).containsExactly(CONNECTED, DISCONNECTED, CONNECTED); + } + +} diff --git a/src/test/java/model/ladder/PositionTest.java b/src/test/java/model/ladder/PositionTest.java new file mode 100644 index 00000000..7dad4993 --- /dev/null +++ b/src/test/java/model/ladder/PositionTest.java @@ -0,0 +1,44 @@ +package model.ladder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import model.player.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PositionTest { + + @Test + @DisplayName("정상적으로 객체를 가진다") + void createPosition() { + // Given + Position position = new Position(5); + + // When & Then + assertThat(position.getValue()).isEqualTo(5); + } + + @Test + @DisplayName("position은 값이 0 이하로 내려갈 수 없다") + void throwExceptionWhenPositionIsNegative() { + // Given + Position position = new Position(-0); + + // When & Then + assertThatThrownBy(() -> position.moveToLeft()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Position의 값은 음수가 될 수 없습니다."); + } + + @Test + @DisplayName("같은 값을 가진 Position 객체는 equals가 true를 반환한다") + void equalsShouldBeTrue() { + // Given + Position position1 = new Position(5); + Position position2 = new Position(5); + + // When & Then + assertThat(position1.equals(position2)).isTrue(); + } +} diff --git a/src/test/java/model/player/PlayerNameTest.java b/src/test/java/model/player/PlayerNameTest.java new file mode 100644 index 00000000..be5d82c9 --- /dev/null +++ b/src/test/java/model/player/PlayerNameTest.java @@ -0,0 +1,27 @@ +package model.player; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +class PlayerNameTest { + + @ParameterizedTest + @ValueSource(strings = {"a", "abc", "abcde"}) + @DisplayName("플레이어 이름이 1글자에서 5글자 사이면 정상적으로 생성된다") + void createWhenPlayerNameIsBetween(String name) { + assertThatNoException().isThrownBy(() -> new PlayerName(name)); + } + + @ParameterizedTest + @ValueSource(strings = {"abcdef", "hahahaha", " "}) + @DisplayName("플레이어 이름이 공백이거나 6글자 이상이면 예외가 발생한다") + void throwExceptionWhenExceedsFive(String name) { + assertThatThrownBy(() -> new PlayerName(name)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("플레이어의 이름은 1~5글자여야 합니다."); + } +} diff --git a/src/test/java/model/player/PlayerTest.java b/src/test/java/model/player/PlayerTest.java new file mode 100644 index 00000000..75b8826c --- /dev/null +++ b/src/test/java/model/player/PlayerTest.java @@ -0,0 +1,38 @@ +package model.player; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PlayerTest { + + @Test + @DisplayName("정상적으로 Player 객체를 생성한다") + void playerShouldHaveNameAndPosition() { + // Given + PlayerName playerName = new PlayerName("abc"); + Position position = new Position(5); + Player player = new Player(playerName, position); + + // When & Then + assertThat(player.getName()).isEqualTo(playerName); + assertThat(player.getPosition()).isEqualTo(position); + } + + @Test + @DisplayName("같은 이름이나 포지션을 가진 Player 객체는 true를 반환한다") + void playerShouldHaveNameAndPositionTrue() { + // Given + PlayerName playerName1 = new PlayerName("abc"); + Position position1 = new Position(5); + Player player1 = new Player(playerName1, position1); + + PlayerName playerName2 = new PlayerName("abc"); + Position position2 = new Position(5); + Player player2 = new Player(playerName2, position2); + + // When & Then + assertThat(player1).isEqualTo(player2); + } +} diff --git a/src/test/java/model/player/PlayersTest.java b/src/test/java/model/player/PlayersTest.java new file mode 100644 index 00000000..a55c2623 --- /dev/null +++ b/src/test/java/model/player/PlayersTest.java @@ -0,0 +1,36 @@ +package model.player; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PlayersTest { + + @Test + @DisplayName("플레이어가 2명 미만일 경우 예외가 발생한다") + void throwExceptionWhenLessThanTwo() { + // Given + List players = List.of(new Player(new PlayerName("abc"), new Position(2))); + + // When & Then + assertThatThrownBy(() -> new Players(players)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어는 최소 2명 이상이어야 합니다."); + } + + @Test + @DisplayName("플레이어 이름이 중복되면 예외가 발생한다") + void throwExceptionWhenDuplicate() { + // Given + Player player1 = new Player(new PlayerName("abc"), new Position(1)); + Player player2 = new Player(new PlayerName("abc"), new Position(2)); + List players = List.of(player1, player2); + + // When & Then + assertThatThrownBy(() -> new Players(players)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어의 이름은 중복될 수 없습니다."); + } +} From 840dbf52835ac60b86044929da26cde18b4dd95c Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:02:19 +0900 Subject: [PATCH 14/24] =?UTF-8?q?feat:=20TestLadderGenerator=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/model/TestLadderGenerator.java | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/java/model/TestLadderGenerator.java diff --git a/src/test/java/model/TestLadderGenerator.java b/src/test/java/model/TestLadderGenerator.java new file mode 100644 index 00000000..0752d038 --- /dev/null +++ b/src/test/java/model/TestLadderGenerator.java @@ -0,0 +1,24 @@ +package model; + +import java.util.List; +import util.LadderGenerator; + +public class TestLadderGenerator implements LadderGenerator { + + private final List values; + private int index = 0; + + public TestLadderGenerator(List values) { + this.values = values; + } + + @Override + public boolean generate() { + boolean value = values.get(index); + index++; + if (index >= values.size()) { + index = 0; + } + return value; + } +} From f2d5016a5cdef33991c7d8be4d57f088df29b78e Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:18:37 +0900 Subject: [PATCH 15/24] =?UTF-8?q?refactor:=20=EA=B2=B0=EA=B3=BC=ED=8C=90?= =?UTF-8?q?=EB=8B=A8=20controller=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/LadderController.java | 10 +++++++++- src/main/java/view/OutputView.java | 13 ++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 6c6d1cd0..09b7730a 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -83,8 +83,16 @@ private LadderHeight createLadderHeight(int playerCount) { private void showResults(Players players, Map results) { String input = inputView.inputPlayerForResult(); while (!input.isBlank()) { - outputView.printResult(input, players, results); + selectResult(input, players, results); input = inputView.inputPlayerForResult(); } } + + private void selectResult(String input, Players players, Map results) { + if(input.equals("all")){ + outputView.printAllResults(results); + return; + } + outputView.printSingleResult(input, players, results); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index f420831f..c80998a3 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -60,22 +60,13 @@ private void printGoals(Goals goals) { System.out.println(); } - public void printResult(String input, Players players, Map results) { - System.out.println("\n" + EXECUTION_RESULT); - if (input.equals("all")) { - printAllResults(results); - return; - } - printSingleResult(input, players, results); - } - - private void printAllResults(Map results) { + public void printAllResults(Map results) { for (var entry : results.entrySet()) { System.out.println(entry.getKey().getName().getName() + " : " + entry.getValue().getGoal()); } } - private void printSingleResult(String name, Players players, Map results) { + public void printSingleResult(String name, Players players, Map results) { for (Player player : players.getPlayers()) { printPlayerResult(name, player, results); } From 02d33d5ce08f34bb27b9911431ba4cf62d4bfe3c Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:27:53 +0900 Subject: [PATCH 16/24] =?UTF-8?q?feat:=20name=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/player/PlayerName.java | 10 +++++++++- src/test/java/model/player/PlayerNameTest.java | 9 +++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/model/player/PlayerName.java b/src/main/java/model/player/PlayerName.java index fbd38370..30bffe82 100644 --- a/src/main/java/model/player/PlayerName.java +++ b/src/main/java/model/player/PlayerName.java @@ -4,11 +4,13 @@ public class PlayerName { - private final int MAXINUM_NAME_LENGTH = 5; private final String name; + private final String CANNOT_NAME = "all"; + private final int MAXINUM_NAME_LENGTH = 5; public PlayerName(String name) { validateName(name); + validateNaming(name); this.name = name; } @@ -18,6 +20,12 @@ private void validateName(String name) { } } + private void validateNaming(String name) { + if (name.equalsIgnoreCase(CANNOT_NAME)) { + throw new IllegalArgumentException("플레이어 이름으로 'all'은 사용할 수 없습니다."); + } + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/src/test/java/model/player/PlayerNameTest.java b/src/test/java/model/player/PlayerNameTest.java index be5d82c9..2852033e 100644 --- a/src/test/java/model/player/PlayerNameTest.java +++ b/src/test/java/model/player/PlayerNameTest.java @@ -24,4 +24,13 @@ void throwExceptionWhenExceedsFive(String name) { .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("플레이어의 이름은 1~5글자여야 합니다."); } + + @ParameterizedTest + @ValueSource(strings = {"all", "ALL", "aLl"}) + @DisplayName("플레이어 이름이 'all'이면 예외가 발생한다") + void throwExceptionWhenNameIsAll(String name) { + assertThatThrownBy(() -> new PlayerName(name)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("플레이어 이름으로 'all'은 사용할 수 없습니다."); + } } From 8decdbf69e95dc315a8cea4ddd9c345fbfbe822a Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:49:35 +0900 Subject: [PATCH 17/24] =?UTF-8?q?feat:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EC=A1=B4=EC=9E=AC=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/LadderController.java | 18 ++++++++++++++---- src/main/java/model/player/Players.java | 11 +++++++++++ src/test/java/model/player/PlayersTest.java | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 09b7730a..caba78e2 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -43,7 +43,7 @@ public void run() { } private Players createPlayers() { - try{ + try { List rawNames = inputView.inputPlayers(); List players = new ArrayList<>(); for (int i = 0; i < rawNames.size(); i++) { @@ -71,7 +71,7 @@ private Goals createGoals(Players players) { } private LadderHeight createLadderHeight(int playerCount) { - try{ + try { int height = inputView.inputLadderHeight(); return new LadderHeight(height, playerCount); } catch (IllegalArgumentException e) { @@ -83,16 +83,26 @@ private LadderHeight createLadderHeight(int playerCount) { private void showResults(Players players, Map results) { String input = inputView.inputPlayerForResult(); while (!input.isBlank()) { + input = processResultInput(input, players, results); + } + } + + private String processResultInput(String input, Players players, Map results) { + try { selectResult(input, players, results); - input = inputView.inputPlayerForResult(); + return inputView.inputPlayerForResult(); + } catch (IllegalArgumentException e) { + System.out.println(INPUT_EXCEPTION_MESSAGE); + return inputView.inputPlayerForResult(); } } private void selectResult(String input, Players players, Map results) { - if(input.equals("all")){ + if (input.equals("all")) { outputView.printAllResults(results); return; } + players.validateContainsPlayer(input); outputView.printSingleResult(input, players, results); } } diff --git a/src/main/java/model/player/Players.java b/src/main/java/model/player/Players.java index 03934051..5c3dd75f 100644 --- a/src/main/java/model/player/Players.java +++ b/src/main/java/model/player/Players.java @@ -29,6 +29,17 @@ private void validateDuplicate(List players) { } } + public void validateContainsPlayer(String input) { + if (!this.containsPlayer(input)) { + throw new IllegalArgumentException("해당 이름의 플레이어가 존재하지 않습니다: " + input); + } + } + + public boolean containsPlayer(String name) { + return players.stream() + .anyMatch(player -> player.getName().getName().equals(name)); + } + public int size() { return players.size(); } diff --git a/src/test/java/model/player/PlayersTest.java b/src/test/java/model/player/PlayersTest.java index a55c2623..66bdd1b3 100644 --- a/src/test/java/model/player/PlayersTest.java +++ b/src/test/java/model/player/PlayersTest.java @@ -33,4 +33,18 @@ void throwExceptionWhenDuplicate() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("플레이어의 이름은 중복될 수 없습니다."); } + + @Test + @DisplayName("존재하지 않는 플레이어 이름 입력 시 예외가 발생한다") + void throwExceptionWhenInvalidName() { + // Given + Player player1 = new Player(new PlayerName("a"), new Position(0)); + Player player2 = new Player(new PlayerName("b"), new Position(1)); + Players players = new Players(List.of(player1, player2)); + + // When & Then + assertThatThrownBy(() -> players.validateContainsPlayer("invalid")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("해당 이름의 플레이어가 존재하지 않습니다: invalid"); + } } From e2ee985d0319a2ced0513813bcf07a9aab018467 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 16:50:05 +0900 Subject: [PATCH 18/24] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=EB=AC=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/OutputView.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index c80998a3..1f0101e9 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -12,12 +12,14 @@ public class OutputView { private static final int MAXIMUM_PLAYER_NAME_SPACE = 6; - private static final String EXECUTION_RESULT = "실행 결과"; + private static final String EXECUTION_RESULT = "\n실행 결과"; + private static final String LADDER_RESULT_HEADER = "\n사다리 결과\n"; private static final String CONNECTED_LINE="-----|"; private static final String DISCONNECTED_LINE=" |"; private static final String EDGE_OF_POINT="|"; public void printLadder(Ladder ladder, Players players, Goals goals) { + System.out.println(LADDER_RESULT_HEADER); printPlayerNamers(players); printLadderLines(ladder); printGoals(goals); @@ -61,12 +63,14 @@ private void printGoals(Goals goals) { } public void printAllResults(Map results) { + System.out.println(EXECUTION_RESULT); for (var entry : results.entrySet()) { System.out.println(entry.getKey().getName().getName() + " : " + entry.getValue().getGoal()); } } public void printSingleResult(String name, Players players, Map results) { + System.out.println(EXECUTION_RESULT); for (Player player : players.getPlayers()) { printPlayerResult(name, player, results); } From 17c809c924a7003867956f4365469c30e6474d0e Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 2 May 2025 17:22:40 +0900 Subject: [PATCH 19/24] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/view/OutputView.java | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 1f0101e9..79f55f43 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -11,12 +11,14 @@ public class OutputView { - private static final int MAXIMUM_PLAYER_NAME_SPACE = 6; + private static final int NAME_WIDTH = 6; private static final String EXECUTION_RESULT = "\n실행 결과"; private static final String LADDER_RESULT_HEADER = "\n사다리 결과\n"; - private static final String CONNECTED_LINE="-----|"; - private static final String DISCONNECTED_LINE=" |"; - private static final String EDGE_OF_POINT="|"; + private static final String CONNECTED_LINE = "-----|"; + private static final String DISCONNECTED_LINE = " |"; + private static final String EDGE_OF_POINT = "|"; + private static final String START_PADDING = " "; + private static final String SINGLE_SPACE = " "; public void printLadder(Ladder ladder, Players players, Goals goals) { System.out.println(LADDER_RESULT_HEADER); @@ -27,7 +29,9 @@ public void printLadder(Ladder ladder, Players players, Goals goals) { private void printPlayerNamers(Players players) { for (Player player : players.getPlayers()) { - System.out.printf("%-" + MAXIMUM_PLAYER_NAME_SPACE + "s", player.getName().getName()); + String name = player.getName().getName(); + int padding = NAME_WIDTH - 1 - name.length(); + System.out.print(SINGLE_SPACE.repeat(padding) + name + SINGLE_SPACE); } System.out.println(); } @@ -39,7 +43,7 @@ private void printLadderLines(Ladder ladder) { } private void printLine(List points) { - System.out.print(" "+EDGE_OF_POINT); + System.out.print(START_PADDING + EDGE_OF_POINT); for (var point : points) { printPoint(point); } @@ -47,7 +51,7 @@ private void printLine(List points) { } private void printPoint(Point point) { - if(point.isConnected()){ + if (point.isConnected()) { System.out.print(CONNECTED_LINE); return; } @@ -55,9 +59,10 @@ private void printPoint(Point point) { } private void printGoals(Goals goals) { - System.out.print(" "); for (Goal goal : goals.getGoals()) { - System.out.printf("%-" + MAXIMUM_PLAYER_NAME_SPACE + "s", goal.getGoal()); + String text = goal.getGoal(); + int padding = NAME_WIDTH - 1 - text.length(); + System.out.print(SINGLE_SPACE.repeat(padding) + text + SINGLE_SPACE); } System.out.println(); } From 3c75d42a6df5ce6de3b6b17559a7aa26b4938b85 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Mon, 5 May 2025 03:21:03 +0900 Subject: [PATCH 20/24] =?UTF-8?q?refactor:=20=EB=B0=A9=EC=96=B4=EC=A0=81?= =?UTF-8?q?=20=EB=B3=B5=EC=82=AC=20=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/goal/Goals.java | 2 +- src/main/java/model/ladder/Line.java | 6 +++--- src/main/java/model/ladder/Point.java | 2 +- src/main/java/model/player/Players.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/model/goal/Goals.java b/src/main/java/model/goal/Goals.java index 8290d930..1f83f12b 100644 --- a/src/main/java/model/goal/Goals.java +++ b/src/main/java/model/goal/Goals.java @@ -9,7 +9,7 @@ public class Goals { public Goals(List goals, int playerCount) { validateGoals(goals, playerCount); - this.goals = new ArrayList<>(goals); + this.goals = List.copyOf(goals); } diff --git a/src/main/java/model/ladder/Line.java b/src/main/java/model/ladder/Line.java index 27997b76..50a91f38 100644 --- a/src/main/java/model/ladder/Line.java +++ b/src/main/java/model/ladder/Line.java @@ -10,7 +10,7 @@ public class Line { private final List points; public Line(List points) { - this.points = new ArrayList<>(points); + this.points = List.copyOf(points); } public static Line create(int PlayerCount, LadderGenerator ladderGenerator) { @@ -23,14 +23,14 @@ public static Line create(int PlayerCount, LadderGenerator ladderGenerator) { private static void makeLine(List points, LadderGenerator ladderGenerator) { if (points.isEmpty()) { // 비어 있을 땐, 랜덤 생성 - points.add(Point.of(ladderGenerator.generate())); + points.add(Point.from(ladderGenerator.generate())); return; } if (points.get(points.size() - 1).isConnected()) { // 연속 연결 방지 points.add(Point.DISCONNECTED); return; } - points.add(Point.of(ladderGenerator.generate())); // 다시 랜덤 생성 + points.add(Point.from(ladderGenerator.generate())); // 다시 랜덤 생성 } public void tryMoveAt(Position position) { diff --git a/src/main/java/model/ladder/Point.java b/src/main/java/model/ladder/Point.java index 9e471bcc..e2af0d9d 100644 --- a/src/main/java/model/ladder/Point.java +++ b/src/main/java/model/ladder/Point.java @@ -4,7 +4,7 @@ public enum Point { CONNECTED, DISCONNECTED; - public static Point of(boolean status) { + public static Point from(boolean status) { if (status) { return CONNECTED; } diff --git a/src/main/java/model/player/Players.java b/src/main/java/model/player/Players.java index 5c3dd75f..06ecdd18 100644 --- a/src/main/java/model/player/Players.java +++ b/src/main/java/model/player/Players.java @@ -11,7 +11,7 @@ public class Players { public Players(List players) { validatePlayerCount(players); validateDuplicate(players); - this.players = players; + this.players = List.copyOf(players);; } private void validatePlayerCount(List players) { From 85a2870b79cb8000d2b57010504cb3939b077a20 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Tue, 6 May 2025 23:42:50 +0900 Subject: [PATCH 21/24] =?UTF-8?q?refactor:=20=ED=94=BC=EB=93=9C=EB=B0=B1?= =?UTF-8?q?=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 15 +- .../java/controller/LadderController.java | 132 ++++++++---------- src/main/java/model/LadderGame.java | 26 ++-- src/main/java/model/goal/Goal.java | 27 ++-- src/main/java/model/goal/Goals.java | 39 ++++-- src/main/java/model/ladder/Ladder.java | 118 ++++++++-------- src/main/java/model/ladder/LadderHeight.java | 26 ++-- src/main/java/model/ladder/Line.java | 88 ++++++------ src/main/java/model/ladder/Point.java | 20 +-- src/main/java/model/player/Player.java | 60 ++++---- src/main/java/model/player/PlayerName.java | 72 +++++----- src/main/java/model/player/Players.java | 82 +++++++---- src/main/java/model/player/Position.java | 60 ++++---- src/main/java/util/LadderGenerator.java | 2 +- src/main/java/util/RandomLadderGenerator.java | 10 +- src/main/java/view/InputView.java | 83 +++++------ src/main/java/view/OutputView.java | 120 ++++++++-------- src/test/java/model/TestLadderGenerator.java | 26 ++-- src/test/java/model/goal/GoalTest.java | 26 ++-- src/test/java/model/goal/GoalsTest.java | 22 +-- .../java/model/ladder/LadderHeightTest.java | 52 +++---- src/test/java/model/ladder/LadderTest.java | 117 ++++++++-------- src/test/java/model/ladder/LineTest.java | 58 ++++---- src/test/java/model/ladder/PositionTest.java | 64 ++++----- .../java/model/player/PlayerNameTest.java | 44 +++--- src/test/java/model/player/PlayerTest.java | 56 ++++---- src/test/java/model/player/PlayersTest.java | 78 +++++------ 27 files changed, 777 insertions(+), 746 deletions(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 106d94f0..0b20749e 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -4,11 +4,12 @@ import view.OutputView; public class Application { - public static void main(String[] args) { - InputView inputView = new InputView(); - OutputView outputView = new OutputView(); - RandomLadderGenerator generator = new RandomLadderGenerator(); - LadderController controller = new LadderController(inputView, outputView, generator); - controller.run(); - } + + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + RandomLadderGenerator generator = new RandomLadderGenerator(); + LadderController controller = new LadderController(inputView, outputView, generator); + controller.run(); + } } diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index caba78e2..36aa4629 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -21,88 +21,80 @@ public class LadderController { - private final InputView inputView; - private final OutputView outputView; - private final LadderGenerator generator; + private final InputView inputView; + private final OutputView outputView; + private final LadderGenerator generator; - public LadderController(InputView inputView, OutputView outputView, LadderGenerator generator) { - this.inputView = inputView; - this.outputView = outputView; - this.generator = generator; - } + public LadderController(InputView inputView, OutputView outputView, LadderGenerator generator) { + this.inputView = inputView; + this.outputView = outputView; + this.generator = generator; + } - public void run() { - Players players = createPlayers(); - Goals goals = createGoals(players); - LadderHeight height = createLadderHeight(players.size()); - Ladder ladder = Ladder.of(players, height, generator); - LadderGame game = new LadderGame(ladder); - Map results = game.play(players, goals); - outputView.printLadder(ladder, players, goals); - showResults(players, results); - } + public void run() { + Players players = createPlayers(); + Goals goals = createGoals(players); + LadderHeight height = createLadderHeight(players.size()); + Ladder ladder = Ladder.of(players, height, generator); + LadderGame game = new LadderGame(ladder); + Map results = game.play(players, goals); + outputView.printLadder(ladder, players, goals); + showResults(players, results); + } - private Players createPlayers() { - try { - List rawNames = inputView.inputPlayers(); - List players = new ArrayList<>(); - for (int i = 0; i < rawNames.size(); i++) { - players.add(new Player(new PlayerName(rawNames.get(i)), - new Position(i))); - } - return new Players(players); - } catch (IllegalArgumentException e) { - System.out.println(INPUT_EXCEPTION_MESSAGE); - return createPlayers(); + private Players createPlayers() { + try { + List rawNames = inputView.inputPlayers(); + return Players.from(rawNames); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + return createPlayers(); + } } - } - private Goals createGoals(Players players) { - try { - List rawGoals = inputView.inputGoals(players); - List goalList = rawGoals.stream() - .map(Goal::new) - .collect(Collectors.toList()); - return new Goals(goalList, players.size()); - } catch (IllegalArgumentException e) { - System.out.println(INPUT_EXCEPTION_MESSAGE); - return createGoals(players); + private Goals createGoals(Players players) { + try { + List rawGoals = inputView.inputGoals(); + return Goals.from(rawGoals, players.size()); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + return createGoals(players); + } } - } - private LadderHeight createLadderHeight(int playerCount) { - try { - int height = inputView.inputLadderHeight(); - return new LadderHeight(height, playerCount); - } catch (IllegalArgumentException e) { - System.out.println(INPUT_EXCEPTION_MESSAGE); - return createLadderHeight(playerCount); + private LadderHeight createLadderHeight(int playerCount) { + try { + int height = inputView.inputLadderHeight(); + return new LadderHeight(height, playerCount); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + return createLadderHeight(playerCount); + } } - } - private void showResults(Players players, Map results) { - String input = inputView.inputPlayerForResult(); - while (!input.isBlank()) { - input = processResultInput(input, players, results); + private void showResults(Players players, Map results) { + String input = inputView.inputPlayerForResult(); + while (!input.isBlank()) { + input = processResultInput(input, players, results); + } } - } - private String processResultInput(String input, Players players, Map results) { - try { - selectResult(input, players, results); - return inputView.inputPlayerForResult(); - } catch (IllegalArgumentException e) { - System.out.println(INPUT_EXCEPTION_MESSAGE); - return inputView.inputPlayerForResult(); + private String processResultInput(String input, Players players, Map results) { + try { + selectResult(input, players, results); + return inputView.inputPlayerForResult(); + } catch (IllegalArgumentException e) { + outputView.printErrorMessage(e.getMessage()); + return inputView.inputPlayerForResult(); + } } - } - private void selectResult(String input, Players players, Map results) { - if (input.equals("all")) { - outputView.printAllResults(results); - return; + private void selectResult(String input, Players players, Map results) { + if (input.equals("all")) { + outputView.printAllResults(results); + return; + } + players.validateContainsPlayer(input); + outputView.printSingleResult(input, players, results); } - players.validateContainsPlayer(input); - outputView.printSingleResult(input, players, results); - } } diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java index b05cd608..4f3884b1 100644 --- a/src/main/java/model/LadderGame.java +++ b/src/main/java/model/LadderGame.java @@ -3,6 +3,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import model.ladder.Ladder; import model.player.Position; import model.goal.Goal; @@ -12,20 +14,18 @@ public class LadderGame { - private final Ladder ladder; + private final Ladder ladder; - public LadderGame(Ladder ladder) { - this.ladder = ladder; - } + public LadderGame(Ladder ladder) { + this.ladder = ladder; + } - public Map play(Players players, Goals goals) { - Map results = new HashMap<>(); - List playerList = players.getPlayers(); - List goalList = goals.getGoals(); - for (int start = 0; start < playerList.size(); start++) { - Position end = ladder.getGoalsPosition(new Position(start)); - results.put(playerList.get(start), goalList.get(end.getValue())); + public Map play(Players players, Goals goals) { + return IntStream.range(0, players.size()) + .boxed() + .collect(Collectors.toMap( + index -> players.getPlayerAt(index), + index -> goals.getGoalAt(ladder.getGoalsPosition(new Position(index)).getValue()) + )); } - return results; - } } diff --git a/src/main/java/model/goal/Goal.java b/src/main/java/model/goal/Goal.java index 0ff6572b..037f768e 100644 --- a/src/main/java/model/goal/Goal.java +++ b/src/main/java/model/goal/Goal.java @@ -2,23 +2,22 @@ public class Goal { - private final int MAXINUM_GOAL_LENGTH = 5; - private final String goal; + private final int MAXINUM_GOAL_LENGTH = 5; + private final String goal; - public Goal(String goal) { - validateGoal(goal); - this.goal = goal; - } - - private void validateGoal(String goal) { - if (goal == null || goal.isBlank() || goal.length() > MAXINUM_GOAL_LENGTH) { - throw new IllegalArgumentException("실행 결과는 1~5글자여야 합니다."); + public Goal(String goal) { + validateGoal(goal); + this.goal = goal; } - } + private void validateGoal(String goal) { + if (goal == null || goal.isBlank() || goal.length() > MAXINUM_GOAL_LENGTH) { + throw new IllegalArgumentException("실행 결과는 1~5글자여야 합니다."); + } + } - public String getGoal() { - return goal; - } + public String getGoal() { + return goal; + } } diff --git a/src/main/java/model/goal/Goals.java b/src/main/java/model/goal/Goals.java index 1f83f12b..8503c9c7 100644 --- a/src/main/java/model/goal/Goals.java +++ b/src/main/java/model/goal/Goals.java @@ -1,25 +1,38 @@ package model.goal; -import java.util.ArrayList; import java.util.List; public class Goals { - private final List goals; + private final List goals; - public Goals(List goals, int playerCount) { - validateGoals(goals, playerCount); - this.goals = List.copyOf(goals); + public Goals(List goals, int playerCount) { + validateGoals(goals, playerCount); + this.goals = List.copyOf(goals); - } + } + + public static Goals from(List rawGoals, int playerCount) { + List goalList = rawGoals.stream() + .map(Goal::new) + .toList(); + return new Goals(goalList, playerCount); + } - private void validateGoals(List goals, int playerCount) { - if (goals.size() != playerCount) { - throw new IllegalArgumentException("실행 결과 수와 참여자 수는 같아야 합니다."); + private void validateGoals(List goals, int playerCount) { + if (goals.size() != playerCount) { + throw new IllegalArgumentException("실행 결과 수와 참여자 수는 같아야 합니다."); + } } - } - public List getGoals() { - return List.copyOf(goals); - } + public Goal getGoalAt(int index) { + if (index < 0 || index >= goals.size()) { + throw new IllegalArgumentException("유효하지 않은 인덱스입니다: " + index); + } + return goals.get(index); + } + + public List getGoals() { + return List.copyOf(goals); + } } diff --git a/src/main/java/model/ladder/Ladder.java b/src/main/java/model/ladder/Ladder.java index 700619d0..a4157ac8 100644 --- a/src/main/java/model/ladder/Ladder.java +++ b/src/main/java/model/ladder/Ladder.java @@ -10,78 +10,78 @@ public class Ladder { - private final LadderHeight height; - private final List lines; + private final LadderHeight height; + private final List lines; - public Ladder(LadderHeight height, List lines) { - this.height = height; - this.lines = lines; - } - - public static Ladder of(Players players, LadderHeight height, LadderGenerator ladderGenerator) { - List lines = new ArrayList<>(); - Ladder ladder = new Ladder(height, lines); - ladder.addLines(players.size(), ladderGenerator); - return ladder; - } + public Ladder(LadderHeight height, List lines) { + this.height = height; + this.lines = lines; + } - private void addLines(int playersCount, LadderGenerator ladderGenerator) { - for (int i = 0; i < getLadderHeight(); i++) { - lines.add(Line.create(playersCount, ladderGenerator)); + public static Ladder of(Players players, LadderHeight height, LadderGenerator ladderGenerator) { + List lines = new ArrayList<>(); + Ladder ladder = new Ladder(height, lines); + ladder.addLines(players.size(), ladderGenerator); + return ladder; } - if (isLadderNotConnected(playersCount)) { - lines.clear(); - addLines(playersCount, ladderGenerator); + + private void addLines(int playersCount, LadderGenerator ladderGenerator) { + for (int i = 0; i < getLadderHeight(); i++) { + lines.add(Line.create(playersCount, ladderGenerator)); + } + if (isLadderNotConnected(playersCount)) { + lines.clear(); + addLines(playersCount, ladderGenerator); + } } - } - // Line이 최소 한 번 연결되었는지 검증 - private boolean isLadderNotConnected(int playersCount) { - Boolean[] isConnectedAt = getLadderConnectionStatus(playersCount); - return Arrays.stream(isConnectedAt) - .collect(Collectors.toSet()) - .size() != 1; - } + // Line이 최소 한 번 연결되었는지 검증 + private boolean isLadderNotConnected(int playersCount) { + Boolean[] isConnectedAt = getLadderConnectionStatus(playersCount); + return Arrays.stream(isConnectedAt) + .collect(Collectors.toSet()) + .size() != 1; + } - // 전체 Line별 연결 상태 확인 - private Boolean[] getLadderConnectionStatus(int playersCount) { - int width = playersCount - 1; - Boolean[] isConnectedAt = new Boolean[width]; - Arrays.fill(isConnectedAt, false); - lines.forEach(line -> getLineConnectionStatus(isConnectedAt, line)); - return isConnectedAt; - } + // 전체 Line별 연결 상태 확인 + private Boolean[] getLadderConnectionStatus(int playersCount) { + int width = playersCount - 1; + Boolean[] isConnectedAt = new Boolean[width]; + Arrays.fill(isConnectedAt, false); + lines.forEach(line -> getLineConnectionStatus(isConnectedAt, line)); + return isConnectedAt; + } - // 특정 Line의 연결 상태 확인 - private void getLineConnectionStatus(Boolean[] isConnectedAt, Line line) { - for (int i = 0; i < line.getLadderWidth(); i++) { - getPointConnectionStatus(isConnectedAt, line, i); + // 특정 Line의 연결 상태 확인 + private void getLineConnectionStatus(Boolean[] isConnectedAt, Line line) { + for (int i = 0; i < line.getLadderWidth(); i++) { + getPointConnectionStatus(isConnectedAt, line, i); + } } - } - // 특정 Line의 특정 Point 연결 상태 확인 - private void getPointConnectionStatus(Boolean[] isConnectedAt, Line line, int i) { - if (line.getPoints().get(i).isConnected()) { - isConnectedAt[i] = true; + // 특정 Line의 특정 Point 연결 상태 확인 + private void getPointConnectionStatus(Boolean[] isConnectedAt, Line line, int i) { + if (line.getPoints().get(i).isConnected()) { + isConnectedAt[i] = true; + } } - } - public int getLadderHeight() { - return height.getLadderHeight(); - } + public int getLadderHeight() { + return height.getLadderHeight(); + } - public int getLadderWidth(Players players) { - return players.size(); - } + public int getLadderWidth(Players players) { + return players.size(); + } - public Position getGoalsPosition(Position position) { - for (Line line : lines) { - line.tryMoveAt(position); + public Position getGoalsPosition(Position position) { + for (Line line : lines) { + line.tryMoveAt(position); + } + return position; } - return position; - } - public List getLines() { - return List.copyOf(lines); - } + public List getLines() { + return List.copyOf(lines); + } } diff --git a/src/main/java/model/ladder/LadderHeight.java b/src/main/java/model/ladder/LadderHeight.java index c37b9983..766675ad 100644 --- a/src/main/java/model/ladder/LadderHeight.java +++ b/src/main/java/model/ladder/LadderHeight.java @@ -2,22 +2,22 @@ public class LadderHeight { - private static final int MAXIMUM_LADDER_HEIGHT = 20; + private static final int MAXIMUM_LADDER_HEIGHT = 20; - private final int height; + private final int height; - public LadderHeight(int height, int playerCount) { - validateLadderHeight(height, playerCount); - this.height = height; - } + public LadderHeight(int height, int playerCount) { + validateLadderHeight(height, playerCount); + this.height = height; + } - private void validateLadderHeight(int height, int playerCount) { - if (height < playerCount - 1 || height > MAXIMUM_LADDER_HEIGHT) { - throw new IllegalArgumentException("사다리의 높이는 (플레이어 수 - 1) 이상, 20 이하의 숫자만 가능합니다."); + private void validateLadderHeight(int height, int playerCount) { + if (height < playerCount - 1 || height > MAXIMUM_LADDER_HEIGHT) { + throw new IllegalArgumentException("사다리의 높이는 (플레이어 수 - 1) 이상, 20 이하의 숫자만 가능합니다."); + } } - } - public int getLadderHeight() { - return height; - } + public int getLadderHeight() { + return height; + } } diff --git a/src/main/java/model/ladder/Line.java b/src/main/java/model/ladder/Line.java index 50a91f38..e99168d7 100644 --- a/src/main/java/model/ladder/Line.java +++ b/src/main/java/model/ladder/Line.java @@ -7,61 +7,61 @@ public class Line { - private final List points; + private final List points; - public Line(List points) { - this.points = List.copyOf(points); - } - - public static Line create(int PlayerCount, LadderGenerator ladderGenerator) { - List points = new ArrayList<>(); - for (int i = 0; i < PlayerCount - 1; i++) { - makeLine(points, ladderGenerator); + public Line(List points) { + this.points = List.copyOf(points); } - return new Line(points); - } - private static void makeLine(List points, LadderGenerator ladderGenerator) { - if (points.isEmpty()) { // 비어 있을 땐, 랜덤 생성 - points.add(Point.from(ladderGenerator.generate())); - return; - } - if (points.get(points.size() - 1).isConnected()) { // 연속 연결 방지 - points.add(Point.DISCONNECTED); - return; + public static Line create(int PlayerCount, LadderGenerator ladderGenerator) { + List points = new ArrayList<>(); + for (int i = 0; i < PlayerCount - 1; i++) { + makeLine(points, ladderGenerator); + } + return new Line(points); } - points.add(Point.from(ladderGenerator.generate())); // 다시 랜덤 생성 - } - public void tryMoveAt(Position position) { - if (isRightPassable(position)) { - position.moveToRight(); - return; + private static void makeLine(List points, LadderGenerator ladderGenerator) { + if (points.isEmpty()) { // 비어 있을 땐, 랜덤 생성 + points.add(Point.from(ladderGenerator.generate())); + return; + } + if (points.get(points.size() - 1).isConnected()) { // 연속 연결 방지 + points.add(Point.DISCONNECTED); + return; + } + points.add(Point.from(ladderGenerator.generate())); // 다시 랜덤 생성 } - if (isLeftPassable(position)) { - position.moveToLeft(); + + public void tryMoveAt(Position position) { + if (isRightPassable(position)) { + position.moveToRight(); + return; + } + if (isLeftPassable(position)) { + position.moveToLeft(); + } } - } - private boolean isRightPassable(Position position) { - if (position.getValue() == points.size()) { // 오른쪽 끝, 이동 불가 - return false; + private boolean isRightPassable(Position position) { + if (position.getValue() == points.size()) { // 오른쪽 끝, 이동 불가 + return false; + } + return points.get(position.getValue()).isConnected(); } - return points.get(position.getValue()).isConnected(); - } - private boolean isLeftPassable(Position position) { - if (position.getValue() == Position.MINIMUM_POSITION) { // 왼쪽 끝, 이동 불가 - return false; + private boolean isLeftPassable(Position position) { + if (position.getValue() == Position.MINIMUM_POSITION) { // 왼쪽 끝, 이동 불가 + return false; + } + return points.get(position.getValue() - 1).isConnected(); } - return points.get(position.getValue() - 1).isConnected(); - } - public List getPoints() { - return List.copyOf(points); - } + public List getPoints() { + return List.copyOf(points); + } - public int getLadderWidth() { - return points.size(); - } + public int getLadderWidth() { + return points.size(); + } } diff --git a/src/main/java/model/ladder/Point.java b/src/main/java/model/ladder/Point.java index e2af0d9d..46470ef4 100644 --- a/src/main/java/model/ladder/Point.java +++ b/src/main/java/model/ladder/Point.java @@ -1,17 +1,17 @@ package model.ladder; public enum Point { - CONNECTED, - DISCONNECTED; + CONNECTED, + DISCONNECTED; - public static Point from(boolean status) { - if (status) { - return CONNECTED; + public static Point from(boolean status) { + if (status) { + return CONNECTED; + } + return DISCONNECTED; } - return DISCONNECTED; - } - public boolean isConnected() { - return this.equals(CONNECTED); - } + public boolean isConnected() { + return this.equals(CONNECTED); + } } diff --git a/src/main/java/model/player/Player.java b/src/main/java/model/player/Player.java index c490907a..f93c1342 100644 --- a/src/main/java/model/player/Player.java +++ b/src/main/java/model/player/Player.java @@ -4,36 +4,36 @@ public class Player { - private final PlayerName name; - private final Position position; - - public Player(PlayerName name, Position position) { - this.name = name; - this.position = position; - } - - public PlayerName getName() { - return name; - } - - public Position getPosition() { - return position; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + private final PlayerName name; + private final Position position; + + public Player(PlayerName name, Position position) { + this.name = name; + this.position = position; + } + + public PlayerName getName() { + return name; + } + + public Position getPosition() { + return position; + } + + @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) && Objects.equals(position, player.position); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public int hashCode() { + return Objects.hash(name, position); } - Player player = (Player) o; - return Objects.equals(name, player.name) && Objects.equals(position, player.position); - } - - @Override - public int hashCode() { - return Objects.hash(name, position); - } } diff --git a/src/main/java/model/player/PlayerName.java b/src/main/java/model/player/PlayerName.java index 30bffe82..a2586bc1 100644 --- a/src/main/java/model/player/PlayerName.java +++ b/src/main/java/model/player/PlayerName.java @@ -4,46 +4,46 @@ public class PlayerName { - private final String name; - private final String CANNOT_NAME = "all"; - private final int MAXINUM_NAME_LENGTH = 5; - - public PlayerName(String name) { - validateName(name); - validateNaming(name); - this.name = name; - } - - private void validateName(String name) { - if (name == null || name.isBlank() || name.length() > MAXINUM_NAME_LENGTH) { - throw new IllegalArgumentException("플레이어의 이름은 1~5글자여야 합니다."); + private final String name; + private final String CANNOT_NAME = "all"; + private final int MAXINUM_NAME_LENGTH = 5; + + public PlayerName(String name) { + validateName(name); + validateNaming(name); + this.name = name; } - } - private void validateNaming(String name) { - if (name.equalsIgnoreCase(CANNOT_NAME)) { - throw new IllegalArgumentException("플레이어 이름으로 'all'은 사용할 수 없습니다."); + private void validateName(String name) { + if (name == null || name.isBlank() || name.length() > MAXINUM_NAME_LENGTH) { + throw new IllegalArgumentException("플레이어의 이름은 1~5글자여야 합니다."); + } } - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + private void validateNaming(String name) { + if (name.equalsIgnoreCase(CANNOT_NAME)) { + throw new IllegalArgumentException("플레이어 이름으로 'all'은 사용할 수 없습니다."); + } } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PlayerName that = (PlayerName) o; + return name.equals(that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + public String getName() { + return name; } - PlayerName that = (PlayerName) o; - return name.equals(that.name); - } - - @Override - public int hashCode() { - return Objects.hash(name); - } - - public String getName() { - return name; - } } diff --git a/src/main/java/model/player/Players.java b/src/main/java/model/player/Players.java index 06ecdd18..b5fec8b0 100644 --- a/src/main/java/model/player/Players.java +++ b/src/main/java/model/player/Players.java @@ -1,50 +1,70 @@ package model.player; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.IntStream; public class Players { - private final List players; + private final List players; - public Players(List players) { - validatePlayerCount(players); - validateDuplicate(players); - this.players = List.copyOf(players);; - } + public Players(List players) { + validatePlayerCount(players); + validateDuplicate(players); + this.players = List.copyOf(players); + ; + } + + public static Players from(List names) { + List players = IntStream.range(0, names.size()) + .mapToObj(i -> new Player( + new PlayerName(names.get(i)), + new Position(i) + )) + .toList(); + return new Players(players); + } + + public Player getPlayerAt(int index) { + if (index < 0 || index >= players.size()) { + throw new IllegalArgumentException("유효하지 않은 인덱스입니다: " + index); + } + return players.get(index); + } - private void validatePlayerCount(List players) { - if (players.size() < 2) { - throw new IllegalArgumentException("플레이어는 최소 2명 이상이어야 합니다."); + private void validatePlayerCount(List players) { + if (players.size() < 2) { + throw new IllegalArgumentException("플레이어는 최소 2명 이상이어야 합니다."); + } } - } - private void validateDuplicate(List players) { - Set names = players.stream() - .map(Player::getName) - .collect(Collectors.toSet()); - if (names.size() != players.size()) { - throw new IllegalArgumentException("플레이어의 이름은 중복될 수 없습니다."); + private void validateDuplicate(List players) { + Set names = players.stream() + .map(Player::getName) + .collect(Collectors.toSet()); + if (names.size() != players.size()) { + throw new IllegalArgumentException("플레이어의 이름은 중복될 수 없습니다."); + } } - } - public void validateContainsPlayer(String input) { - if (!this.containsPlayer(input)) { - throw new IllegalArgumentException("해당 이름의 플레이어가 존재하지 않습니다: " + input); + public void validateContainsPlayer(String input) { + if (!this.containsPlayer(input)) { + throw new IllegalArgumentException("해당 이름의 플레이어가 존재하지 않습니다: " + input); + } } - } - public boolean containsPlayer(String name) { - return players.stream() - .anyMatch(player -> player.getName().getName().equals(name)); - } + public boolean containsPlayer(String name) { + return players.stream() + .anyMatch(player -> player.getName().getName().equals(name)); + } - public int size() { - return players.size(); - } + public int size() { + return players.size(); + } - public List getPlayers() { - return List.copyOf(players); - } + public List getPlayers() { + return List.copyOf(players); + } } diff --git a/src/main/java/model/player/Position.java b/src/main/java/model/player/Position.java index 22986488..20194967 100644 --- a/src/main/java/model/player/Position.java +++ b/src/main/java/model/player/Position.java @@ -4,43 +4,43 @@ public class Position { - public static final int MINIMUM_POSITION = 0; - private int value; + public static final int MINIMUM_POSITION = 0; + private int value; - public Position(int value) { - this.value = value; - } + public Position(int value) { + this.value = value; + } - public void moveToRight() { - value++; - } + public void moveToRight() { + value++; + } - public void moveToLeft() { - if (value <= MINIMUM_POSITION) { - throw new IllegalArgumentException("Position의 값은 음수가 될 수 없습니다."); + public void moveToLeft() { + if (value <= MINIMUM_POSITION) { + throw new IllegalArgumentException("Position의 값은 음수가 될 수 없습니다."); + } + value--; } - value--; - } - public int getValue() { - return value; - } + public int getValue() { + return value; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @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; } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public int hashCode() { + return Objects.hash(value); } - Position position = (Position) o; - return value == position.value; - } - - @Override - public int hashCode() { - return Objects.hash(value); - } } diff --git a/src/main/java/util/LadderGenerator.java b/src/main/java/util/LadderGenerator.java index 0b602088..741c336f 100644 --- a/src/main/java/util/LadderGenerator.java +++ b/src/main/java/util/LadderGenerator.java @@ -2,5 +2,5 @@ public interface LadderGenerator { - boolean generate(); + boolean generate(); } diff --git a/src/main/java/util/RandomLadderGenerator.java b/src/main/java/util/RandomLadderGenerator.java index 0154850d..fe61dd32 100644 --- a/src/main/java/util/RandomLadderGenerator.java +++ b/src/main/java/util/RandomLadderGenerator.java @@ -2,11 +2,11 @@ import java.util.Random; -public class RandomLadderGenerator implements LadderGenerator{ +public class RandomLadderGenerator implements LadderGenerator { - private final Random random = new Random(); + private final Random random = new Random(); - public boolean generate() { - return random.nextBoolean(); - } + public boolean generate() { + return random.nextBoolean(); + } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 685596c4..4c721cb1 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -8,46 +8,47 @@ public class InputView { - private static final Scanner scanner = new Scanner(System.in); - public static final String INPUT_EXCEPTION_MESSAGE = "올바른 입력 형식이 아닙니다. 다시 입력해주세요."; - private static final String LADDER_HEIGHT_MESSAGE = "최대 사다리 높이는 몇 개인가요?"; - private static final String EXECUTION_GOAL_MESSAGE = "실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"; - private static final String EXECUTION_NAME_MESSAGE = "참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"; - private static final String PLAYER_FOR_RESULT_MESSAGE = "결과를 보고 싶은 사람은?"; - private static final String INPUT_DELIMITER = ","; - - public int inputLadderHeight() { - System.out.println("\n" + LADDER_HEIGHT_MESSAGE); - String rawLadderHeight = scanner.nextLine(); - return parseInt(rawLadderHeight); - } - - private int parseInt(String rawLadderHeight) { - try { - return Integer.parseInt(rawLadderHeight); - } catch (NumberFormatException e) { - throw new IllegalArgumentException(INPUT_EXCEPTION_MESSAGE); + private static final Scanner scanner = new Scanner(System.in); + public static final String INPUT_EXCEPTION_MESSAGE = "올바른 입력 형식이 아닙니다. 숫자로 입력해주세요."; + private static final String LADDER_HEIGHT_MESSAGE = "최대 사다리 높이는 몇 개인가요?"; + private static final String EXECUTION_GOAL_MESSAGE = "실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"; + private static final String EXECUTION_NAME_MESSAGE = "참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"; + private static final String PLAYER_FOR_RESULT_MESSAGE = "결과를 보고 싶은 사람은?"; + private static final String INPUT_DELIMITER = ","; + private static final String NEW_LINE = "\n"; + + public int inputLadderHeight() { + System.out.println(NEW_LINE + LADDER_HEIGHT_MESSAGE); + String rawLadderHeight = scanner.nextLine(); + return parseInt(rawLadderHeight); + } + + private int parseInt(String rawLadderHeight) { + try { + return Integer.parseInt(rawLadderHeight); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(INPUT_EXCEPTION_MESSAGE); + } + } + + public List inputPlayers() { + System.out.println(NEW_LINE + EXECUTION_NAME_MESSAGE); + String rawPlayerName = scanner.nextLine(); + return Arrays.stream(rawPlayerName.split(INPUT_DELIMITER)) + .map(String::trim) + .collect(Collectors.toList()); + } + + public List inputGoals() { + System.out.println(NEW_LINE + EXECUTION_GOAL_MESSAGE); + String rawGoals = scanner.nextLine(); + return Arrays.stream(rawGoals.split(INPUT_DELIMITER)) + .map(String::trim) + .collect(Collectors.toList()); + } + + public String inputPlayerForResult() { + System.out.println(NEW_LINE + PLAYER_FOR_RESULT_MESSAGE); + return scanner.nextLine(); } - } - - public List inputPlayers() { - System.out.println("\n" +EXECUTION_NAME_MESSAGE); - String rawPlayerName = scanner.nextLine(); - return Arrays.stream(rawPlayerName.split(INPUT_DELIMITER)) - .map(String::trim) - .collect(Collectors.toList()); - } - - public List inputGoals(Players players) { - System.out.println("\n" + EXECUTION_GOAL_MESSAGE); - String rawGoals = scanner.nextLine(); - return Arrays.stream(rawGoals.split(INPUT_DELIMITER)) - .map(String::trim) - .collect(Collectors.toList()); - } - - public String inputPlayerForResult() { - System.out.println("\n" + PLAYER_FOR_RESULT_MESSAGE); - return scanner.nextLine(); - } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 79f55f43..ec61b360 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -11,79 +11,83 @@ public class OutputView { - private static final int NAME_WIDTH = 6; - private static final String EXECUTION_RESULT = "\n실행 결과"; - private static final String LADDER_RESULT_HEADER = "\n사다리 결과\n"; - private static final String CONNECTED_LINE = "-----|"; - private static final String DISCONNECTED_LINE = " |"; - private static final String EDGE_OF_POINT = "|"; - private static final String START_PADDING = " "; - private static final String SINGLE_SPACE = " "; + private static final int NAME_WIDTH = 6; + private static final String EXECUTION_RESULT = "\n실행 결과"; + private static final String LADDER_RESULT_HEADER = "\n사다리 결과\n"; + private static final String CONNECTED_LINE = "-----|"; + private static final String DISCONNECTED_LINE = " |"; + private static final String EDGE_OF_POINT = "|"; + private static final String START_PADDING = " "; + private static final String SINGLE_SPACE = " "; - public void printLadder(Ladder ladder, Players players, Goals goals) { - System.out.println(LADDER_RESULT_HEADER); - printPlayerNamers(players); - printLadderLines(ladder); - printGoals(goals); - } + public void printLadder(Ladder ladder, Players players, Goals goals) { + System.out.println(LADDER_RESULT_HEADER); + printPlayerNamers(players); + printLadderLines(ladder); + printGoals(goals); + } + + private void printPlayerNamers(Players players) { + for (Player player : players.getPlayers()) { + String name = player.getName().getName(); + int padding = NAME_WIDTH - 1 - name.length(); + System.out.print(SINGLE_SPACE.repeat(padding) + name + SINGLE_SPACE); + } + System.out.println(); + } - private void printPlayerNamers(Players players) { - for (Player player : players.getPlayers()) { - String name = player.getName().getName(); - int padding = NAME_WIDTH - 1 - name.length(); - System.out.print(SINGLE_SPACE.repeat(padding) + name + SINGLE_SPACE); + private void printLadderLines(Ladder ladder) { + for (var line : ladder.getLines()) { + printLine(line.getPoints()); + } } - System.out.println(); - } - private void printLadderLines(Ladder ladder) { - for (var line : ladder.getLines()) { - printLine(line.getPoints()); + private void printLine(List points) { + System.out.print(START_PADDING + EDGE_OF_POINT); + for (var point : points) { + printPoint(point); + } + System.out.println(); } - } - private void printLine(List points) { - System.out.print(START_PADDING + EDGE_OF_POINT); - for (var point : points) { - printPoint(point); + private void printPoint(Point point) { + if (point.isConnected()) { + System.out.print(CONNECTED_LINE); + return; + } + System.out.print(DISCONNECTED_LINE); } - System.out.println(); - } - private void printPoint(Point point) { - if (point.isConnected()) { - System.out.print(CONNECTED_LINE); - return; + private void printGoals(Goals goals) { + for (Goal goal : goals.getGoals()) { + String text = goal.getGoal(); + int padding = NAME_WIDTH - 1 - text.length(); + System.out.print(SINGLE_SPACE.repeat(padding) + text + SINGLE_SPACE); + } + System.out.println(); } - System.out.print(DISCONNECTED_LINE); - } - private void printGoals(Goals goals) { - for (Goal goal : goals.getGoals()) { - String text = goal.getGoal(); - int padding = NAME_WIDTH - 1 - text.length(); - System.out.print(SINGLE_SPACE.repeat(padding) + text + SINGLE_SPACE); + public void printAllResults(Map results) { + System.out.println(EXECUTION_RESULT); + for (var entry : results.entrySet()) { + System.out.println(entry.getKey().getName().getName() + " : " + entry.getValue().getGoal()); + } } - System.out.println(); - } - public void printAllResults(Map results) { - System.out.println(EXECUTION_RESULT); - for (var entry : results.entrySet()) { - System.out.println(entry.getKey().getName().getName() + " : " + entry.getValue().getGoal()); + public void printSingleResult(String name, Players players, Map results) { + System.out.println(EXECUTION_RESULT); + for (Player player : players.getPlayers()) { + printPlayerResult(name, player, results); + } } - } - public void printSingleResult(String name, Players players, Map results) { - System.out.println(EXECUTION_RESULT); - for (Player player : players.getPlayers()) { - printPlayerResult(name, player, results); + private void printPlayerResult(String name, Player player, Map results) { + if (player.getName().getName().equals(name)) { + System.out.println(results.get(player).getGoal()); + } } - } - private void printPlayerResult(String name, Player player, Map results) { - if (player.getName().getName().equals(name)) { - System.out.println(results.get(player).getGoal()); + public void printErrorMessage(String message) { + System.out.println(message); } - } } diff --git a/src/test/java/model/TestLadderGenerator.java b/src/test/java/model/TestLadderGenerator.java index 0752d038..720de780 100644 --- a/src/test/java/model/TestLadderGenerator.java +++ b/src/test/java/model/TestLadderGenerator.java @@ -5,20 +5,20 @@ public class TestLadderGenerator implements LadderGenerator { - private final List values; - private int index = 0; + private final List values; + private int index = 0; - public TestLadderGenerator(List values) { - this.values = values; - } + public TestLadderGenerator(List values) { + this.values = values; + } - @Override - public boolean generate() { - boolean value = values.get(index); - index++; - if (index >= values.size()) { - index = 0; + @Override + public boolean generate() { + boolean value = values.get(index); + index++; + if (index >= values.size()) { + index = 0; + } + return value; } - return value; - } } diff --git a/src/test/java/model/goal/GoalTest.java b/src/test/java/model/goal/GoalTest.java index cf15d54c..f3205736 100644 --- a/src/test/java/model/goal/GoalTest.java +++ b/src/test/java/model/goal/GoalTest.java @@ -10,18 +10,18 @@ class GoalTest { - @DisplayName("정상적으로 Goal 객체를 생성한다") - @Test - void createGoal() { - assertDoesNotThrow(() -> new Goal("꽝")); - } + @DisplayName("정상적으로 Goal 객체를 생성한다") + @Test + void createGoal() { + assertDoesNotThrow(() -> new Goal("꽝")); + } - @ParameterizedTest - @ValueSource(strings = {"결과가너무너무길때", " "}) - @DisplayName("플레이어 이름이 공백이거나 6글자 이상이면 예외가 발생한다") - void throwExceptionWhenExceedsFive(String goal) { - assertThatThrownBy(() -> new Goal(goal)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("실행 결과는 1~5글자여야 합니다."); - } + @ParameterizedTest + @ValueSource(strings = {"결과가너무너무길때", " "}) + @DisplayName("플레이어 이름이 공백이거나 6글자 이상이면 예외가 발생한다") + void throwExceptionWhenExceedsFive(String goal) { + assertThatThrownBy(() -> new Goal(goal)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("실행 결과는 1~5글자여야 합니다."); + } } diff --git a/src/test/java/model/goal/GoalsTest.java b/src/test/java/model/goal/GoalsTest.java index 42679ea4..cd79d728 100644 --- a/src/test/java/model/goal/GoalsTest.java +++ b/src/test/java/model/goal/GoalsTest.java @@ -8,16 +8,16 @@ class GoalsTest { - @Test - @DisplayName("플레이어의 수와 다른 갯수의 결과가 입력되면 예외를 반환한다") - void throwExceptionWhenNotMatches() { - // Given - List goals = List.of(new Goal("당첨"), new Goal("꽝")); - int playerCount = 3; + @Test + @DisplayName("플레이어의 수와 다른 갯수의 결과가 입력되면 예외를 반환한다") + void throwExceptionWhenNotMatches() { + // Given + List goals = List.of(new Goal("당첨"), new Goal("꽝")); + int playerCount = 3; - // When & Then - assertThatThrownBy(() -> new Goals(goals, playerCount)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("실행 결과 수와 참여자 수는 같아야 합니다."); - } + // When & Then + assertThatThrownBy(() -> new Goals(goals, playerCount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("실행 결과 수와 참여자 수는 같아야 합니다."); + } } diff --git a/src/test/java/model/ladder/LadderHeightTest.java b/src/test/java/model/ladder/LadderHeightTest.java index 92378c4e..bc502be0 100644 --- a/src/test/java/model/ladder/LadderHeightTest.java +++ b/src/test/java/model/ladder/LadderHeightTest.java @@ -8,30 +8,30 @@ class LadderHeightTest { - @Test - @DisplayName("정상적으로 LadderHeight 객체가 생성된다") - void createLadderHeight() { - // Given - int height = 5; - int player = 5; - - // When - LadderHeight ladderHeight = new LadderHeight(height, player); - - // Then - assertThat(ladderHeight.getLadderHeight()).isEqualTo(height); - } - - @Test - @DisplayName("사다리 높이가 (플레이어 - 1) 작거나 20보다 크면 예외가 발생한다") - void throwExceptionHeightWhenIsBetween() { - // Given - int invalidHeight = 10; - int playerCount = 15; - - // When & Then - assertThatThrownBy(() -> new LadderHeight(invalidHeight, playerCount)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("사다리의 높이는 (플레이어 수 - 1) 이상, 20 이하의 숫자만 가능합니다."); - } + @Test + @DisplayName("정상적으로 LadderHeight 객체가 생성된다") + void createLadderHeight() { + // Given + int height = 5; + int player = 5; + + // When + LadderHeight ladderHeight = new LadderHeight(height, player); + + // Then + assertThat(ladderHeight.getLadderHeight()).isEqualTo(height); + } + + @Test + @DisplayName("사다리 높이가 (플레이어 - 1) 작거나 20보다 크면 예외가 발생한다") + void throwExceptionHeightWhenIsBetween() { + // Given + int invalidHeight = 10; + int playerCount = 15; + + // When & Then + assertThatThrownBy(() -> new LadderHeight(invalidHeight, playerCount)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("사다리의 높이는 (플레이어 수 - 1) 이상, 20 이하의 숫자만 가능합니다."); + } } diff --git a/src/test/java/model/ladder/LadderTest.java b/src/test/java/model/ladder/LadderTest.java index de2f03b0..8b9ff354 100644 --- a/src/test/java/model/ladder/LadderTest.java +++ b/src/test/java/model/ladder/LadderTest.java @@ -15,71 +15,72 @@ import util.RandomLadderGenerator; class LadderTest { - @Test - @DisplayName("Ladder는 올바른 높이와 플레이어 수에 맞는 라인을 생성한다") - void createLadder() { - // Given - int playerCount = 4; - LadderHeight height = new LadderHeight(5,playerCount); - List playersList = List.of( - new Player(new PlayerName("a"), new Position(0)), - new Player(new PlayerName("b"), new Position(1)), - new Player(new PlayerName("c"), new Position(2)), - new Player(new PlayerName("d"), new Position(3)) - ); - Players players = new Players(playersList); + @Test + @DisplayName("Ladder는 올바른 높이와 플레이어 수에 맞는 라인을 생성한다") + void createLadder() { + // Given + int playerCount = 4; + LadderHeight height = new LadderHeight(5, playerCount); - // When - Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); + List playersList = List.of( + new Player(new PlayerName("a"), new Position(0)), + new Player(new PlayerName("b"), new Position(1)), + new Player(new PlayerName("c"), new Position(2)), + new Player(new PlayerName("d"), new Position(3)) + ); + Players players = new Players(playersList); - // Then - assertThat(ladder.getLadderHeight()).isEqualTo(5); - assertThat(ladder.getLadderWidth(players)).isEqualTo(4); - assertThat(ladder.getLines().size()).isEqualTo(5); - } + // When + Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); - @Test - @DisplayName("플레이어가 다르다면 서로 다른 결과 위치를 반환해주어야 한다") - void getDifferentStartEndPosition(){ - // Given - LadderHeight height = new LadderHeight(2, 3); - List playersList = List.of( - new Player(new PlayerName("a"), new Position(0)), - new Player(new PlayerName("b"), new Position(1)), - new Player(new PlayerName("c"), new Position(2)) - ); - Players players = new Players(playersList); - Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); + // Then + assertThat(ladder.getLadderHeight()).isEqualTo(5); + assertThat(ladder.getLadderWidth(players)).isEqualTo(4); + assertThat(ladder.getLines().size()).isEqualTo(5); + } - // When - Position first = ladder.getGoalsPosition(new Position(0)); - Position second = ladder.getGoalsPosition(new Position(1)); + @Test + @DisplayName("플레이어가 다르다면 서로 다른 결과 위치를 반환해주어야 한다") + void getDifferentStartEndPosition() { + // Given + LadderHeight height = new LadderHeight(2, 3); + List playersList = List.of( + new Player(new PlayerName("a"), new Position(0)), + new Player(new PlayerName("b"), new Position(1)), + new Player(new PlayerName("c"), new Position(2)) + ); + Players players = new Players(playersList); + Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); - // Then - assertThat(first).isNotEqualTo(second); - } + // When + Position first = ladder.getGoalsPosition(new Position(0)); + Position second = ladder.getGoalsPosition(new Position(1)); - @ParameterizedTest - @CsvSource(value = {"0:3", "1:1", "2:2", "3:0"}, delimiter = ':') - @DisplayName("사다리의 결과에 맞는 시작 위치, 도착 위치를 반환해주어야 한다") - void getAppropriatePosition(int start, int end) { - // Given - List orderList = List.of(true, true, false, true, true, true); - LadderHeight height = new LadderHeight(3,4); - List playersList = List.of( - new Player(new PlayerName("a"), new Position(0)), - new Player(new PlayerName("b"), new Position(1)), - new Player(new PlayerName("c"), new Position(2)), - new Player(new PlayerName("d"), new Position(3)) - ); - Players players = new Players(playersList); - Ladder ladder = Ladder.of(players, height, new TestLadderGenerator(orderList)); + // Then + assertThat(first).isNotEqualTo(second); + } - // When - Position results = ladder.getGoalsPosition(new Position(start)); + @ParameterizedTest + @CsvSource(value = {"0:3", "1:1", "2:2", "3:0"}, delimiter = ':') + @DisplayName("사다리의 결과에 맞는 시작 위치, 도착 위치를 반환해주어야 한다") + void getAppropriatePosition(int start, int end) { + // Given + List orderList = List.of(true, true, false, true, true, true); + LadderHeight height = new LadderHeight(3, 4); + List playersList = List.of( + new Player(new PlayerName("a"), new Position(0)), + new Player(new PlayerName("b"), new Position(1)), + new Player(new PlayerName("c"), new Position(2)), + new Player(new PlayerName("d"), new Position(3)) + ); + Players players = new Players(playersList); + Ladder ladder = Ladder.of(players, height, new TestLadderGenerator(orderList)); - // Then - assertThat(results.getValue()).isEqualTo(end); - } + // When + Position results = ladder.getGoalsPosition(new Position(start)); + + // Then + assertThat(results.getValue()).isEqualTo(end); + } } diff --git a/src/test/java/model/ladder/LineTest.java b/src/test/java/model/ladder/LineTest.java index 9884c692..b7061a5e 100644 --- a/src/test/java/model/ladder/LineTest.java +++ b/src/test/java/model/ladder/LineTest.java @@ -12,34 +12,34 @@ class LineTest { - @Test - @DisplayName("인자값으로 받은 playerCount -1 개 만큼의 Point를 가진다") - void createLine() { - // Given - int playerCount = 3; - - // When - Line line = Line.create(3, new RandomLadderGenerator()); - List points = line.getPoints(); - - // Then - assertThat(points.size()).isEqualTo(playerCount - 1); - } - - @Test - @DisplayName("Point 들은 연속된 다리를 가질 수 없다") - void pointCanNotHaveDuplicate() { - int playerCount = 4; - List orderList = List.of( - true, - true, - true - ); - - Line line = Line.create(playerCount, new TestLadderGenerator(orderList)); - List points = line.getPoints(); - - assertThat(points).containsExactly(CONNECTED, DISCONNECTED, CONNECTED); - } + @Test + @DisplayName("인자값으로 받은 playerCount -1 개 만큼의 Point를 가진다") + void createLine() { + // Given + int playerCount = 3; + + // When + Line line = Line.create(3, new RandomLadderGenerator()); + List points = line.getPoints(); + + // Then + assertThat(points.size()).isEqualTo(playerCount - 1); + } + + @Test + @DisplayName("Point 들은 연속된 다리를 가질 수 없다") + void pointCanNotHaveDuplicate() { + int playerCount = 4; + List orderList = List.of( + true, + true, + true + ); + + Line line = Line.create(playerCount, new TestLadderGenerator(orderList)); + List points = line.getPoints(); + + assertThat(points).containsExactly(CONNECTED, DISCONNECTED, CONNECTED); + } } diff --git a/src/test/java/model/ladder/PositionTest.java b/src/test/java/model/ladder/PositionTest.java index 7dad4993..6d9e0c06 100644 --- a/src/test/java/model/ladder/PositionTest.java +++ b/src/test/java/model/ladder/PositionTest.java @@ -9,36 +9,36 @@ class PositionTest { - @Test - @DisplayName("정상적으로 객체를 가진다") - void createPosition() { - // Given - Position position = new Position(5); - - // When & Then - assertThat(position.getValue()).isEqualTo(5); - } - - @Test - @DisplayName("position은 값이 0 이하로 내려갈 수 없다") - void throwExceptionWhenPositionIsNegative() { - // Given - Position position = new Position(-0); - - // When & Then - assertThatThrownBy(() -> position.moveToLeft()) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Position의 값은 음수가 될 수 없습니다."); - } - - @Test - @DisplayName("같은 값을 가진 Position 객체는 equals가 true를 반환한다") - void equalsShouldBeTrue() { - // Given - Position position1 = new Position(5); - Position position2 = new Position(5); - - // When & Then - assertThat(position1.equals(position2)).isTrue(); - } + @Test + @DisplayName("정상적으로 객체를 가진다") + void createPosition() { + // Given + Position position = new Position(5); + + // When & Then + assertThat(position.getValue()).isEqualTo(5); + } + + @Test + @DisplayName("position은 값이 0 이하로 내려갈 수 없다") + void throwExceptionWhenPositionIsNegative() { + // Given + Position position = new Position(-0); + + // When & Then + assertThatThrownBy(() -> position.moveToLeft()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Position의 값은 음수가 될 수 없습니다."); + } + + @Test + @DisplayName("같은 값을 가진 Position 객체는 equals가 true를 반환한다") + void equalsShouldBeTrue() { + // Given + Position position1 = new Position(5); + Position position2 = new Position(5); + + // When & Then + assertThat(position1.equals(position2)).isTrue(); + } } diff --git a/src/test/java/model/player/PlayerNameTest.java b/src/test/java/model/player/PlayerNameTest.java index 2852033e..a58003ba 100644 --- a/src/test/java/model/player/PlayerNameTest.java +++ b/src/test/java/model/player/PlayerNameTest.java @@ -9,28 +9,28 @@ class PlayerNameTest { - @ParameterizedTest - @ValueSource(strings = {"a", "abc", "abcde"}) - @DisplayName("플레이어 이름이 1글자에서 5글자 사이면 정상적으로 생성된다") - void createWhenPlayerNameIsBetween(String name) { - assertThatNoException().isThrownBy(() -> new PlayerName(name)); - } + @ParameterizedTest + @ValueSource(strings = {"a", "abc", "abcde"}) + @DisplayName("플레이어 이름이 1글자에서 5글자 사이면 정상적으로 생성된다") + void createWhenPlayerNameIsBetween(String name) { + assertThatNoException().isThrownBy(() -> new PlayerName(name)); + } - @ParameterizedTest - @ValueSource(strings = {"abcdef", "hahahaha", " "}) - @DisplayName("플레이어 이름이 공백이거나 6글자 이상이면 예외가 발생한다") - void throwExceptionWhenExceedsFive(String name) { - assertThatThrownBy(() -> new PlayerName(name)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("플레이어의 이름은 1~5글자여야 합니다."); - } + @ParameterizedTest + @ValueSource(strings = {"abcdef", "hahahaha", " "}) + @DisplayName("플레이어 이름이 공백이거나 6글자 이상이면 예외가 발생한다") + void throwExceptionWhenExceedsFive(String name) { + assertThatThrownBy(() -> new PlayerName(name)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("플레이어의 이름은 1~5글자여야 합니다."); + } - @ParameterizedTest - @ValueSource(strings = {"all", "ALL", "aLl"}) - @DisplayName("플레이어 이름이 'all'이면 예외가 발생한다") - void throwExceptionWhenNameIsAll(String name) { - assertThatThrownBy(() -> new PlayerName(name)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("플레이어 이름으로 'all'은 사용할 수 없습니다."); - } + @ParameterizedTest + @ValueSource(strings = {"all", "ALL", "aLl"}) + @DisplayName("플레이어 이름이 'all'이면 예외가 발생한다") + void throwExceptionWhenNameIsAll(String name) { + assertThatThrownBy(() -> new PlayerName(name)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("플레이어 이름으로 'all'은 사용할 수 없습니다."); + } } diff --git a/src/test/java/model/player/PlayerTest.java b/src/test/java/model/player/PlayerTest.java index 75b8826c..3ed96dce 100644 --- a/src/test/java/model/player/PlayerTest.java +++ b/src/test/java/model/player/PlayerTest.java @@ -7,32 +7,32 @@ class PlayerTest { - @Test - @DisplayName("정상적으로 Player 객체를 생성한다") - void playerShouldHaveNameAndPosition() { - // Given - PlayerName playerName = new PlayerName("abc"); - Position position = new Position(5); - Player player = new Player(playerName, position); - - // When & Then - assertThat(player.getName()).isEqualTo(playerName); - assertThat(player.getPosition()).isEqualTo(position); - } - - @Test - @DisplayName("같은 이름이나 포지션을 가진 Player 객체는 true를 반환한다") - void playerShouldHaveNameAndPositionTrue() { - // Given - PlayerName playerName1 = new PlayerName("abc"); - Position position1 = new Position(5); - Player player1 = new Player(playerName1, position1); - - PlayerName playerName2 = new PlayerName("abc"); - Position position2 = new Position(5); - Player player2 = new Player(playerName2, position2); - - // When & Then - assertThat(player1).isEqualTo(player2); - } + @Test + @DisplayName("정상적으로 Player 객체를 생성한다") + void playerShouldHaveNameAndPosition() { + // Given + PlayerName playerName = new PlayerName("abc"); + Position position = new Position(5); + Player player = new Player(playerName, position); + + // When & Then + assertThat(player.getName()).isEqualTo(playerName); + assertThat(player.getPosition()).isEqualTo(position); + } + + @Test + @DisplayName("같은 이름이나 포지션을 가진 Player 객체는 true를 반환한다") + void playerShouldHaveNameAndPositionTrue() { + // Given + PlayerName playerName1 = new PlayerName("abc"); + Position position1 = new Position(5); + Player player1 = new Player(playerName1, position1); + + PlayerName playerName2 = new PlayerName("abc"); + Position position2 = new Position(5); + Player player2 = new Player(playerName2, position2); + + // When & Then + assertThat(player1).isEqualTo(player2); + } } diff --git a/src/test/java/model/player/PlayersTest.java b/src/test/java/model/player/PlayersTest.java index 66bdd1b3..06f03a1d 100644 --- a/src/test/java/model/player/PlayersTest.java +++ b/src/test/java/model/player/PlayersTest.java @@ -8,43 +8,43 @@ class PlayersTest { - @Test - @DisplayName("플레이어가 2명 미만일 경우 예외가 발생한다") - void throwExceptionWhenLessThanTwo() { - // Given - List players = List.of(new Player(new PlayerName("abc"), new Position(2))); - - // When & Then - assertThatThrownBy(() -> new Players(players)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어는 최소 2명 이상이어야 합니다."); - } - - @Test - @DisplayName("플레이어 이름이 중복되면 예외가 발생한다") - void throwExceptionWhenDuplicate() { - // Given - Player player1 = new Player(new PlayerName("abc"), new Position(1)); - Player player2 = new Player(new PlayerName("abc"), new Position(2)); - List players = List.of(player1, player2); - - // When & Then - assertThatThrownBy(() -> new Players(players)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("플레이어의 이름은 중복될 수 없습니다."); - } - - @Test - @DisplayName("존재하지 않는 플레이어 이름 입력 시 예외가 발생한다") - void throwExceptionWhenInvalidName() { - // Given - Player player1 = new Player(new PlayerName("a"), new Position(0)); - Player player2 = new Player(new PlayerName("b"), new Position(1)); - Players players = new Players(List.of(player1, player2)); - - // When & Then - assertThatThrownBy(() -> players.validateContainsPlayer("invalid")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("해당 이름의 플레이어가 존재하지 않습니다: invalid"); - } + @Test + @DisplayName("플레이어가 2명 미만일 경우 예외가 발생한다") + void throwExceptionWhenLessThanTwo() { + // Given + List players = List.of(new Player(new PlayerName("abc"), new Position(2))); + + // When & Then + assertThatThrownBy(() -> new Players(players)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어는 최소 2명 이상이어야 합니다."); + } + + @Test + @DisplayName("플레이어 이름이 중복되면 예외가 발생한다") + void throwExceptionWhenDuplicate() { + // Given + Player player1 = new Player(new PlayerName("abc"), new Position(1)); + Player player2 = new Player(new PlayerName("abc"), new Position(2)); + List players = List.of(player1, player2); + + // When & Then + assertThatThrownBy(() -> new Players(players)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("플레이어의 이름은 중복될 수 없습니다."); + } + + @Test + @DisplayName("존재하지 않는 플레이어 이름 입력 시 예외가 발생한다") + void throwExceptionWhenInvalidName() { + // Given + Player player1 = new Player(new PlayerName("a"), new Position(0)); + Player player2 = new Player(new PlayerName("b"), new Position(1)); + Players players = new Players(List.of(player1, player2)); + + // When & Then + assertThatThrownBy(() -> players.validateContainsPlayer("invalid")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("해당 이름의 플레이어가 존재하지 않습니다: invalid"); + } } From e68fb1146e616d4e46a195328888dcbfbbc05bd4 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Wed, 7 May 2025 02:36:52 +0900 Subject: [PATCH 22/24] =?UTF-8?q?refactor:=20=ED=95=A8=EC=88=98=ED=98=95?= =?UTF-8?q?=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/LadderGame.java | 2 - src/main/java/model/ladder/Direction.java | 51 +++++++++++++++++ src/main/java/model/ladder/Ladder.java | 13 +++-- src/main/java/model/ladder/Line.java | 37 ++++--------- src/main/java/model/player/Position.java | 10 ++-- src/test/java/model/ladder/DirectionTest.java | 55 +++++++++++++++++++ 6 files changed, 129 insertions(+), 39 deletions(-) create mode 100644 src/main/java/model/ladder/Direction.java create mode 100644 src/test/java/model/ladder/DirectionTest.java diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java index 4f3884b1..31a215e2 100644 --- a/src/main/java/model/LadderGame.java +++ b/src/main/java/model/LadderGame.java @@ -1,7 +1,5 @@ package model; -import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; diff --git a/src/main/java/model/ladder/Direction.java b/src/main/java/model/ladder/Direction.java new file mode 100644 index 00000000..5ddce6c0 --- /dev/null +++ b/src/main/java/model/ladder/Direction.java @@ -0,0 +1,51 @@ +package model.ladder; + +import java.util.List; +import model.player.Position; + +public enum Direction { + + // 현재 위치의 오른쪽에 사다리 연결이 있을 경우 오른쪽 이동 + RIGHT( + (position, points) -> position.getValue() < points.size() + && points.get(position.getValue()).isConnected(), + Position::moveToRight + ), + // 현재 위치의 왼쪽에 사다리 연결이 있을 경우 왼쪽 이동 + LEFT( + (position, points) -> position.getValue() > 0 + && points.get(position.getValue() - 1).isConnected(), + Position::moveToLeft + ), + // 그 외의 경우, 현재 위치에 그대로 머무름 + STAY( + (position, points) -> true, + position -> position + ); + + private final MoveStrategy strategy; + private final PositionChanger changer; + + Direction(MoveStrategy strategy, PositionChanger changer) { + this.strategy = strategy; + this.changer = changer; + } + + public boolean isMovable(Position position, List points) { + return strategy.isMovable(position, points); + } + + public Position move(Position position) { + return changer.move(position); + } + + @FunctionalInterface + interface MoveStrategy { // 지금 이 방향으로 움직일 수 있는가? + boolean isMovable(Position position, List points); + } + + @FunctionalInterface + interface PositionChanger { // 이동했을 때 Position 어디인가? + Position move(Position position); + } +} diff --git a/src/main/java/model/ladder/Ladder.java b/src/main/java/model/ladder/Ladder.java index a4157ac8..b68f63e1 100644 --- a/src/main/java/model/ladder/Ladder.java +++ b/src/main/java/model/ladder/Ladder.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.IntStream; import model.player.Players; import model.player.Position; import util.LadderGenerator; @@ -54,9 +55,8 @@ private Boolean[] getLadderConnectionStatus(int playersCount) { // 특정 Line의 연결 상태 확인 private void getLineConnectionStatus(Boolean[] isConnectedAt, Line line) { - for (int i = 0; i < line.getLadderWidth(); i++) { - getPointConnectionStatus(isConnectedAt, line, i); - } + IntStream.range(0, line.getLadderWidth()) + .forEach(i -> getPointConnectionStatus(isConnectedAt, line, i)); } // 특정 Line의 특정 Point 연결 상태 확인 @@ -74,11 +74,12 @@ public int getLadderWidth(Players players) { return players.size(); } - public Position getGoalsPosition(Position position) { + public Position getGoalsPosition(Position start) { + Position current = start; for (Line line : lines) { - line.tryMoveAt(position); + current = line.move(current); } - return position; + return current; } public List getLines() { diff --git a/src/main/java/model/ladder/Line.java b/src/main/java/model/ladder/Line.java index e99168d7..c25c972f 100644 --- a/src/main/java/model/ladder/Line.java +++ b/src/main/java/model/ladder/Line.java @@ -2,6 +2,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; import model.player.Position; import util.LadderGenerator; @@ -13,11 +15,10 @@ public Line(List points) { this.points = List.copyOf(points); } - public static Line create(int PlayerCount, LadderGenerator ladderGenerator) { + public static Line create(int playerCount, LadderGenerator ladderGenerator) { List points = new ArrayList<>(); - for (int i = 0; i < PlayerCount - 1; i++) { - makeLine(points, ladderGenerator); - } + IntStream.range(0, playerCount - 1) + .forEach(i -> makeLine(points, ladderGenerator)); return new Line(points); } @@ -33,28 +34,12 @@ private static void makeLine(List points, LadderGenerator ladderGenerator points.add(Point.from(ladderGenerator.generate())); // 다시 랜덤 생성 } - public void tryMoveAt(Position position) { - if (isRightPassable(position)) { - position.moveToRight(); - return; - } - if (isLeftPassable(position)) { - position.moveToLeft(); - } - } - - private boolean isRightPassable(Position position) { - if (position.getValue() == points.size()) { // 오른쪽 끝, 이동 불가 - return false; - } - return points.get(position.getValue()).isConnected(); - } - - private boolean isLeftPassable(Position position) { - if (position.getValue() == Position.MINIMUM_POSITION) { // 왼쪽 끝, 이동 불가 - return false; - } - return points.get(position.getValue() - 1).isConnected(); + public Position move(Position position) { + return Stream.of(Direction.RIGHT, Direction.LEFT, Direction.STAY) + .filter(direction -> direction.isMovable(position, points)) + .findFirst() + .map(direction -> direction.move(position)) + .orElse(position); } public List getPoints() { diff --git a/src/main/java/model/player/Position.java b/src/main/java/model/player/Position.java index 20194967..3dee285f 100644 --- a/src/main/java/model/player/Position.java +++ b/src/main/java/model/player/Position.java @@ -5,21 +5,21 @@ public class Position { public static final int MINIMUM_POSITION = 0; - private int value; + private final int value; public Position(int value) { this.value = value; } - public void moveToRight() { - value++; + public Position moveToRight() { + return new Position(value + 1); } - public void moveToLeft() { + public Position moveToLeft() { if (value <= MINIMUM_POSITION) { throw new IllegalArgumentException("Position의 값은 음수가 될 수 없습니다."); } - value--; + return new Position(value - 1); } public int getValue() { diff --git a/src/test/java/model/ladder/DirectionTest.java b/src/test/java/model/ladder/DirectionTest.java new file mode 100644 index 00000000..448e2802 --- /dev/null +++ b/src/test/java/model/ladder/DirectionTest.java @@ -0,0 +1,55 @@ +package model.ladder; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.List; +import model.player.Position; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class DirectionTest { + + @Test + @DisplayName("오른쪽 이동이 가능한 경우") + void rightDirectionTest() { + // Given + Position position = new Position(0); + List points = List.of(Point.CONNECTED); + + // When + boolean result = Direction.RIGHT.isMovable(position, points); + + // Then + assertTrue(result); + } + + @Test + @DisplayName("왼쪽 이동이 가능한 경우") + void leftDirectionTest() { + // Given + Position position = new Position(1); + List points = List.of(Point.CONNECTED); + + // When + boolean result = Direction.LEFT.isMovable(position, points); + + // Then + assertTrue(result); + } + + @Test + @DisplayName("왼쪽 이동이 가능한 경우") + void stayDirectionTest() { + // Given + Position position = new Position(1); + List points = List.of(Point.DISCONNECTED); + + // When + boolean movable = Direction.STAY.isMovable(position, points); + Position moved = Direction.STAY.move(position); + + // Then + assertTrue(movable); + assertEquals(1, moved.getValue()); + } +} From 51598a8d68ce2c44eb2a52c26e2dc20064c2250c Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Thu, 8 May 2025 09:38:39 +0900 Subject: [PATCH 23/24] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/LadderGame.java | 2 +- src/main/java/model/player/Player.java | 17 ----------------- src/main/java/model/player/Position.java | 18 ------------------ src/test/java/model/ladder/PositionTest.java | 11 ----------- src/test/java/model/player/PlayerTest.java | 16 ---------------- 5 files changed, 1 insertion(+), 63 deletions(-) diff --git a/src/main/java/model/LadderGame.java b/src/main/java/model/LadderGame.java index 31a215e2..dbadd5be 100644 --- a/src/main/java/model/LadderGame.java +++ b/src/main/java/model/LadderGame.java @@ -22,7 +22,7 @@ public Map play(Players players, Goals goals) { return IntStream.range(0, players.size()) .boxed() .collect(Collectors.toMap( - index -> players.getPlayerAt(index), + players::getPlayerAt, index -> goals.getGoalAt(ladder.getGoalsPosition(new Position(index)).getValue()) )); } diff --git a/src/main/java/model/player/Player.java b/src/main/java/model/player/Player.java index f93c1342..a897a19d 100644 --- a/src/main/java/model/player/Player.java +++ b/src/main/java/model/player/Player.java @@ -19,21 +19,4 @@ public PlayerName getName() { public Position getPosition() { return position; } - - @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) && Objects.equals(position, player.position); - } - - @Override - public int hashCode() { - return Objects.hash(name, position); - } } diff --git a/src/main/java/model/player/Position.java b/src/main/java/model/player/Position.java index 3dee285f..7ba1e309 100644 --- a/src/main/java/model/player/Position.java +++ b/src/main/java/model/player/Position.java @@ -25,22 +25,4 @@ public Position moveToLeft() { public int getValue() { return value; } - - @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 Objects.hash(value); - } - } diff --git a/src/test/java/model/ladder/PositionTest.java b/src/test/java/model/ladder/PositionTest.java index 6d9e0c06..01e88a65 100644 --- a/src/test/java/model/ladder/PositionTest.java +++ b/src/test/java/model/ladder/PositionTest.java @@ -30,15 +30,4 @@ void throwExceptionWhenPositionIsNegative() { .isInstanceOf(IllegalArgumentException.class) .hasMessage("Position의 값은 음수가 될 수 없습니다."); } - - @Test - @DisplayName("같은 값을 가진 Position 객체는 equals가 true를 반환한다") - void equalsShouldBeTrue() { - // Given - Position position1 = new Position(5); - Position position2 = new Position(5); - - // When & Then - assertThat(position1.equals(position2)).isTrue(); - } } diff --git a/src/test/java/model/player/PlayerTest.java b/src/test/java/model/player/PlayerTest.java index 3ed96dce..7a260c0a 100644 --- a/src/test/java/model/player/PlayerTest.java +++ b/src/test/java/model/player/PlayerTest.java @@ -19,20 +19,4 @@ void playerShouldHaveNameAndPosition() { assertThat(player.getName()).isEqualTo(playerName); assertThat(player.getPosition()).isEqualTo(position); } - - @Test - @DisplayName("같은 이름이나 포지션을 가진 Player 객체는 true를 반환한다") - void playerShouldHaveNameAndPositionTrue() { - // Given - PlayerName playerName1 = new PlayerName("abc"); - Position position1 = new Position(5); - Player player1 = new Player(playerName1, position1); - - PlayerName playerName2 = new PlayerName("abc"); - Position position2 = new Position(5); - Player player2 = new Player(playerName2, position2); - - // When & Then - assertThat(player1).isEqualTo(player2); - } } From 959b6f556b74542f6924745f0042de9a0d6dbba4 Mon Sep 17 00:00:00 2001 From: hwangsea <134906042+hwangsea@users.noreply.github.com> Date: Fri, 9 May 2025 10:30:10 +0900 Subject: [PATCH 24/24] =?UTF-8?q?refactor:=20Player=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/model/player/Player.java | 8 +++----- src/main/java/model/player/Players.java | 6 +----- src/main/java/model/player/Position.java | 2 -- src/test/java/model/ladder/LadderTest.java | 22 ++++++++++----------- src/test/java/model/player/PlayerTest.java | 8 +++----- src/test/java/model/player/PlayersTest.java | 10 +++++----- 6 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/main/java/model/player/Player.java b/src/main/java/model/player/Player.java index a897a19d..2b44c943 100644 --- a/src/main/java/model/player/Player.java +++ b/src/main/java/model/player/Player.java @@ -1,15 +1,13 @@ package model.player; -import java.util.Objects; - public class Player { private final PlayerName name; private final Position position; - public Player(PlayerName name, Position position) { - this.name = name; - this.position = position; + public Player(String name, int position) { + this.name = new PlayerName(name); + this.position = new Position(position); } public PlayerName getName() { diff --git a/src/main/java/model/player/Players.java b/src/main/java/model/player/Players.java index b5fec8b0..7a8b6472 100644 --- a/src/main/java/model/player/Players.java +++ b/src/main/java/model/player/Players.java @@ -1,6 +1,5 @@ package model.player; -import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -19,10 +18,7 @@ public Players(List players) { public static Players from(List names) { List players = IntStream.range(0, names.size()) - .mapToObj(i -> new Player( - new PlayerName(names.get(i)), - new Position(i) - )) + .mapToObj(i -> new Player(names.get(i), i)) .toList(); return new Players(players); } diff --git a/src/main/java/model/player/Position.java b/src/main/java/model/player/Position.java index 7ba1e309..a30b2f46 100644 --- a/src/main/java/model/player/Position.java +++ b/src/main/java/model/player/Position.java @@ -1,7 +1,5 @@ package model.player; -import java.util.Objects; - public class Position { public static final int MINIMUM_POSITION = 0; diff --git a/src/test/java/model/ladder/LadderTest.java b/src/test/java/model/ladder/LadderTest.java index 8b9ff354..8382740e 100644 --- a/src/test/java/model/ladder/LadderTest.java +++ b/src/test/java/model/ladder/LadderTest.java @@ -24,10 +24,10 @@ void createLadder() { LadderHeight height = new LadderHeight(5, playerCount); List playersList = List.of( - new Player(new PlayerName("a"), new Position(0)), - new Player(new PlayerName("b"), new Position(1)), - new Player(new PlayerName("c"), new Position(2)), - new Player(new PlayerName("d"), new Position(3)) + new Player("a", 0), + new Player("b", 1), + new Player("c", 2), + new Player("d", 3) ); Players players = new Players(playersList); @@ -46,9 +46,9 @@ void getDifferentStartEndPosition() { // Given LadderHeight height = new LadderHeight(2, 3); List playersList = List.of( - new Player(new PlayerName("a"), new Position(0)), - new Player(new PlayerName("b"), new Position(1)), - new Player(new PlayerName("c"), new Position(2)) + new Player("a", 0), + new Player("b", 1), + new Player("c", 2) ); Players players = new Players(playersList); Ladder ladder = Ladder.of(players, height, new RandomLadderGenerator()); @@ -69,10 +69,10 @@ void getAppropriatePosition(int start, int end) { List orderList = List.of(true, true, false, true, true, true); LadderHeight height = new LadderHeight(3, 4); List playersList = List.of( - new Player(new PlayerName("a"), new Position(0)), - new Player(new PlayerName("b"), new Position(1)), - new Player(new PlayerName("c"), new Position(2)), - new Player(new PlayerName("d"), new Position(3)) + new Player("a", 0), + new Player("b", 1), + new Player("c", 2), + new Player("d", 3) ); Players players = new Players(playersList); Ladder ladder = Ladder.of(players, height, new TestLadderGenerator(orderList)); diff --git a/src/test/java/model/player/PlayerTest.java b/src/test/java/model/player/PlayerTest.java index 7a260c0a..76966bb8 100644 --- a/src/test/java/model/player/PlayerTest.java +++ b/src/test/java/model/player/PlayerTest.java @@ -11,12 +11,10 @@ class PlayerTest { @DisplayName("정상적으로 Player 객체를 생성한다") void playerShouldHaveNameAndPosition() { // Given - PlayerName playerName = new PlayerName("abc"); - Position position = new Position(5); - Player player = new Player(playerName, position); + Player player = new Player("abc", 5); // When & Then - assertThat(player.getName()).isEqualTo(playerName); - assertThat(player.getPosition()).isEqualTo(position); + assertThat(player.getName()).isEqualTo(new PlayerName("abc")); + assertThat(player.getPosition()).isEqualTo(new Position(5)); } } diff --git a/src/test/java/model/player/PlayersTest.java b/src/test/java/model/player/PlayersTest.java index 06f03a1d..b06268d4 100644 --- a/src/test/java/model/player/PlayersTest.java +++ b/src/test/java/model/player/PlayersTest.java @@ -12,7 +12,7 @@ class PlayersTest { @DisplayName("플레이어가 2명 미만일 경우 예외가 발생한다") void throwExceptionWhenLessThanTwo() { // Given - List players = List.of(new Player(new PlayerName("abc"), new Position(2))); + List players = List.of(new Player("abc", 2)); // When & Then assertThatThrownBy(() -> new Players(players)) @@ -24,8 +24,8 @@ void throwExceptionWhenLessThanTwo() { @DisplayName("플레이어 이름이 중복되면 예외가 발생한다") void throwExceptionWhenDuplicate() { // Given - Player player1 = new Player(new PlayerName("abc"), new Position(1)); - Player player2 = new Player(new PlayerName("abc"), new Position(2)); + Player player1 = new Player("abc",1); + Player player2 = new Player("abc",2); List players = List.of(player1, player2); // When & Then @@ -38,8 +38,8 @@ void throwExceptionWhenDuplicate() { @DisplayName("존재하지 않는 플레이어 이름 입력 시 예외가 발생한다") void throwExceptionWhenInvalidName() { // Given - Player player1 = new Player(new PlayerName("a"), new Position(0)); - Player player2 = new Player(new PlayerName("b"), new Position(1)); + Player player1 = new Player("a",0); + Player player2 = new Player("b",1); Players players = new Players(List.of(player1, player2)); // When & Then