From 8c68e8f358d066f907b33b61e5ba3297e1730b81 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:54:38 +0900 Subject: [PATCH 01/42] =?UTF-8?q?feat:=20=EC=B4=88=EA=B8=B0=20Application?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/Application.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 00000000..a6525ec1 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,12 @@ +import controller.LadderController; +import view.InputView; +import view.OutputView; + +public class Application { + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + LadderController controller = new LadderController(inputView, outputView); + controller.run(); + } +} \ No newline at end of file From c64a687402e04abadac5c48a1ec84587e32de83a Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:55:15 +0900 Subject: [PATCH 02/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EB=86=92=EC=9D=B4=20=EB=84=92=EC=9D=B4=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EB=B0=9B=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/main/java/view/InputView.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/view/InputView.java diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..30135884 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,19 @@ +package view; + +import java.util.Scanner; + +public class InputView { + private static final String REQUEST_WIDTH_MESSAGE = "사다리의 넓이는 몇 개인가요?"; + private static final String REQUEST_HEIGHT_MESSAGE = "사다리의 높이는 몇 개인가요?"; + private static final Scanner SCANNER = new Scanner(System.in); + + public int readWidth() { + System.out.println(REQUEST_WIDTH_MESSAGE); + return Integer.parseInt(SCANNER.nextLine()); + } + + public int readHeight() { + System.out.println(REQUEST_HEIGHT_MESSAGE); + return Integer.parseInt(SCANNER.nextLine()); + } +} \ No newline at end of file From 8bec14e73840a5c34177202092a4d033cc8ce622 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:56:05 +0900 Subject: [PATCH 03/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=EC=9D=98=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20?= =?UTF-8?q?=EB=8B=B4=EC=9D=80=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Ladder.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/domain/Ladder.java diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java new file mode 100644 index 00000000..a590e6ab --- /dev/null +++ b/src/main/java/domain/Ladder.java @@ -0,0 +1,25 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Ladder { + private final List lines; + + public Ladder(List lines) { + this.lines = lines; + } + + public static Ladder generate(LadderWidth width, LadderHeight height, BooleanGenerator generator) { + List lines = new ArrayList<>(); + for (int i = 0; i < height.getValue(); i++) { + lines.add(Line.generate(width, generator)); + } + return new Ladder(lines); + } + + public List getLines() { + return Collections.unmodifiableList(lines); + } +} From 9ab451eb333f00565776e69e800245faffc816c5 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:56:33 +0900 Subject: [PATCH 04/42] =?UTF-8?q?feat:=20=EB=9E=9C=EB=8D=A4=EA=B0=92?= =?UTF-8?q?=EC=9D=84=20=EC=9D=B4=EC=9A=A9=ED=95=9C=20=EC=82=AC=EB=8B=A4?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EA=B0=92=20=EC=84=A4=EC=A0=95=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=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/domain/BooleanGenerator.java | 6 ++++++ src/main/java/domain/RandomBooleanGenerator.java | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/main/java/domain/BooleanGenerator.java create mode 100644 src/main/java/domain/RandomBooleanGenerator.java diff --git a/src/main/java/domain/BooleanGenerator.java b/src/main/java/domain/BooleanGenerator.java new file mode 100644 index 00000000..1ca5cebd --- /dev/null +++ b/src/main/java/domain/BooleanGenerator.java @@ -0,0 +1,6 @@ +package domain; + + +public interface BooleanGenerator { + boolean generate(); +} \ No newline at end of file diff --git a/src/main/java/domain/RandomBooleanGenerator.java b/src/main/java/domain/RandomBooleanGenerator.java new file mode 100644 index 00000000..857e12b5 --- /dev/null +++ b/src/main/java/domain/RandomBooleanGenerator.java @@ -0,0 +1,12 @@ +package domain; + +import java.util.Random; + +public class RandomBooleanGenerator implements BooleanGenerator { + private static final Random RANDOM = new Random(); + + @Override + public boolean generate() { + return RANDOM.nextBoolean(); + } +} From 75be80699452949279abc2bb4fff7939ee7afec0 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:57:01 +0900 Subject: [PATCH 05/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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 | 34 ++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..ea533895 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,34 @@ +package view; +import domain.Ladder; +import domain.Line; + +public class OutputView { + private static final String VERTICAL_LINE = "|"; + private static final String CONNECTED_LINE = "-----"; + private static final String DISCONNECTED_LINE = " "; + private static final String RESULT_MESSAGE = "실행결과\n"; + + public void printLadder(Ladder ladder) { + System.out.println(RESULT_MESSAGE); + ladder.getLines().forEach(this::printLine); + } + + private void printLine(Line line) { + StringBuilder builder = new StringBuilder(); + builder.append(VERTICAL_LINE); + line.getPoints().forEach(point -> appendPoint(builder, point)); + System.out.println(builder.toString()); + } + + private void appendPoint(StringBuilder builder, boolean isConnected) { + builder.append(getLineShape(isConnected)); + builder.append(VERTICAL_LINE); + } + + private String getLineShape(boolean isConnected) { + if (isConnected) { + return CONNECTED_LINE; + } + return DISCONNECTED_LINE; + } +} \ No newline at end of file From 5c216cbfb2029b4622d31d9a033e6910d9db16d5 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:57:16 +0900 Subject: [PATCH 06/42] =?UTF-8?q?feat:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EA=B8=B0=EB=8A=A5=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 | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/controller/LadderController.java diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java new file mode 100644 index 00000000..e0d3d00d --- /dev/null +++ b/src/main/java/controller/LadderController.java @@ -0,0 +1,26 @@ +package controller; + +import domain.*; +import view.InputView; +import view.OutputView; + +public class LadderController { + private final OutputView outputView; + private final InputView inputView; + + public LadderController(InputView inputView, OutputView outputView) { + this.outputView = outputView; + this.inputView = inputView; + + } + + public void run() { + LadderWidth width = new LadderWidth(inputView.readWidth()); + LadderHeight height = new LadderHeight(inputView.readHeight()); + BooleanGenerator generator = new RandomBooleanGenerator(); + + Ladder ladder = Ladder.generate(width, height, generator); + + outputView.printLadder(ladder); + } +} \ No newline at end of file From 44168630ee52aeb8b6b730df926ab5eccf71df13 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:57:46 +0900 Subject: [PATCH 07/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EB=86=92=EC=9D=B4=EB=A5=BC=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/LadderHeight.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/domain/LadderHeight.java diff --git a/src/main/java/domain/LadderHeight.java b/src/main/java/domain/LadderHeight.java new file mode 100644 index 00000000..799c7491 --- /dev/null +++ b/src/main/java/domain/LadderHeight.java @@ -0,0 +1,23 @@ +package domain; + +public class LadderHeight { + private static final int MINIMUM_HEIGHT = 1; + private static final String ERROR_MESSAGE = "사다리 높이는 1 이상이어야 합니다."; + + private final int value; + + public LadderHeight(int value) { + validate(value); + this.value = value; + } + + private void validate(int value) { + if (value < MINIMUM_HEIGHT) { + throw new IllegalArgumentException(ERROR_MESSAGE); + } + } + + public int getValue() { + return value; + } +} From 96cdcde39ff060feeb92d20e25013166a06a47b6 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 10:58:02 +0900 Subject: [PATCH 08/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=ED=8F=AD=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/LadderWidth.java | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/domain/LadderWidth.java diff --git a/src/main/java/domain/LadderWidth.java b/src/main/java/domain/LadderWidth.java new file mode 100644 index 00000000..cd6586fc --- /dev/null +++ b/src/main/java/domain/LadderWidth.java @@ -0,0 +1,28 @@ +package domain; + +public class LadderWidth { + private static final int MINIMUM_WIDTH = 2; + private static final String ERROR_MESSAGE = "사다리 폭은 2 이상이어야 합니다."; + + private final int value; + + public LadderWidth(int value) { + validate(value); + this.value = value; + } + + private void validate(int value) { + if (value < MINIMUM_WIDTH) { + throw new IllegalArgumentException(ERROR_MESSAGE); + } + } + + public int getValue() { + return value; + } + + public int getIntervalCount() { + return value - 1; + } + +} From 05c8532bd3adc06d4a6ea3b8e52af09e5e8ebcd8 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 11:00:51 +0900 Subject: [PATCH 09/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=ED=95=98=EB=8A=94=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=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/domain/Line.java | 39 ++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/domain/Line.java diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java new file mode 100644 index 00000000..e5f2760d --- /dev/null +++ b/src/main/java/domain/Line.java @@ -0,0 +1,39 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Line { + private final List points; + + public Line(List points) { + this.points = points; + } + + public static Line generate(LadderWidth width, BooleanGenerator generator) { + List points = new ArrayList<>(); + boolean previous = false; + for (int i = 0; i < width.getIntervalCount(); i++) { + previous = addPointAndReturnPrevious(points, previous, generator); + } + return new Line(points); + } + + private static boolean addPointAndReturnPrevious(List points, boolean previous, BooleanGenerator generator) { + boolean nextPoint = generateNext(previous, generator); + points.add(nextPoint); + return nextPoint; + } + + private static boolean generateNext(boolean previous, BooleanGenerator generator) { + if (previous) { + return false; + } + return generator.generate(); + } + + public List getPoints() { + return Collections.unmodifiableList(points); + } +} \ No newline at end of file From 3813be0ecd2c20f94069a8a19c970b253f725a22 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 12:56:47 +0900 Subject: [PATCH 10/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index e0d3d00d..385ab05f 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -20,7 +20,9 @@ public void run() { BooleanGenerator generator = new RandomBooleanGenerator(); Ladder ladder = Ladder.generate(width, height, generator); - outputView.printLadder(ladder); + + LadderResult result = ladder.play(width); + outputView.printLadderResult(result); } } \ No newline at end of file From 5f81de0b56b6ba81b355708fe29073900f42997d Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 12:57:38 +0900 Subject: [PATCH 11/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B7=9C=EC=B9=99=EC=9D=84=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/domain/Line.java | 53 +++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java index e5f2760d..7c78958f 100644 --- a/src/main/java/domain/Line.java +++ b/src/main/java/domain/Line.java @@ -11,26 +11,65 @@ public Line(List points) { this.points = points; } - public static Line generate(LadderWidth width, BooleanGenerator generator) { + public static Line generateFirst(LadderWidth width, BooleanGenerator generator) { List points = new ArrayList<>(); boolean previous = false; for (int i = 0; i < width.getIntervalCount(); i++) { - previous = addPointAndReturnPrevious(points, previous, generator); + previous = addPoint(points, previous, false, generator); } return new Line(points); } - private static boolean addPointAndReturnPrevious(List points, boolean previous, BooleanGenerator generator) { - boolean nextPoint = generateNext(previous, generator); + public static Line generateNext(LadderWidth width, BooleanGenerator generator, Line previousLine) { + List points = new ArrayList<>(); + boolean previous = false; + for (int i = 0; i < width.getIntervalCount(); i++) { + boolean above = previousLine.isConnectedAt(i); + previous = addPoint(points, previous, above, generator); + } + return new Line(points); + } + + private static boolean addPoint(List points, boolean previous, boolean above, BooleanGenerator gen) { + boolean nextPoint = determineNext(previous, above, gen); points.add(nextPoint); return nextPoint; } - private static boolean generateNext(boolean previous, BooleanGenerator generator) { - if (previous) { + private static boolean determineNext(boolean previous, boolean above, BooleanGenerator gen) { + if (previous || above) { + return false; + } + return gen.generate(); + } + + public boolean isConnectedAt(int index) { + return points.get(index); + } + + public Position move(Position position) { + int currentIndex = position.getValue(); + if (canMoveLeft(currentIndex)) { + return position.moveLeft(); + } + if (canMoveRight(currentIndex)) { + return position.moveRight(); + } + return position; + } + + private boolean canMoveLeft(int currentIndex) { + if (currentIndex <= 0) { + return false; + } + return points.get(currentIndex - 1); + } + + private boolean canMoveRight(int currentIndex) { + if (currentIndex >= points.size()) { return false; } - return generator.generate(); + return points.get(currentIndex); } public List getPoints() { From 8242c8c8c24b5e16b00a7e26b3261d908a5cb5b4 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 12:58:11 +0900 Subject: [PATCH 12/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index ea533895..e40e877f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,12 +1,14 @@ package view; import domain.Ladder; +import domain.LadderResult; import domain.Line; +import domain.Position; public class OutputView { private static final String VERTICAL_LINE = "|"; private static final String CONNECTED_LINE = "-----"; private static final String DISCONNECTED_LINE = " "; - private static final String RESULT_MESSAGE = "실행결과\n"; + private static final String RESULT_MESSAGE = "\n실행결과\n"; public void printLadder(Ladder ladder) { System.out.println(RESULT_MESSAGE); @@ -31,4 +33,13 @@ private String getLineShape(boolean isConnected) { } return DISCONNECTED_LINE; } + + public void printLadderResult(LadderResult result) { + System.out.println(); + result.getResults().forEach(this::printSingleResult); + } + + private void printSingleResult(Position start, Position end) { + System.out.println(start.getValue() + " -> " + end.getValue()); + } } \ No newline at end of file From 7e90e3058a40d68377b75403eb57c2c56d39c9af Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:00:44 +0900 Subject: [PATCH 13/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/domain/Position.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/domain/Position.java diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java new file mode 100644 index 00000000..6d75d1c6 --- /dev/null +++ b/src/main/java/domain/Position.java @@ -0,0 +1,21 @@ +package domain; + +public class Position { + private final int value; + + public Position(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public Position moveLeft() { + return new Position(value - 1); + } + + public Position moveRight() { + return new Position(value + 1); + } +} \ No newline at end of file From cca1c3fc8967119187243a0ecdceef4447c50281 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:00:51 +0900 Subject: [PATCH 14/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/domain/LadderResult.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/domain/LadderResult.java diff --git a/src/main/java/domain/LadderResult.java b/src/main/java/domain/LadderResult.java new file mode 100644 index 00000000..c0baed21 --- /dev/null +++ b/src/main/java/domain/LadderResult.java @@ -0,0 +1,16 @@ +package domain; + +import java.util.Collections; +import java.util.Map; + +public class LadderResult { + private final Map results; + + public LadderResult(Map results) { + this.results = results; + } + + public Map getResults() { + return Collections.unmodifiableMap(results); + } +} \ No newline at end of file From a12701eb8a304d31ac85fcd090ea89bf62241d4c Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:02:18 +0900 Subject: [PATCH 15/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=9D=98=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/domain/Ladder.java | 53 +++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index a590e6ab..4ee4d7eb 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -2,7 +2,10 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; public class Ladder { private final List lines; @@ -12,14 +15,56 @@ public Ladder(List lines) { } public static Ladder generate(LadderWidth width, LadderHeight height, BooleanGenerator generator) { + Ladder ladder = createLadder(width, height, generator); + while (ladder.hasEmptyInterval(width)) { + ladder = createLadder(width, height, generator); + } + return ladder; + } + + private static Ladder createLadder(LadderWidth width, LadderHeight height, BooleanGenerator generator) { List lines = new ArrayList<>(); - for (int i = 0; i < height.getValue(); i++) { - lines.add(Line.generate(width, generator)); + Line currentLine = Line.generateFirst(width, generator); + lines.add(currentLine); + return new Ladder(addRemainingLines(lines, width, height, generator, currentLine)); + } + + private static List addRemainingLines(List lines, LadderWidth width, LadderHeight height, BooleanGenerator generator, Line firstLine) { + Line currentLine = firstLine; + for (int i = 1; i < height.getValue(); i++) { + currentLine = Line.generateNext(width, generator, currentLine); + lines.add(currentLine); + } + return lines; + } + + private boolean hasEmptyInterval(LadderWidth width) { + return IntStream.range(0, width.getIntervalCount()) + .anyMatch(this::isEmptyInterval); + } + + private boolean isEmptyInterval(int index) { + return lines.stream().noneMatch(line -> line.isConnectedAt(index)); + } + + public LadderResult play(LadderWidth width) { + Map results = new LinkedHashMap<>(); + for (int i = 0; i < width.getValue(); i++) { + Position startPosition = new Position(i); + results.put(startPosition, playOne(startPosition)); + } + return new LadderResult(results); + } + + private Position playOne(Position startPosition) { + Position current = startPosition; + for (Line line : lines) { + current = line.move(current); } - return new Ladder(lines); + return current; } public List getLines() { return Collections.unmodifiableList(lines); } -} +} \ No newline at end of file From 4444739b04d20077f5b7e3bbde044611f7e45cb9 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:03:14 +0900 Subject: [PATCH 16/42] =?UTF-8?q?feat:=20=ED=94=8C=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=96=B4=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/PlayerName.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/domain/PlayerName.java diff --git a/src/main/java/domain/PlayerName.java b/src/main/java/domain/PlayerName.java new file mode 100644 index 00000000..bdf6ad2e --- /dev/null +++ b/src/main/java/domain/PlayerName.java @@ -0,0 +1,17 @@ +package domain; + +public class PlayerName { + private static final int MAX_LENGTH = 5; + private final String value; + + public PlayerName(String value) { + if (value.length() > MAX_LENGTH) { + throw new IllegalArgumentException("이름은 5자를 초과할 수 없습니다."); + } + this.value = value; + } + + public String getValue() { + return value; + } +} \ No newline at end of file From c2f8034fc6e94c13dd7c3e73f16b6ec58baa5728 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:04:02 +0900 Subject: [PATCH 17/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=8B=A4=EB=A6=AC?= =?UTF-8?q?=EC=97=90=20=EB=A7=A4=EC=B9=AD=EB=90=98=EB=8A=94=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Reward.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/java/domain/Reward.java diff --git a/src/main/java/domain/Reward.java b/src/main/java/domain/Reward.java new file mode 100644 index 00000000..91aacd49 --- /dev/null +++ b/src/main/java/domain/Reward.java @@ -0,0 +1,18 @@ +package domain; +public class Reward { + private static final int MAX_LENGTH = 5; + private final String value; + + public Reward(String value) { + if (value.length() > MAX_LENGTH) { + throw new IllegalArgumentException("결과는 5자를 초과할 수 없습니다."); + } + this.value = value; + } + + public String getValue() { + return value; + } +} + + From c4a8b024786a5d9edca880ad38f6f1c7177fc490 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:04:45 +0900 Subject: [PATCH 18/42] =?UTF-8?q?feat:=20=EC=82=AC=EB=9E=8C=EC=9D=84=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=9D=BC=EA=B8=89=20?= =?UTF-8?q?=EC=BB=AC=EB=A0=89=EC=85=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Players.java | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/main/java/domain/Players.java diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java new file mode 100644 index 00000000..82abb9ef --- /dev/null +++ b/src/main/java/domain/Players.java @@ -0,0 +1,30 @@ +package domain; + +import java.util.Collections; +import java.util.List; + +public class Players { + private final List names; + + public Players(List names) { + this.names = names; + } + + public void validateMatch(Rewards rewards) { + if (this.names.size() != rewards.size()) { + throw new IllegalArgumentException("사람 수와 결과 수가 일치하지 않습니다."); + } + } + + public int size() { + return names.size(); + } + + public PlayerName getName(int index) { + return names.get(index); + } + + public List getNames() { + return Collections.unmodifiableList(names); + } +} From 5644c84fe6d66efc22bdde7414b965f034da6a8f Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:05:20 +0900 Subject: [PATCH 19/42] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=ED=95=98=EB=8A=94=20=EC=9D=BC=EA=B8=89=20?= =?UTF-8?q?=EC=BB=AC=EB=A0=89=EC=85=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Rewards.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/java/domain/Rewards.java diff --git a/src/main/java/domain/Rewards.java b/src/main/java/domain/Rewards.java new file mode 100644 index 00000000..8ecf6bc5 --- /dev/null +++ b/src/main/java/domain/Rewards.java @@ -0,0 +1,24 @@ +package domain; + +import java.util.Collections; +import java.util.List; + +public class Rewards { + private final List items; + + public Rewards(List items) { + this.items = items; + } + + public int size() { + return items.size(); + } + + public Reward getReward(int index) { + return items.get(index); + } + + public List getItems() { + return Collections.unmodifiableList(items); + } +} From 160c1bd02d700903bcc34d451386fbe3b0d9a4b0 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:06:52 +0900 Subject: [PATCH 20/42] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=EC=99=80=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EC=9D=84=20=EC=A0=80=EC=9E=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/domain/Player.java | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/domain/Player.java diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java new file mode 100644 index 00000000..508d9bb0 --- /dev/null +++ b/src/main/java/domain/Player.java @@ -0,0 +1,26 @@ +package domain; + +import java.util.Collections; +import java.util.List; + +public class Player { + private final PlayerName name; + private final Reward reward; + + public Player(PlayerName name, Reward reward) { + this.name = name; + this.reward = reward; + } + + public boolean hasName(String targetName) { + return this.name.getValue().equals(targetName); + } + + public PlayerName getName() { + return name; + } + + public Reward getReward() { + return reward; + } +} \ No newline at end of file From 821e9d22d3d9cafc134c62d7dafedbfa3ae737fe Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:10:19 +0900 Subject: [PATCH 21/42] =?UTF-8?q?feat:=201.=20=EC=B0=B8=EA=B0=80=EC=9E=90?= =?UTF-8?q?=20=EC=9D=B4=EB=A6=84=EA=B3=BC=20=EC=8B=A4=ED=96=89=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EC=9E=85=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80.=202.=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EC=8B=9C=20=ED=8F=AD(Width)=EC=9D=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=EC=9D=80=20=EC=82=AC=EB=9E=8C=EC=9D=98=20?= =?UTF-8?q?=EC=88=98(players.size())=EB=A1=9C=20=EB=8F=99=EC=A0=81=20?= =?UTF-8?q?=ED=95=A0=EB=8B=B9=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD.=203.=20=ED=8A=B9=EC=A0=95=20=EC=82=AC=EB=9E=8C?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=A6=84=20=ED=98=B9=EC=9D=80=20"all"=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EC=97=90=20=EB=94=B0=EB=9D=BC=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EB=A5=BC=20=EB=B0=98=EB=B3=B5=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=ED=95=98=EB=8A=94=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 --- .../java/controller/LadderController.java | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 385ab05f..5001a82d 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -5,24 +5,52 @@ import view.OutputView; public class LadderController { - private final OutputView outputView; private final InputView inputView; + private final OutputView outputView; public LadderController(InputView inputView, OutputView outputView) { - this.outputView = outputView; this.inputView = inputView; - + this.outputView = outputView; } public void run() { - LadderWidth width = new LadderWidth(inputView.readWidth()); + Players players = inputView.readPlayers(); + Rewards rewards = inputRewards(players); LadderHeight height = new LadderHeight(inputView.readHeight()); - BooleanGenerator generator = new RandomBooleanGenerator(); - Ladder ladder = Ladder.generate(width, height, generator); - outputView.printLadder(ladder); + Ladder ladder = Ladder.generate(new LadderWidth(players.size()), height, new RandomBooleanGenerator()); + outputView.printLadderBoard(players, ladder, rewards); + + GameResult gameResult = createGameResult(players, rewards, ladder); + printTargetResults(gameResult); + } + + private Rewards inputRewards(Players players) { + Rewards rewards = inputView.readRewards(); + players.validateMatch(rewards); + return rewards; + } + + private GameResult createGameResult(Players players, Rewards rewards, Ladder ladder) { + LadderResult ladderResult = ladder.play(new LadderWidth(players.size())); + return GameResult.of(players, rewards, ladderResult); + } + + private void printTargetResults(GameResult gameResult) { + while (true) { + String target = inputView.readTargetPerson(); + if (processTarget(target, gameResult)) { + break; + } + } + } - LadderResult result = ladder.play(width); - outputView.printLadderResult(result); + private boolean processTarget(String target, GameResult gameResult) { + if ("all".equals(target)) { + outputView.printAllResults(gameResult); + return true; + } + outputView.printSingleResult(gameResult.findByName(target)); + return false; } } \ No newline at end of file From ea9a9a0e899c8c08a816c62638692df0d2acbc32 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:11:59 +0900 Subject: [PATCH 22/42] =?UTF-8?q?feat:=20=EC=89=BC=ED=91=9C(,)=EB=A5=BC=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=AC=B8=EC=9E=90?= =?UTF-8?q?=EC=97=B4=EC=9D=84=20=EB=B6=84=EB=A6=AC=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=EC=82=AC=EB=9E=8C=20=EC=9D=B4=EB=A6=84=EA=B3=BC=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EB=A5=BC=20=EC=9E=85=EB=A0=A5=EB=B0=9B=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80.=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EB=A5=BC=20=ED=99=95=EC=9D=B8=ED=95=A0=20=EC=82=AC?= =?UTF-8?q?=EB=9E=8C=EC=9D=98=20=EC=9D=B4=EB=A6=84=EC=9D=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=EB=B0=9B=EB=8A=94=20=20=EB=A9=94=EC=84=9C=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/main/java/view/InputView.java | 44 ++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 30135884..01155ec9 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,19 +1,51 @@ package view; +import domain.PlayerName; +import domain.Players; +import domain.Reward; +import domain.Rewards; + +import java.util.Scanner; + +import java.util.Arrays; +import java.util.List; import java.util.Scanner; +import java.util.stream.Collectors; public class InputView { - private static final String REQUEST_WIDTH_MESSAGE = "사다리의 넓이는 몇 개인가요?"; - private static final String REQUEST_HEIGHT_MESSAGE = "사다리의 높이는 몇 개인가요?"; private static final Scanner SCANNER = new Scanner(System.in); - public int readWidth() { - System.out.println(REQUEST_WIDTH_MESSAGE); - return Integer.parseInt(SCANNER.nextLine()); + public Players readPlayers() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); + return new Players(parseNames(SCANNER.nextLine())); + } + + private List parseNames(String input) { + return Arrays.stream(input.split(",")) + .map(String::trim) + .map(PlayerName::new) + .collect(Collectors.toList()); + } + + public Rewards readRewards() { + System.out.println("\n실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); + return new Rewards(parseRewards(SCANNER.nextLine())); + } + + private List parseRewards(String input) { + return Arrays.stream(input.split(",")) + .map(String::trim) + .map(Reward::new) + .collect(Collectors.toList()); } public int readHeight() { - System.out.println(REQUEST_HEIGHT_MESSAGE); + System.out.println("\n최대 사다리 높이는 몇 개인가요?"); return Integer.parseInt(SCANNER.nextLine()); } + + public String readTargetPerson() { + System.out.println("\n결과를 보고 싶은 사람은?"); + return SCANNER.nextLine().trim(); + } } \ No newline at end of file From 3007e43b1afde5057c7c3f5be5e1e00fb3bf00d5 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:13:07 +0900 Subject: [PATCH 23/42] =?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=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20pri?= =?UTF-8?q?ntLadderBoard=20=EB=A1=9C=20=EB=B3=80=EA=B2=BD.=20=EC=82=AC?= =?UTF-8?q?=EB=8B=A4=EB=A6=AC=20=EC=B6=9C=EB=A0=A5=20=EC=A0=84=ED=9B=84?= =?UTF-8?q?=EB=A1=9C=20=EC=82=AC=EB=9E=8C=20=EC=9D=B4=EB=A6=84=EA=B3=BC=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=206=EC=9E=90?= =?UTF-8?q?=EB=A6=AC=20=EA=B0=84=EA=B2=A9=EC=9C=BC=EB=A1=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=ED=95=98=EC=97=AC=20=EC=B6=9C=EB=A0=A5=ED=95=98?= =?UTF-8?q?=EB=8A=94=20printNames,=20printRewards=20=EB=A1=9C=EC=A7=81=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/view/OutputView.java | 43 +++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index e40e877f..100c337f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,18 +1,32 @@ package view; -import domain.Ladder; -import domain.LadderResult; -import domain.Line; -import domain.Position; +import domain.*; + +import java.util.stream.Collectors; public class OutputView { private static final String VERTICAL_LINE = "|"; private static final String CONNECTED_LINE = "-----"; private static final String DISCONNECTED_LINE = " "; - private static final String RESULT_MESSAGE = "\n실행결과\n"; - public void printLadder(Ladder ladder) { - System.out.println(RESULT_MESSAGE); + public void printLadderBoard(Players players, Ladder ladder, Rewards rewards) { + System.out.println("\n사다리 결과\n"); + printNames(players); ladder.getLines().forEach(this::printLine); + printRewards(rewards); + } + + private void printNames(Players players) { + String names = players.getNames().stream() + .map(name -> String.format("%-6s", name.getValue())) + .collect(Collectors.joining()); + System.out.println(names); + } + + private void printRewards(Rewards rewards) { + String items = rewards.getItems().stream() + .map(reward -> String.format("%-6s", reward.getValue())) + .collect(Collectors.joining()); + System.out.println(items); } private void printLine(Line line) { @@ -34,12 +48,17 @@ private String getLineShape(boolean isConnected) { return DISCONNECTED_LINE; } - public void printLadderResult(LadderResult result) { - System.out.println(); - result.getResults().forEach(this::printSingleResult); + public void printSingleResult(Player player) { + System.out.println("\n실행 결과"); + System.out.println(player.getReward().getValue()); + } + + public void printAllResults(GameResult gameResult) { + System.out.println("\n실행 결과"); + gameResult.getAll().forEach(this::printFormattedResult); } - private void printSingleResult(Position start, Position end) { - System.out.println(start.getValue() + " -> " + end.getValue()); + private void printFormattedResult(Player player) { + System.out.println(player.getName().getValue() + " : " + player.getReward().getValue()); } } \ No newline at end of file From 9bd9cc18b705b719999b680076a9c9a4af4063f1 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:14:01 +0900 Subject: [PATCH 24/42] =?UTF-8?q?feat:=20Map=20?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=ED=82=A4(Ke?= =?UTF-8?q?y)=EB=A1=9C=20=EC=A0=95=EC=83=81=20=EC=A1=B0=ED=9A=8C=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=20equals=20=EB=B0=8F=20hashCode?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=98=A4=EB=B2=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=94=A9=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/domain/Position.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 6d75d1c6..09a2036d 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -18,4 +18,17 @@ public Position moveLeft() { public Position moveRight() { return new Position(value + 1); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Position position = (Position) o; + return value == position.value; + } + + @Override + public int hashCode() { + return value; + } } \ No newline at end of file From 035a320680b3e63264f0ebc405e2aa69f36e5b6a Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:14:49 +0900 Subject: [PATCH 25/42] =?UTF-8?q?feat:=20=EC=8B=9C=EC=9E=91=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=EB=A5=BC=20=EC=A0=84=EB=8B=AC=EB=B0=9B=EC=95=84=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91=EB=90=9C=20=EB=8F=84=EC=B0=A9=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=EB=A5=BC=20=EB=B0=98=ED=99=98=ED=95=98=EB=8A=94?= =?UTF-8?q?=EB=A9=94=EC=84=9C=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/domain/LadderResult.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/domain/LadderResult.java b/src/main/java/domain/LadderResult.java index c0baed21..3cbb3d72 100644 --- a/src/main/java/domain/LadderResult.java +++ b/src/main/java/domain/LadderResult.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.Map; + public class LadderResult { private final Map results; @@ -10,6 +11,10 @@ public LadderResult(Map results) { this.results = results; } + public Position getEndPosition(Position start) { + return results.get(start); + } + public Map getResults() { return Collections.unmodifiableMap(results); } From a38db349a26c4c087a336e9935ac895f7467c013 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:21:37 +0900 Subject: [PATCH 26/42] =?UTF-8?q?feat:=20=EA=B2=B0=EA=B3=BC=EB=A5=BC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/domain/LadderResult.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/domain/LadderResult.java b/src/main/java/domain/LadderResult.java index 3cbb3d72..858f9055 100644 --- a/src/main/java/domain/LadderResult.java +++ b/src/main/java/domain/LadderResult.java @@ -1,6 +1,4 @@ package domain; - -import java.util.Collections; import java.util.Map; @@ -14,8 +12,4 @@ public LadderResult(Map results) { public Position getEndPosition(Position start) { return results.get(start); } - - public Map getResults() { - return Collections.unmodifiableMap(results); - } } \ No newline at end of file From b3cf1a45b169106982e4730f9ceb624b6f29bade Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 13:22:00 +0900 Subject: [PATCH 27/42] =?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=EA=B2=B0=EA=B3=BC=EB=A5=BC=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=ED=95=98=EB=8A=94=20=EA=B8=B0=EB=8A=A5=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/main/java/domain/GameResult.java | 38 ++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/domain/GameResult.java diff --git a/src/main/java/domain/GameResult.java b/src/main/java/domain/GameResult.java new file mode 100644 index 00000000..256b1c0b --- /dev/null +++ b/src/main/java/domain/GameResult.java @@ -0,0 +1,38 @@ +package domain; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class GameResult { + private final List players; + + public GameResult(List players) { + this.players = players; + } + + public static GameResult of(Players players, Rewards rewards, LadderResult ladderResult) { + List playerList = new ArrayList<>(); + for (int i = 0; i < players.size(); i++) { + playerList.add(createPlayer(i, players, rewards, ladderResult)); + } + return new GameResult(playerList); + } + + private static Player createPlayer(int index, Players players, Rewards rewards, LadderResult result) { + Position start = new Position(index); + Position end = result.getEndPosition(start); + return new Player(players.getName(index), rewards.getReward(end.getValue())); + } + + public Player findByName(String targetName) { + return players.stream() + .filter(player -> player.hasName(targetName)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 사람입니다.")); + } + + public List getAll() { + return Collections.unmodifiableList(players); + } +} \ No newline at end of file From d03a63783fe9b8f8f47ce9dd7d8cc02a57cd49aa Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Tue, 28 Apr 2026 16:07:06 +0900 Subject: [PATCH 28/42] =?UTF-8?q?chore:=20=EA=B3=B5=EB=B0=B1=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/README.md | 0 .../java/controller/LadderController.java | 2 +- src/main/java/domain/BooleanGenerator.java | 2 +- src/main/java/domain/GameResult.java | 2 +- src/main/java/domain/Ladder.java | 2 +- src/main/java/domain/LadderHeight.java | 1 + src/main/java/domain/LadderResult.java | 2 +- src/main/java/domain/Line.java | 2 +- src/main/java/domain/Player.java | 4 +- src/main/java/domain/PlayerName.java | 2 +- src/main/java/domain/Position.java | 2 +- src/main/java/domain/Reward.java | 2 - src/main/java/view/InputView.java | 3 +- src/main/java/view/OutputView.java | 2 +- src/test/java/domain/GameResultTest.java | 30 +++++++++++ src/test/java/domain/LadderTest.java | 34 +++++++++++++ src/test/java/domain/LineTest.java | 50 +++++++++++++++++++ src/test/java/domain/PositionTest.java | 28 +++++++++++ 18 files changed, 154 insertions(+), 16 deletions(-) create mode 100644 src/README.md create mode 100644 src/test/java/domain/GameResultTest.java create mode 100644 src/test/java/domain/LadderTest.java create mode 100644 src/test/java/domain/LineTest.java create mode 100644 src/test/java/domain/PositionTest.java diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 5001a82d..352501f2 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -53,4 +53,4 @@ private boolean processTarget(String target, GameResult gameResult) { outputView.printSingleResult(gameResult.findByName(target)); return false; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/BooleanGenerator.java b/src/main/java/domain/BooleanGenerator.java index 1ca5cebd..92ad2cab 100644 --- a/src/main/java/domain/BooleanGenerator.java +++ b/src/main/java/domain/BooleanGenerator.java @@ -3,4 +3,4 @@ public interface BooleanGenerator { boolean generate(); -} \ No newline at end of file +} diff --git a/src/main/java/domain/GameResult.java b/src/main/java/domain/GameResult.java index 256b1c0b..dd7d5236 100644 --- a/src/main/java/domain/GameResult.java +++ b/src/main/java/domain/GameResult.java @@ -35,4 +35,4 @@ public Player findByName(String targetName) { public List getAll() { return Collections.unmodifiableList(players); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index 4ee4d7eb..5c86cbd7 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -67,4 +67,4 @@ private Position playOne(Position startPosition) { public List getLines() { return Collections.unmodifiableList(lines); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/LadderHeight.java b/src/main/java/domain/LadderHeight.java index 799c7491..07ebabf2 100644 --- a/src/main/java/domain/LadderHeight.java +++ b/src/main/java/domain/LadderHeight.java @@ -17,6 +17,7 @@ private void validate(int value) { } } + public int getValue() { return value; } diff --git a/src/main/java/domain/LadderResult.java b/src/main/java/domain/LadderResult.java index 858f9055..0a5dd113 100644 --- a/src/main/java/domain/LadderResult.java +++ b/src/main/java/domain/LadderResult.java @@ -12,4 +12,4 @@ public LadderResult(Map results) { public Position getEndPosition(Position start) { return results.get(start); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java index 7c78958f..b966b644 100644 --- a/src/main/java/domain/Line.java +++ b/src/main/java/domain/Line.java @@ -75,4 +75,4 @@ private boolean canMoveRight(int currentIndex) { public List getPoints() { return Collections.unmodifiableList(points); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 508d9bb0..9fcc9a2c 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -1,7 +1,5 @@ package domain; -import java.util.Collections; -import java.util.List; public class Player { private final PlayerName name; @@ -23,4 +21,4 @@ public PlayerName getName() { public Reward getReward() { return reward; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/PlayerName.java b/src/main/java/domain/PlayerName.java index bdf6ad2e..952d6144 100644 --- a/src/main/java/domain/PlayerName.java +++ b/src/main/java/domain/PlayerName.java @@ -14,4 +14,4 @@ public PlayerName(String value) { public String getValue() { return value; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 09a2036d..925bf615 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -31,4 +31,4 @@ public boolean equals(Object o) { public int hashCode() { return value; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Reward.java b/src/main/java/domain/Reward.java index 91aacd49..f97829ed 100644 --- a/src/main/java/domain/Reward.java +++ b/src/main/java/domain/Reward.java @@ -14,5 +14,3 @@ public String getValue() { return value; } } - - diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 01155ec9..f5811097 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -9,7 +9,6 @@ import java.util.Arrays; import java.util.List; -import java.util.Scanner; import java.util.stream.Collectors; public class InputView { @@ -48,4 +47,4 @@ public String readTargetPerson() { System.out.println("\n결과를 보고 싶은 사람은?"); return SCANNER.nextLine().trim(); } -} \ No newline at end of file +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 100c337f..498be687 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -61,4 +61,4 @@ public void printAllResults(GameResult gameResult) { private void printFormattedResult(Player player) { System.out.println(player.getName().getValue() + " : " + player.getReward().getValue()); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java new file mode 100644 index 00000000..d78c476f --- /dev/null +++ b/src/test/java/domain/GameResultTest.java @@ -0,0 +1,30 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class GameResultTest { + + @Test + @DisplayName("이름으로 결과를 찾을 수 있다.") + void findByName() { + Player player = new Player(new PlayerName("neo"), new Reward("꽝")); + GameResult gameResult = new GameResult(Arrays.asList(player)); + + assertThat(gameResult.findByName("neo").getReward().getValue()).isEqualTo("꽝"); + } + + @Test + @DisplayName("존재하지 않는 이름으로 검색 시 예외가 발생한다.") + void findByName_Fail() { + GameResult gameResult = new GameResult(Arrays.asList()); + + assertThatThrownBy(() -> gameResult.findByName("none")) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/domain/LadderTest.java b/src/test/java/domain/LadderTest.java new file mode 100644 index 00000000..e8b08309 --- /dev/null +++ b/src/test/java/domain/LadderTest.java @@ -0,0 +1,34 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class LadderTest { + + @Test + @DisplayName("제어된 제너레이터를 통해 빈 공간 발생 시 사다리가 재생성되는지 검증한다.") + void generateAndRetryWhenEmptyInterval() { + BooleanGenerator customGenerator = new BooleanGenerator() { + private int callCount = 0; + + @Override + public boolean generate() { + callCount++; + // 3간격 * 2높이 = 6번 호출됨 + // 첫 번째 시도(callCount <= 6)는 모두 false 반환 -> 공백 사다리 발생 조건 + // 두 번째 시도부터 true를 섞어 반환 -> 정상 사다리 생성 + return callCount > 6; + } + }; + + Ladder ladder = Ladder.generate(new LadderWidth(3), new LadderHeight(2), customGenerator); + + // 높이가 2인 사다리가 정상적으로 반환되었는지 검증 + assertThat(ladder.getLines()).hasSize(2); + + // 재시도 로직을 거쳐 새롭게 생성된(true가 포함된) 라인인지 확인 + assertThat(ladder.getLines().get(0).isConnectedAt(0)).isTrue(); + } +} \ No newline at end of file diff --git a/src/test/java/domain/LineTest.java b/src/test/java/domain/LineTest.java new file mode 100644 index 00000000..fafc9514 --- /dev/null +++ b/src/test/java/domain/LineTest.java @@ -0,0 +1,50 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class LineTest { + + @Test + @DisplayName("가로 라인은 연속으로 생성되지 않는다.") + void generateFirst() { + Line line = Line.generateFirst(new LadderWidth(3), () -> true); + + assertThat(line.isConnectedAt(0)).isTrue(); + assertThat(line.isConnectedAt(1)).isFalse(); + } + + @Test + @DisplayName("현재 위치에서 연결된 방향으로 이동한다.") + void move() { + Line line = new Line(Arrays.asList(true, false)); + + assertThat(line.move(new Position(0))).isEqualTo(new Position(1)); + assertThat(line.move(new Position(1))).isEqualTo(new Position(0)); + assertThat(line.move(new Position(2))).isEqualTo(new Position(2)); + } + + @Test + @DisplayName("주입된 불리언 제너레이터의 반환값에 따라 사다리 라인이 검증된다.") + void generateWithSequentialRandom() { + BooleanGenerator sequentialGenerator = new BooleanGenerator() { + private boolean flag = false; + + @Override + public boolean generate() { + flag = !flag; + return flag; // true, false, true, false 순서로 반환 + } + }; + + Line line = Line.generateFirst(new LadderWidth(4), sequentialGenerator); + + assertThat(line.isConnectedAt(0)).isTrue(); + assertThat(line.isConnectedAt(1)).isFalse(); + assertThat(line.isConnectedAt(2)).isTrue(); + } +} \ No newline at end of file diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java new file mode 100644 index 00000000..9312910a --- /dev/null +++ b/src/test/java/domain/PositionTest.java @@ -0,0 +1,28 @@ +package domain; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PositionTest { + + @Test + @DisplayName("왼쪽으로 이동한다.") + void moveLeft() { + Position position = new Position(1); + assertThat(position.moveLeft()).isEqualTo(new Position(0)); + } + + @Test + @DisplayName("오른쪽으로 이동한다.") + void moveRight() { + Position position = new Position(1); + assertThat(position.moveRight()).isEqualTo(new Position(2)); + } + + @Test + @DisplayName("동일한 값을 가지면 동등한 객체로 취급한다.") + void equals() { + assertThat(new Position(1)).isEqualTo(new Position(1)); + } +} \ No newline at end of file From cec2e4f1d4969a13b6cad7533a17678a3228c6e3 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:23:18 +0900 Subject: [PATCH 29/42] =?UTF-8?q?feat:=20=ED=95=B4=EC=8B=9C=EC=BD=94?= =?UTF-8?q?=EB=93=9C,=20equals=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/domain/PlayerName.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/domain/PlayerName.java b/src/main/java/domain/PlayerName.java index 952d6144..dc9dda86 100644 --- a/src/main/java/domain/PlayerName.java +++ b/src/main/java/domain/PlayerName.java @@ -1,5 +1,7 @@ package domain; +import java.util.Objects; + public class PlayerName { private static final int MAX_LENGTH = 5; private final String value; @@ -14,4 +16,17 @@ public PlayerName(String value) { public String getValue() { return value; } -} + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlayerName that = (PlayerName) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } +} \ No newline at end of file From b821da1bc33f3752c69cae373636246069958048 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:24:17 +0900 Subject: [PATCH 30/42] =?UTF-8?q?feat:=20=EA=B0=9D=EC=B2=B4=20=EB=B9=84?= =?UTF-8?q?=EA=B5=90=EB=A1=9C=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/domain/Player.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 9fcc9a2c..7b34b4fd 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -1,6 +1,5 @@ package domain; - public class Player { private final PlayerName name; private final Reward reward; @@ -11,7 +10,7 @@ public Player(PlayerName name, Reward reward) { } public boolean hasName(String targetName) { - return this.name.getValue().equals(targetName); + return this.name.equals(new PlayerName(targetName)); } public PlayerName getName() { @@ -21,4 +20,4 @@ public PlayerName getName() { public Reward getReward() { return reward; } -} +} \ No newline at end of file From ad72977269e874a61bdfde7c14cb336e2433251b Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:25:23 +0900 Subject: [PATCH 31/42] =?UTF-8?q?refactor:=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Players.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java index 82abb9ef..c9aa2c84 100644 --- a/src/main/java/domain/Players.java +++ b/src/main/java/domain/Players.java @@ -10,12 +10,6 @@ public Players(List names) { this.names = names; } - public void validateMatch(Rewards rewards) { - if (this.names.size() != rewards.size()) { - throw new IllegalArgumentException("사람 수와 결과 수가 일치하지 않습니다."); - } - } - public int size() { return names.size(); } @@ -27,4 +21,4 @@ public PlayerName getName(int index) { public List getNames() { return Collections.unmodifiableList(names); } -} +} \ No newline at end of file From ea59aca2dfaf7fbae7b08a60f4503154e6d71736 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:26:32 +0900 Subject: [PATCH 32/42] =?UTF-8?q?refactor:=20=EC=9D=B4=EB=A6=84=EC=97=90?= =?UTF-8?q?=20=EB=8C=80=ED=95=9C=20=EC=B1=85=EC=9E=84=20=EA=B2=80=EC=A6=9D?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/controller/LadderController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 352501f2..a70f9991 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -27,7 +27,9 @@ public void run() { private Rewards inputRewards(Players players) { Rewards rewards = inputView.readRewards(); - players.validateMatch(rewards); + if (players.size() != rewards.size()) { + throw new IllegalArgumentException("사람 수와 결과 수가 일치하지 않습니다."); + } return rewards; } @@ -53,4 +55,4 @@ private boolean processTarget(String target, GameResult gameResult) { outputView.printSingleResult(gameResult.findByName(target)); return false; } -} +} \ No newline at end of file From 895b46b4a785de94508c654bc8a7a153e2002a9a Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:27:13 +0900 Subject: [PATCH 33/42] =?UTF-8?q?feat:=20=EC=9D=B4=EB=A6=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=ED=98=95=EC=8B=9D=20=EA=B2=80=EC=A6=9D=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=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 | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index f5811097..f55d6cc1 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -6,7 +6,6 @@ import domain.Rewards; import java.util.Scanner; - import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -16,7 +15,9 @@ public class InputView { public Players readPlayers() { System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); - return new Players(parseNames(SCANNER.nextLine())); + String input = SCANNER.nextLine(); + validateInputFormat(input); + return new Players(parseNames(input)); } private List parseNames(String input) { @@ -28,7 +29,9 @@ private List parseNames(String input) { public Rewards readRewards() { System.out.println("\n실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요)"); - return new Rewards(parseRewards(SCANNER.nextLine())); + String input = SCANNER.nextLine(); + validateInputFormat(input); + return new Rewards(parseRewards(input)); } private List parseRewards(String input) { @@ -38,13 +41,22 @@ private List parseRewards(String input) { .collect(Collectors.toList()); } + private void validateInputFormat(String input) { + if (input == null || input.trim().isEmpty()) { + throw new IllegalArgumentException("입력값이 비어있습니다."); + } + if (input.startsWith(",") || input.endsWith(",")) { + throw new IllegalArgumentException("입력값은 쉼표(,)로 시작하거나 끝날 수 없습니다."); + } + } + public int readHeight() { System.out.println("\n최대 사다리 높이는 몇 개인가요?"); - return Integer.parseInt(SCANNER.nextLine()); + return Integer.parseInt(SCANNER.nextLine().trim()); } public String readTargetPerson() { System.out.println("\n결과를 보고 싶은 사람은?"); return SCANNER.nextLine().trim(); } -} +} \ No newline at end of file From 3b5ff8d0257f152cf60634909a566483f9ba7c64 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:37:22 +0900 Subject: [PATCH 34/42] =?UTF-8?q?refactor:=20=EB=B3=80=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Ladder.java | 4 ++-- src/main/java/domain/Line.java | 19 +++++++++++-------- src/main/java/domain/Position.java | 3 +-- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index 5c86cbd7..fdfe8dcd 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -16,7 +16,7 @@ public Ladder(List lines) { public static Ladder generate(LadderWidth width, LadderHeight height, BooleanGenerator generator) { Ladder ladder = createLadder(width, height, generator); - while (ladder.hasEmptyInterval(width)) { + while (ladder.hasEmptyInterval(width)) { // 불량이 있을 경우에만 ladder = createLadder(width, height, generator); } return ladder; @@ -43,7 +43,7 @@ private boolean hasEmptyInterval(LadderWidth width) { .anyMatch(this::isEmptyInterval); } - private boolean isEmptyInterval(int index) { + private boolean isEmptyInterval(int index) { // 불량 판정 return lines.stream().noneMatch(line -> line.isConnectedAt(index)); } diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java index b966b644..5e2805f4 100644 --- a/src/main/java/domain/Line.java +++ b/src/main/java/domain/Line.java @@ -22,25 +22,28 @@ public static Line generateFirst(LadderWidth width, BooleanGenerator generator) public static Line generateNext(LadderWidth width, BooleanGenerator generator, Line previousLine) { List points = new ArrayList<>(); - boolean previous = false; + boolean isConnectedLeft = false; for (int i = 0; i < width.getIntervalCount(); i++) { - boolean above = previousLine.isConnectedAt(i); - previous = addPoint(points, previous, above, generator); + boolean isConnectedAbove = previousLine.isConnectedAt(i); + isConnectedLeft = addPoint(points, isConnectedLeft, isConnectedAbove, generator); } return new Line(points); } - private static boolean addPoint(List points, boolean previous, boolean above, BooleanGenerator gen) { - boolean nextPoint = determineNext(previous, above, gen); + private static boolean addPoint(List points, boolean isConnectedLeft, boolean isConnectedAbove, BooleanGenerator gen) { + boolean nextPoint = determineNext(isConnectedLeft, isConnectedAbove, gen); points.add(nextPoint); + return nextPoint; } - private static boolean determineNext(boolean previous, boolean above, BooleanGenerator gen) { - if (previous || above) { + private static boolean determineNext(boolean isConnectedLeft, boolean isConnectedAbove, BooleanGenerator generator + ) { + if (isConnectedLeft || isConnectedAbove) { return false; } - return gen.generate(); + + return generator.generate(); } public boolean isConnectedAt(int index) { diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 925bf615..3dd20ea4 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -1,5 +1,4 @@ package domain; - public class Position { private final int value; @@ -31,4 +30,4 @@ public boolean equals(Object o) { public int hashCode() { return value; } -} +} \ No newline at end of file From d9c9a921f8317cb87b85cb51ede5bc98a9137547 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 12:50:36 +0900 Subject: [PATCH 35/42] =?UTF-8?q?refactor:=20ladder=20=EC=9D=98=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 13 +++++- src/main/java/domain/Ladder.java | 37 +--------------- src/main/java/domain/LadderGenerator.java | 44 +++++++++++++++++++ 3 files changed, 56 insertions(+), 38 deletions(-) create mode 100644 src/main/java/domain/LadderGenerator.java diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index a70f9991..062821be 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,6 +1,15 @@ package controller; -import domain.*; + +import domain.LadderGenerator; +import domain.LadderHeight; +import domain.Players; +import domain.Rewards; +import domain.GameResult; +import domain.Ladder; +import domain.LadderWidth; +import domain.LadderResult; +import domain.RandomBooleanGenerator; import view.InputView; import view.OutputView; @@ -18,7 +27,7 @@ public void run() { Rewards rewards = inputRewards(players); LadderHeight height = new LadderHeight(inputView.readHeight()); - Ladder ladder = Ladder.generate(new LadderWidth(players.size()), height, new RandomBooleanGenerator()); + Ladder ladder = LadderGenerator.generate(new LadderWidth(players.size()), height, new RandomBooleanGenerator()); outputView.printLadderBoard(players, ladder, rewards); GameResult gameResult = createGameResult(players, rewards, ladder); diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index fdfe8dcd..c2fad6b8 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -1,11 +1,9 @@ package domain; -import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.stream.IntStream; public class Ladder { private final List lines; @@ -14,39 +12,6 @@ public Ladder(List lines) { this.lines = lines; } - public static Ladder generate(LadderWidth width, LadderHeight height, BooleanGenerator generator) { - Ladder ladder = createLadder(width, height, generator); - while (ladder.hasEmptyInterval(width)) { // 불량이 있을 경우에만 - ladder = createLadder(width, height, generator); - } - return ladder; - } - - private static Ladder createLadder(LadderWidth width, LadderHeight height, BooleanGenerator generator) { - List lines = new ArrayList<>(); - Line currentLine = Line.generateFirst(width, generator); - lines.add(currentLine); - return new Ladder(addRemainingLines(lines, width, height, generator, currentLine)); - } - - private static List addRemainingLines(List lines, LadderWidth width, LadderHeight height, BooleanGenerator generator, Line firstLine) { - Line currentLine = firstLine; - for (int i = 1; i < height.getValue(); i++) { - currentLine = Line.generateNext(width, generator, currentLine); - lines.add(currentLine); - } - return lines; - } - - private boolean hasEmptyInterval(LadderWidth width) { - return IntStream.range(0, width.getIntervalCount()) - .anyMatch(this::isEmptyInterval); - } - - private boolean isEmptyInterval(int index) { // 불량 판정 - return lines.stream().noneMatch(line -> line.isConnectedAt(index)); - } - public LadderResult play(LadderWidth width) { Map results = new LinkedHashMap<>(); for (int i = 0; i < width.getValue(); i++) { @@ -67,4 +32,4 @@ private Position playOne(Position startPosition) { public List getLines() { return Collections.unmodifiableList(lines); } -} +} \ No newline at end of file diff --git a/src/main/java/domain/LadderGenerator.java b/src/main/java/domain/LadderGenerator.java new file mode 100644 index 00000000..8153cb6c --- /dev/null +++ b/src/main/java/domain/LadderGenerator.java @@ -0,0 +1,44 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.IntStream; + +public class LadderGenerator { + + private LadderGenerator() { + } + + public static Ladder generate(LadderWidth width, LadderHeight height, BooleanGenerator generator) { + Ladder ladder = createLadder(width, height, generator); + while (hasEmptyInterval(ladder, width)) { + ladder = createLadder(width, height, generator); + } + return ladder; + } + + private static Ladder createLadder(LadderWidth width, LadderHeight height, BooleanGenerator generator) { + List lines = new ArrayList<>(); + Line currentLine = Line.generateFirst(width, generator); + lines.add(currentLine); + return new Ladder(addRemainingLines(lines, width, height, generator, currentLine)); + } + + private static List addRemainingLines(List lines, LadderWidth width, LadderHeight height, BooleanGenerator generator, Line firstLine) { + Line currentLine = firstLine; + for (int i = 1; i < height.getValue(); i++) { + currentLine = Line.generateNext(width, generator, currentLine); + lines.add(currentLine); + } + return lines; + } + + private static boolean hasEmptyInterval(Ladder ladder, LadderWidth width) { + return IntStream.range(0, width.getIntervalCount()) + .anyMatch(index -> isEmptyInterval(ladder, index)); + } + + private static boolean isEmptyInterval(Ladder ladder, int index) { + return ladder.getLines().stream().noneMatch(line -> line.isConnectedAt(index)); + } +} \ No newline at end of file From d91171fc9cf22c2c056c670df5962f852ff86b6f Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:02:23 +0900 Subject: [PATCH 36/42] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/LadderGeneratorTest.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/test/java/domain/LadderGeneratorTest.java diff --git a/src/test/java/domain/LadderGeneratorTest.java b/src/test/java/domain/LadderGeneratorTest.java new file mode 100644 index 00000000..5689faa4 --- /dev/null +++ b/src/test/java/domain/LadderGeneratorTest.java @@ -0,0 +1,30 @@ +package domain; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +class LadderGeneratorTest { + @Test + void 존재하는_이름으로_검색하면_해당_플레이어를_반환한다() { + Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); + GameResult gameResult = new GameResult(List.of(pobi)); + + assertThat(gameResult.findByName("pobi")).isEqualTo(pobi); + } + + @Test + void 존재하지_않는_이름으로_검색하면_예외가_발생한다() { + Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); + GameResult gameResult = new GameResult(List.of(pobi)); + + assertThatThrownBy(() -> gameResult.findByName("crong")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("존재하지 않는 사람입니다."); + } + +} \ No newline at end of file From 0eb57b82b0e0775de0b6009f4f18ddba06c6e8e1 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:02:27 +0900 Subject: [PATCH 37/42] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/LadderTest.java | 41 +++++++++++----------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/test/java/domain/LadderTest.java b/src/test/java/domain/LadderTest.java index e8b08309..723fbb31 100644 --- a/src/test/java/domain/LadderTest.java +++ b/src/test/java/domain/LadderTest.java @@ -1,34 +1,25 @@ package domain; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; +import java.util.List; +import static org.assertj.core.api.Assertions.*; class LadderTest { @Test - @DisplayName("제어된 제너레이터를 통해 빈 공간 발생 시 사다리가 재생성되는지 검증한다.") - void generateAndRetryWhenEmptyInterval() { - BooleanGenerator customGenerator = new BooleanGenerator() { - private int callCount = 0; - - @Override - public boolean generate() { - callCount++; - // 3간격 * 2높이 = 6번 호출됨 - // 첫 번째 시도(callCount <= 6)는 모두 false 반환 -> 공백 사다리 발생 조건 - // 두 번째 시도부터 true를 섞어 반환 -> 정상 사다리 생성 - return callCount > 6; - } - }; - - Ladder ladder = Ladder.generate(new LadderWidth(3), new LadderHeight(2), customGenerator); - - // 높이가 2인 사다리가 정상적으로 반환되었는지 검증 - assertThat(ladder.getLines()).hasSize(2); - - // 재시도 로직을 거쳐 새롭게 생성된(true가 포함된) 라인인지 확인 - assertThat(ladder.getLines().get(0).isConnectedAt(0)).isTrue(); + void 정상적인_사다리를_실행하면_계산된_결과를_반환한다() { + // given + Line line1 = new Line(List.of(true, false)); // 0-1 연결 + Line line2 = new Line(List.of(false, true)); // 1-2 연결 + Ladder ladder = new Ladder(List.of(line1, line2)); + LadderWidth width = new LadderWidth(3); + + // when + LadderResult result = ladder.play(width); + + // then + assertThat(result.getEndPosition(new Position(0))).isEqualTo(new Position(2)); + assertThat(result.getEndPosition(new Position(1))).isEqualTo(new Position(0)); + assertThat(result.getEndPosition(new Position(2))).isEqualTo(new Position(1)); } } \ No newline at end of file From aebc5ed9b1f185048ecce64cf3e65201aa56b05e Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:02:33 +0900 Subject: [PATCH 38/42] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/LineTest.java | 49 +++++++++--------------------- 1 file changed, 14 insertions(+), 35 deletions(-) diff --git a/src/test/java/domain/LineTest.java b/src/test/java/domain/LineTest.java index fafc9514..0a17f035 100644 --- a/src/test/java/domain/LineTest.java +++ b/src/test/java/domain/LineTest.java @@ -1,50 +1,29 @@ package domain; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - -import java.util.Arrays; - -import static org.assertj.core.api.Assertions.assertThat; +import java.util.List; +import static org.assertj.core.api.Assertions.*; class LineTest { @Test - @DisplayName("가로 라인은 연속으로 생성되지 않는다.") - void generateFirst() { - Line line = Line.generateFirst(new LadderWidth(3), () -> true); - - assertThat(line.isConnectedAt(0)).isTrue(); - assertThat(line.isConnectedAt(1)).isFalse(); + void 왼쪽이_연결되어_있으면_왼쪽으로_이동한다() { + Line line = new Line(List.of(true, false)); + Position current = new Position(1); + assertThat(line.move(current)).isEqualTo(new Position(0)); } @Test - @DisplayName("현재 위치에서 연결된 방향으로 이동한다.") - void move() { - Line line = new Line(Arrays.asList(true, false)); - - assertThat(line.move(new Position(0))).isEqualTo(new Position(1)); - assertThat(line.move(new Position(1))).isEqualTo(new Position(0)); - assertThat(line.move(new Position(2))).isEqualTo(new Position(2)); + void 오른쪽이_연결되어_있으면_오른쪽으로_이동한다() { + Line line = new Line(List.of(true, false)); + Position current = new Position(0); + assertThat(line.move(current)).isEqualTo(new Position(1)); } @Test - @DisplayName("주입된 불리언 제너레이터의 반환값에 따라 사다리 라인이 검증된다.") - void generateWithSequentialRandom() { - BooleanGenerator sequentialGenerator = new BooleanGenerator() { - private boolean flag = false; - - @Override - public boolean generate() { - flag = !flag; - return flag; // true, false, true, false 순서로 반환 - } - }; - - Line line = Line.generateFirst(new LadderWidth(4), sequentialGenerator); - - assertThat(line.isConnectedAt(0)).isTrue(); - assertThat(line.isConnectedAt(1)).isFalse(); - assertThat(line.isConnectedAt(2)).isTrue(); + void 양쪽_모두_연결되어_있지_않으면_그대로_머문다() { + Line line = new Line(List.of(false, false)); + Position current = new Position(1); + assertThat(line.move(current)).isEqualTo(new Position(1)); } } \ No newline at end of file From c7eb9f2f1a1f470448dbb99d4175517a1e8ee03a Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:02:36 +0900 Subject: [PATCH 39/42] =?UTF-8?q?refactor:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/PositionTest.java | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java index 9312910a..872d9e28 100644 --- a/src/test/java/domain/PositionTest.java +++ b/src/test/java/domain/PositionTest.java @@ -1,28 +1,19 @@ package domain; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.*; class PositionTest { @Test - @DisplayName("왼쪽으로 이동한다.") - void moveLeft() { + void 왼쪽으로_이동하면_값이_1_감소한다() { Position position = new Position(1); assertThat(position.moveLeft()).isEqualTo(new Position(0)); } @Test - @DisplayName("오른쪽으로 이동한다.") - void moveRight() { + void 오른쪽으로_이동하면_값이_1_증가한다() { Position position = new Position(1); assertThat(position.moveRight()).isEqualTo(new Position(2)); } - - @Test - @DisplayName("동일한 값을 가지면 동등한 객체로 취급한다.") - void equals() { - assertThat(new Position(1)).isEqualTo(new Position(1)); - } } \ No newline at end of file From f4c79863317eee609effc9fd49c692a1a3675a93 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:15:59 +0900 Subject: [PATCH 40/42] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=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 | 2 - src/main/java/domain/LadderGenerator.java | 1 + src/test/java/domain/GameResultTest.java | 30 +++++++------- src/test/java/domain/LadderGeneratorTest.java | 40 +++++++++---------- 4 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 062821be..cb3559fa 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,6 +1,4 @@ package controller; - - import domain.LadderGenerator; import domain.LadderHeight; import domain.Players; diff --git a/src/main/java/domain/LadderGenerator.java b/src/main/java/domain/LadderGenerator.java index 8153cb6c..1f657841 100644 --- a/src/main/java/domain/LadderGenerator.java +++ b/src/main/java/domain/LadderGenerator.java @@ -41,4 +41,5 @@ private static boolean hasEmptyInterval(Ladder ladder, LadderWidth width) { private static boolean isEmptyInterval(Ladder ladder, int index) { return ladder.getLines().stream().noneMatch(line -> line.isConnectedAt(index)); } + } \ No newline at end of file diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java index d78c476f..e9e51a4f 100644 --- a/src/test/java/domain/GameResultTest.java +++ b/src/test/java/domain/GameResultTest.java @@ -1,30 +1,28 @@ package domain; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.util.List; -import java.util.Arrays; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; class GameResultTest { - @Test - @DisplayName("이름으로 결과를 찾을 수 있다.") - void findByName() { - Player player = new Player(new PlayerName("neo"), new Reward("꽝")); - GameResult gameResult = new GameResult(Arrays.asList(player)); + void 존재하는_이름으로_검색하면_해당_플레이어를_반환한다() { + Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); + GameResult gameResult = new GameResult(List.of(pobi)); - assertThat(gameResult.findByName("neo").getReward().getValue()).isEqualTo("꽝"); + assertThat(gameResult.findByName("pobi")).isEqualTo(pobi); } @Test - @DisplayName("존재하지 않는 이름으로 검색 시 예외가 발생한다.") - void findByName_Fail() { - GameResult gameResult = new GameResult(Arrays.asList()); + void 존재하지_않는_이름으로_검색하면_예외가_발생한다() { + Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); + GameResult gameResult = new GameResult(List.of(pobi)); - assertThatThrownBy(() -> gameResult.findByName("none")) - .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> gameResult.findByName("crong")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("존재하지 않는 사람입니다."); } + } \ No newline at end of file diff --git a/src/test/java/domain/LadderGeneratorTest.java b/src/test/java/domain/LadderGeneratorTest.java index 5689faa4..273730eb 100644 --- a/src/test/java/domain/LadderGeneratorTest.java +++ b/src/test/java/domain/LadderGeneratorTest.java @@ -1,30 +1,30 @@ package domain; +import org.assertj.core.api.AssertionsForInterfaceTypes; import org.junit.jupiter.api.Test; - -import java.util.List; - import static org.assertj.core.api.AssertionsForClassTypes.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; - -class LadderGeneratorTest { - @Test - void 존재하는_이름으로_검색하면_해당_플레이어를_반환한다() { - Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); - GameResult gameResult = new GameResult(List.of(pobi)); - assertThat(gameResult.findByName("pobi")).isEqualTo(pobi); - } +class LadderGeneratorTest { @Test - void 존재하지_않는_이름으로_검색하면_예외가_발생한다() { - Player pobi = new Player(new PlayerName("pobi"), new Reward("꽝")); - GameResult gameResult = new GameResult(List.of(pobi)); - - assertThatThrownBy(() -> gameResult.findByName("crong")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("존재하지 않는 사람입니다."); + void 빈_공간_발생_시_사다리가_재생성된다() { + BooleanGenerator customGenerator = new BooleanGenerator() { + private int callCount = 0; + + @Override + public boolean generate() { + callCount++; + // 폭이 4(간격 3)이고 높이가 2일 때, 1회 생성 시 6번(3 * 2) 호출됨 + // 첫 6번은 false를 반환하여 모든 간격이 빈 상태를 유도 + // 두 번째 시도부터 true를 반환하여 정상 생성 + return callCount > 6; + } + }; + + Ladder ladder = LadderGenerator.generate(new LadderWidth(4), new LadderHeight(2), customGenerator); + + AssertionsForInterfaceTypes.assertThat(ladder.getLines()).hasSize(2); + assertThat(ladder.getLines().get(0).isConnectedAt(0)).isTrue(); } } \ No newline at end of file From bea7a8327791583d6da5a53a14108b31bbed96b8 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:23:57 +0900 Subject: [PATCH 41/42] =?UTF-8?q?docs:=20=EB=A6=AC=EB=93=9C=EB=AF=B8=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/README.md b/src/README.md index e69de29b..f155431d 100644 --- a/src/README.md +++ b/src/README.md @@ -0,0 +1,42 @@ +# 사다리 게임 + +콘솔 환경에서 실행되는 사다리 타기 애플리케이션입니다. 사용자로부터 참여자 이름, 실행 결과, 사다리 높이를 입력받아 사다리를 무작위로 생성하고 결과를 계산합니다. + +## 기능 목록 + +* **입력 기능** + * 참여할 사람의 이름을 쉼표(,)를 기준으로 입력받는다. (이름은 최대 5자) + * 게임 실행 결과를 쉼표(,)를 기준으로 입력받는다. (결과는 최대 5자, 참여자 수와 개수가 일치해야 함) + * 최대 사다리 높이를 입력받는다. + * 결과를 확인할 대상의 이름을 입력받는다. ('all' 입력 시 전체 결과 확인) + +* **사다리 생성 로직** + * 주어진 참여자 수와 사다리 높이에 맞춰 사다리 라인을 생성한다. + * 가로 라인이 연속으로 겹치지 않도록 제어한다. + * 사다리 생성 시 사다리를 건너갈 수 없는(가로 라인이 하나도 없는) 수직 구간이 발생할 경우, 조건이 충족될 때까지 사다리를 재생성한다. + +* **결과 계산 로직** + * 각 참여자의 시작 위치에서 사다리 라인을 타고 내려가 최종 도착 위치를 연산한다. + * 최종 도착 위치에 해당하는 실행 결과를 플레이어에게 매핑한다. + +* **출력 기능** + * 생성된 사다리의 형태를 참여자 이름, 실행 결과와 함께 정렬하여 출력한다. + * 특정 플레이어의 이름을 입력하면 매핑된 실행 결과를 단건 출력한다. + * 'all'을 입력하면 모든 플레이어의 실행 결과를 전체 출력한다. + +## 패키지 구조 + +* `controller` + * `LadderController` : 사용자 입력, 도메인 로직 실행, 뷰 출력 흐름을 제어합니다. +* `domain` + * `Ladder`, `Line` : 사다리의 형태 유지 및 이동 경로 데이터 관리를 담당합니다. + * `LadderGenerator`, `LineGenerator` : 무작위 값(Boolean)을 이용한 사다리 생성 책임을 가집니다. + * `Player`, `Players`, `Reward`, `Rewards` : 참여자와 결과에 대한 값 객체 및 일급 컬렉션입니다. + * `GameResult` : 사다리 이동 결과와 보상을 매핑하여 최종 게임 결과를 보관합니다. +* `view` + * `InputView` : 콘솔을 통한 데이터 입력을 담당합니다. + * `OutputView` : 사다리 형태 및 게임 결과 출력을 담당합니다. + +## 실행 방법 + +`Application` 클래스의 `main` 메서드를 통해 애플리케이션을 실행합니다. \ No newline at end of file From f6bc97d38500491ee03e2aac7481a9cf935e36c1 Mon Sep 17 00:00:00 2001 From: mgim9316-a11y Date: Fri, 1 May 2026 13:36:11 +0900 Subject: [PATCH 42/42] =?UTF-8?q?chore:=20=EA=B3=B5=EB=B0=B1=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/main/java/Application.java | 2 +- src/main/java/controller/LadderController.java | 2 +- src/main/java/domain/Ladder.java | 2 +- src/main/java/domain/LadderGenerator.java | 2 +- src/main/java/domain/Player.java | 2 +- src/main/java/domain/PlayerName.java | 2 +- src/main/java/domain/Players.java | 2 +- src/main/java/domain/Position.java | 2 +- src/main/java/view/InputView.java | 2 +- src/test/java/domain/GameResultTest.java | 2 +- src/test/java/domain/LadderGeneratorTest.java | 2 +- src/test/java/domain/LadderTest.java | 2 +- src/test/java/domain/LineTest.java | 2 +- src/test/java/domain/PositionTest.java | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index a6525ec1..e948443b 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -9,4 +9,4 @@ public static void main(String[] args) { LadderController controller = new LadderController(inputView, outputView); controller.run(); } -} \ No newline at end of file +} diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index cb3559fa..eb8fb961 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -62,4 +62,4 @@ private boolean processTarget(String target, GameResult gameResult) { outputView.printSingleResult(gameResult.findByName(target)); return false; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index c2fad6b8..3a056719 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -32,4 +32,4 @@ private Position playOne(Position startPosition) { public List getLines() { return Collections.unmodifiableList(lines); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/LadderGenerator.java b/src/main/java/domain/LadderGenerator.java index 1f657841..6dfb4311 100644 --- a/src/main/java/domain/LadderGenerator.java +++ b/src/main/java/domain/LadderGenerator.java @@ -42,4 +42,4 @@ private static boolean isEmptyInterval(Ladder ladder, int index) { return ladder.getLines().stream().noneMatch(line -> line.isConnectedAt(index)); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java index 7b34b4fd..01bdc9e8 100644 --- a/src/main/java/domain/Player.java +++ b/src/main/java/domain/Player.java @@ -20,4 +20,4 @@ public PlayerName getName() { public Reward getReward() { return reward; } -} \ No newline at end of file +} diff --git a/src/main/java/domain/PlayerName.java b/src/main/java/domain/PlayerName.java index dc9dda86..cac2edf8 100644 --- a/src/main/java/domain/PlayerName.java +++ b/src/main/java/domain/PlayerName.java @@ -29,4 +29,4 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(value); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java index c9aa2c84..ecdcbbc1 100644 --- a/src/main/java/domain/Players.java +++ b/src/main/java/domain/Players.java @@ -21,4 +21,4 @@ public PlayerName getName(int index) { public List getNames() { return Collections.unmodifiableList(names); } -} \ No newline at end of file +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 3dd20ea4..a8c0f2ba 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -30,4 +30,4 @@ public boolean equals(Object o) { public int hashCode() { return value; } -} \ No newline at end of file +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index f55d6cc1..5eeae536 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -59,4 +59,4 @@ public String readTargetPerson() { System.out.println("\n결과를 보고 싶은 사람은?"); return SCANNER.nextLine().trim(); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/GameResultTest.java b/src/test/java/domain/GameResultTest.java index e9e51a4f..a7c1e222 100644 --- a/src/test/java/domain/GameResultTest.java +++ b/src/test/java/domain/GameResultTest.java @@ -25,4 +25,4 @@ class GameResultTest { .hasMessage("존재하지 않는 사람입니다."); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/LadderGeneratorTest.java b/src/test/java/domain/LadderGeneratorTest.java index 273730eb..e3a6e13a 100644 --- a/src/test/java/domain/LadderGeneratorTest.java +++ b/src/test/java/domain/LadderGeneratorTest.java @@ -27,4 +27,4 @@ public boolean generate() { assertThat(ladder.getLines().get(0).isConnectedAt(0)).isTrue(); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/LadderTest.java b/src/test/java/domain/LadderTest.java index 723fbb31..a1762b3d 100644 --- a/src/test/java/domain/LadderTest.java +++ b/src/test/java/domain/LadderTest.java @@ -22,4 +22,4 @@ class LadderTest { assertThat(result.getEndPosition(new Position(1))).isEqualTo(new Position(0)); assertThat(result.getEndPosition(new Position(2))).isEqualTo(new Position(1)); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/LineTest.java b/src/test/java/domain/LineTest.java index 0a17f035..51c38cd2 100644 --- a/src/test/java/domain/LineTest.java +++ b/src/test/java/domain/LineTest.java @@ -26,4 +26,4 @@ class LineTest { Position current = new Position(1); assertThat(line.move(current)).isEqualTo(new Position(1)); } -} \ No newline at end of file +} diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java index 872d9e28..717f6606 100644 --- a/src/test/java/domain/PositionTest.java +++ b/src/test/java/domain/PositionTest.java @@ -16,4 +16,4 @@ class PositionTest { Position position = new Position(1); assertThat(position.moveRight()).isEqualTo(new Position(2)); } -} \ No newline at end of file +}