From 5ff07983876b1eb8dcfe3523dc8c7154987389a8 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 16:07:24 +0900 Subject: [PATCH 01/17] =?UTF-8?q?feat:=201=EB=8B=A8=EA=B3=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20-=20Ladder,=20Line,=20Link=20?= =?UTF-8?q?=EC=82=AC=EB=8B=A4=EB=A6=AC=20=EA=B5=AC=EC=A1=B0=20=EB=8B=B4?= =?UTF-8?q?=EB=8B=B9=20=ED=81=B4=EB=9E=98=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/LadderApplication.java | 11 +++++++ .../java/controller/LadderController.java | 26 ++++++++++++++++ src/main/java/domain/Ladder.java | 25 +++++++++++++++ src/main/java/domain/Line.java | 31 +++++++++++++++++++ src/main/java/domain/Point.java | 14 +++++++++ src/main/java/view/LadderPrinter.java | 24 ++++++++++++++ 6 files changed, 131 insertions(+) create mode 100644 src/main/java/LadderApplication.java create mode 100644 src/main/java/controller/LadderController.java create mode 100644 src/main/java/domain/Ladder.java create mode 100644 src/main/java/domain/Line.java create mode 100644 src/main/java/domain/Point.java create mode 100644 src/main/java/view/LadderPrinter.java diff --git a/src/main/java/LadderApplication.java b/src/main/java/LadderApplication.java new file mode 100644 index 00000000..01295678 --- /dev/null +++ b/src/main/java/LadderApplication.java @@ -0,0 +1,11 @@ +import controller.LadderController; +import view.InputView; + +public class LadderApplication { + + public static void main(String[] args) { + InputView inputview = new InputView(); + LadderController ladderController = new LadderController(inputview); + ladderController.run(); + } +} diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java new file mode 100644 index 00000000..ede01c45 --- /dev/null +++ b/src/main/java/controller/LadderController.java @@ -0,0 +1,26 @@ +package controller; + +import domain.Height; +import domain.Ladder; +import domain.Width; +import view.InputView; +import view.LadderPrinter; + +import java.util.Random; + +public class LadderController { + + private final InputView inputview; + + public LadderController(InputView inputview) { + this.inputview = inputview; + } + + public void run() { + Width width = inputview.readWidth(); + Height height = inputview.readHeight(); + + Ladder ladder = Ladder.generate(width, height, new Random()); + new LadderPrinter().print(ladder); + } +} diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java new file mode 100644 index 00000000..aadf0efe --- /dev/null +++ b/src/main/java/domain/Ladder.java @@ -0,0 +1,25 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class Ladder { + private final List lines; + + public Ladder(List lines) { + this.lines = lines; + } + + public static Ladder generate(Width width, Height height, Random random) { + List lines = new ArrayList<>(); + for (int i = 0; i < height.value(); i++) { + lines.add(Line.generate(width.value(), random)); + } + return new Ladder(lines); + } + + public List getLines() { + return lines; + } +} diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java new file mode 100644 index 00000000..e22a689a --- /dev/null +++ b/src/main/java/domain/Line.java @@ -0,0 +1,31 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class Line { + + private final List points; + + public Line(List points) { + this.points = points; + } + + public static Line generate(int width, Random random) { + List result = new ArrayList<>(); + boolean prevHasLine = false; + + for (int i = 0; i < width - 1; i++) { + boolean hasLine = !prevHasLine && random.nextBoolean(); + result.add(new Point(hasLine)); + prevHasLine = hasLine; + } + + return new Line(result); + } + + public List getLinks() { + return points; + } +} diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java new file mode 100644 index 00000000..11e23a28 --- /dev/null +++ b/src/main/java/domain/Point.java @@ -0,0 +1,14 @@ +package domain; + +public class Point { + + private final Boolean hasRightLine; + + public Point(Boolean hasRightLine) { + this.hasRightLine = hasRightLine; + } + + public Boolean hasRightLine() { + return hasRightLine; + } +} diff --git a/src/main/java/view/LadderPrinter.java b/src/main/java/view/LadderPrinter.java new file mode 100644 index 00000000..55c4bf4b --- /dev/null +++ b/src/main/java/view/LadderPrinter.java @@ -0,0 +1,24 @@ +package view; + +import domain.Ladder; +import domain.Line; +import domain.Point; + +public class LadderPrinter { + + public void print(Ladder ladder) { + for (Line line : ladder.getLines()) { + printLine(line); + } + } + + private void printLine(Line line) { + StringBuilder stringBuilder = new StringBuilder(" "); + for (Point point : line.getLinks()) { + stringBuilder.append("|"); + stringBuilder.append(point.hasRightLine() ? "------" : " "); + } + stringBuilder.append("|"); + System.out.println(stringBuilder); + } +} From 6aa9170dc6dd5bc8c1423c1aa97e8080b0351cd7 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 16:08:27 +0900 Subject: [PATCH 02/17] =?UTF-8?q?feat:=202=EB=8B=A8=EA=B3=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20=EC=82=AC=EC=9A=A9=EC=9E=90=EB=A1=9C=EB=B6=80?= =?UTF-8?q?=ED=84=B0=20=EB=84=93=EC=9D=B4/=EB=86=92=EC=9D=B4=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20-=20Width?= =?UTF-8?q?,=20Height=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EC=9B=90?= =?UTF-8?q?=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Height.java | 10 ++++++++++ src/main/java/domain/Width.java | 10 ++++++++++ src/main/java/view/InputView.java | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/main/java/domain/Height.java create mode 100644 src/main/java/domain/Width.java create mode 100644 src/main/java/view/InputView.java diff --git a/src/main/java/domain/Height.java b/src/main/java/domain/Height.java new file mode 100644 index 00000000..c9d692d4 --- /dev/null +++ b/src/main/java/domain/Height.java @@ -0,0 +1,10 @@ +package domain; + +public record Height(int value) { + + public Height { + if (value < 1) { + throw new IllegalArgumentException("사다리의 높이는 1 이상이어야 합니다."); + } + } +} diff --git a/src/main/java/domain/Width.java b/src/main/java/domain/Width.java new file mode 100644 index 00000000..382d121d --- /dev/null +++ b/src/main/java/domain/Width.java @@ -0,0 +1,10 @@ +package domain; + +public record Width(int value) { + + public Width { + if (value < 2) { + throw new IllegalArgumentException("사다리의 넓이는 2 이상이어야 합니다."); + } + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..cb86ceed --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,21 @@ +package view; + +import domain.Height; +import domain.Width; + +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner = new Scanner(System.in); + + public Width readWidth() { + System.out.println("사다리의 넓이는 몇 개인가요?"); + return new Width(scanner.nextInt()); + } + + public Height readHeight() { + System.out.println("사다리의 높이는 몇 개인가요?"); + return new Height(scanner.nextInt()); + } +} From d330a5307f431df4b1b03b8801b75c310f4dbae2 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 16:08:27 +0900 Subject: [PATCH 03/17] =?UTF-8?q?feat:=202=EB=8B=A8=EA=B3=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20=EC=82=AC=EC=9A=A9=EC=9E=90=EB=A1=9C=EB=B6=80?= =?UTF-8?q?=ED=84=B0=20=EB=84=93=EC=9D=B4/=EB=86=92=EC=9D=B4=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20-=20Width?= =?UTF-8?q?,=20Height=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=A1=9C=20=EC=9B=90?= =?UTF-8?q?=EC=8B=9C=EA=B0=92=20=ED=8F=AC=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Height.java | 10 ++++++++++ src/main/java/domain/Width.java | 10 ++++++++++ src/main/java/view/InputView.java | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 src/main/java/domain/Height.java create mode 100644 src/main/java/domain/Width.java create mode 100644 src/main/java/view/InputView.java diff --git a/src/main/java/domain/Height.java b/src/main/java/domain/Height.java new file mode 100644 index 00000000..c9d692d4 --- /dev/null +++ b/src/main/java/domain/Height.java @@ -0,0 +1,10 @@ +package domain; + +public record Height(int value) { + + public Height { + if (value < 1) { + throw new IllegalArgumentException("사다리의 높이는 1 이상이어야 합니다."); + } + } +} diff --git a/src/main/java/domain/Width.java b/src/main/java/domain/Width.java new file mode 100644 index 00000000..382d121d --- /dev/null +++ b/src/main/java/domain/Width.java @@ -0,0 +1,10 @@ +package domain; + +public record Width(int value) { + + public Width { + if (value < 2) { + throw new IllegalArgumentException("사다리의 넓이는 2 이상이어야 합니다."); + } + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 00000000..cb86ceed --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,21 @@ +package view; + +import domain.Height; +import domain.Width; + +import java.util.Scanner; + +public class InputView { + + private final Scanner scanner = new Scanner(System.in); + + public Width readWidth() { + System.out.println("사다리의 넓이는 몇 개인가요?"); + return new Width(scanner.nextInt()); + } + + public Height readHeight() { + System.out.println("사다리의 높이는 몇 개인가요?"); + return new Height(scanner.nextInt()); + } +} From b074532646c71ce6ed06534c87cadd9438858c97 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 19:47:45 +0900 Subject: [PATCH 04/17] =?UTF-8?q?feat:=203=EB=8B=A8=EA=B3=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20=ED=83=80?= =?UTF-8?q?=EA=B8=B0=20=EA=B2=B0=EA=B3=BC=20=EC=B6=9C=EB=A0=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20-=20=EC=8B=9C=EC=9E=91=20=EC=A7=80=EC=A0=90=20->=20?= =?UTF-8?q?=EB=8F=84=EC=B0=A9=20=EC=A7=80=EC=A0=90=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/LadderApplication.java | 5 ++- .../java/controller/LadderController.java | 9 ++-- src/main/java/domain/Height.java | 4 +- src/main/java/domain/Ladder.java | 45 +++++++++++++++++-- src/main/java/domain/Line.java | 28 ++++++------ src/main/java/domain/Point.java | 24 +++++++--- src/main/java/domain/Width.java | 6 ++- src/main/java/view/LadderPrinter.java | 30 +++++++++---- src/main/java/view/OutputView.java | 17 +++++++ 9 files changed, 131 insertions(+), 37 deletions(-) create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/LadderApplication.java b/src/main/java/LadderApplication.java index 01295678..af1c3707 100644 --- a/src/main/java/LadderApplication.java +++ b/src/main/java/LadderApplication.java @@ -1,11 +1,14 @@ import controller.LadderController; import view.InputView; +import view.OutputView; public class LadderApplication { public static void main(String[] args) { InputView inputview = new InputView(); - LadderController ladderController = new LadderController(inputview); + OutputView outputview = new OutputView(); + + LadderController ladderController = new LadderController(inputview, outputview); ladderController.run(); } } diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index ede01c45..906f19aa 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -4,16 +4,18 @@ import domain.Ladder; import domain.Width; import view.InputView; -import view.LadderPrinter; +import view.OutputView; import java.util.Random; public class LadderController { private final InputView inputview; + private final OutputView outputview; - public LadderController(InputView inputview) { + public LadderController(InputView inputview, OutputView outputview) { this.inputview = inputview; + this.outputview = outputview; } public void run() { @@ -21,6 +23,7 @@ public void run() { Height height = inputview.readHeight(); Ladder ladder = Ladder.generate(width, height, new Random()); - new LadderPrinter().print(ladder); + + outputview.printLadderResult(ladder); } } diff --git a/src/main/java/domain/Height.java b/src/main/java/domain/Height.java index c9d692d4..e812b500 100644 --- a/src/main/java/domain/Height.java +++ b/src/main/java/domain/Height.java @@ -2,8 +2,10 @@ public record Height(int value) { + private static final int MIN_HEIGHT_VALUE = 1; + public Height { - if (value < 1) { + if (value < MIN_HEIGHT_VALUE) { throw new IllegalArgumentException("사다리의 높이는 1 이상이어야 합니다."); } } diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index aadf0efe..6ccb7a69 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -5,21 +5,60 @@ import java.util.Random; public class Ladder { + private final List lines; + private final Width width; + private final Height height; - public Ladder(List lines) { + public Ladder(List lines, Width width, Height height) { this.lines = lines; + this.width = width; + this.height = height; } public static Ladder generate(Width width, Height height, Random random) { List lines = new ArrayList<>(); for (int i = 0; i < height.value(); i++) { - lines.add(Line.generate(width.value(), random)); + Line line = new Line(width); + line.connect(random); + lines.add(line); + } + return new Ladder(lines, width, height); + } + + public int getFinalPosition(int startPosition) { + int currentPosition = startPosition; + for (Line line : getLines()) { + currentPosition = moveToNextPosition(currentPosition, line); } - return new Ladder(lines); + return currentPosition; + } + + private int moveToNextPosition(int currentPosition, Line line) { + List points = line.getPoints(); + + if (canMoveLeft(currentPosition, points)) { + currentPosition--; + } + if (canMoveRight(currentPosition, points)) { + currentPosition++; + } + return currentPosition; + } + + private boolean canMoveLeft(int currentPosition, List points) { + return currentPosition > 0 && points.get(currentPosition - 1).isConnectedToLeft(); + } + + private boolean canMoveRight(int currentPosition, List points) { + return currentPosition < points.size() - 1 && points.get(currentPosition).isConnectedToRight(); } public List getLines() { return lines; } + + public Width getWidth() { + return width; + } } diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java index e22a689a..9de563a7 100644 --- a/src/main/java/domain/Line.java +++ b/src/main/java/domain/Line.java @@ -8,24 +8,26 @@ public class Line { private final List points; - public Line(List points) { - this.points = points; + public Line(Width width) { + points = new ArrayList<>(); + for (int i = 0; i < width.value(); i++) { + points.add(new Point()); + } } - public static Line generate(int width, Random random) { - List result = new ArrayList<>(); - boolean prevHasLine = false; - - for (int i = 0; i < width - 1; i++) { - boolean hasLine = !prevHasLine && random.nextBoolean(); - result.add(new Point(hasLine)); - prevHasLine = hasLine; + public void connect(Random random) { + for (int i = 0; i < points.size() - 1; i++) { + if (i > 0 && points.get(i - 1).isConnectedToRight()) { + continue; + } + if (random.nextBoolean()) { + points.get(i).connectToRight(); + points.get(i + 1).connectToLeft(); + } } - - return new Line(result); } - public List getLinks() { + public List getPoints() { return points; } } diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java index 11e23a28..5b22a10a 100644 --- a/src/main/java/domain/Point.java +++ b/src/main/java/domain/Point.java @@ -2,13 +2,27 @@ public class Point { - private final Boolean hasRightLine; + private boolean connectedToRight; + private boolean connectedToLeft; - public Point(Boolean hasRightLine) { - this.hasRightLine = hasRightLine; + public Point() { + this.connectedToRight = false; + this.connectedToLeft = false; } - public Boolean hasRightLine() { - return hasRightLine; + public boolean isConnectedToRight() { + return connectedToRight; + } + + public void connectToRight() { + this.connectedToRight = true; + } + + public boolean isConnectedToLeft() { + return connectedToLeft; + } + + public void connectToLeft() { + this.connectedToLeft = true; } } diff --git a/src/main/java/domain/Width.java b/src/main/java/domain/Width.java index 382d121d..e9c80434 100644 --- a/src/main/java/domain/Width.java +++ b/src/main/java/domain/Width.java @@ -2,9 +2,11 @@ public record Width(int value) { + private static final int MIN_WIDTH_VALUE = 1; + public Width { - if (value < 2) { - throw new IllegalArgumentException("사다리의 넓이는 2 이상이어야 합니다."); + if (value < MIN_WIDTH_VALUE) { + throw new IllegalArgumentException("사다리의 넓이는 1 이상이어야 합니다."); } } } diff --git a/src/main/java/view/LadderPrinter.java b/src/main/java/view/LadderPrinter.java index 55c4bf4b..fcbadd50 100644 --- a/src/main/java/view/LadderPrinter.java +++ b/src/main/java/view/LadderPrinter.java @@ -4,21 +4,33 @@ import domain.Line; import domain.Point; +import java.util.List; + public class LadderPrinter { - public void print(Ladder ladder) { + public void printLadder(Ladder ladder) { + int width = ladder.getWidth().value(); for (Line line : ladder.getLines()) { - printLine(line); + printLine(line, width); + } + } + + private void printLine(Line line, int width) { + StringBuilder lineBuilder = new StringBuilder(); + List points = line.getPoints(); + + for (int i = 0; i < width; i++) { + lineBuilder.append("|"); + lineBuilder.append(printConnection(points, i)); } + + System.out.println(lineBuilder.toString()); } - private void printLine(Line line) { - StringBuilder stringBuilder = new StringBuilder(" "); - for (Point point : line.getLinks()) { - stringBuilder.append("|"); - stringBuilder.append(point.hasRightLine() ? "------" : " "); + private String printConnection(List points, int i) { + if (i < points.size() && points.get(i).isConnectedToRight()) { + return "-----"; } - stringBuilder.append("|"); - System.out.println(stringBuilder); + return " "; } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 00000000..e96fd557 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,17 @@ +package view; + +import domain.Ladder; + +public class OutputView { + + private final LadderPrinter ladderPrinter = new LadderPrinter(); + + public void printLadderResult(Ladder ladder) { + System.out.println("실행결과"); + + ladderPrinter.printLadder(ladder); + for (int i = 0; i < ladder.getLines().get(0).getPoints().size(); i++) { + System.out.println(i + " -> " + ladder.getFinalPosition(i)); + } + } +} From b44fff53605c72ae4730ffce1e18d2f61befeaa8 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 21:31:46 +0900 Subject: [PATCH 05/17] =?UTF-8?q?feat:=204=EB=8B=A8=EA=B3=84=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(=EC=88=98=EC=A0=95=20=EC=A4=91)=20-=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=20=EC=82=AC=EB=9E=8C,=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EA=B2=B0=EA=B3=BC=20=EC=9E=85=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20=EA=B2=B0=EA=B3=BC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5,=20=EC=B6=9C=EB=A0=A5=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 --- .../java/controller/LadderController.java | 36 ++++++++++++++----- src/main/java/domain/Ladder.java | 8 +++-- src/main/java/domain/Line.java | 2 +- src/main/java/view/InputView.java | 34 ++++++++++++++---- src/main/java/view/LadderPrinter.java | 8 +++-- src/main/java/view/OutputView.java | 35 +++++++++++++++--- 6 files changed, 98 insertions(+), 25 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 906f19aa..6e985214 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -6,24 +6,44 @@ import view.InputView; import view.OutputView; +import java.util.List; import java.util.Random; public class LadderController { - private final InputView inputview; - private final OutputView outputview; + private final InputView inputView; + private final OutputView outputView; - public LadderController(InputView inputview, OutputView outputview) { - this.inputview = inputview; - this.outputview = outputview; + public LadderController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; } public void run() { - Width width = inputview.readWidth(); - Height height = inputview.readHeight(); + final List playerNames = inputView.readPlayerNames(); + final List gameResults = inputView.readGameResults(); + Width width = new Width(playerNames.size()); + Height height = inputView.readHeight(); Ladder ladder = Ladder.generate(width, height, new Random()); - outputview.printLadderResult(ladder); + outputView.printLadder(playerNames, ladder, gameResults); + + String request = inputView.readResultRequest(); + handleResultRequest(request, playerNames, ladder, gameResults); + } + + private void handleResultRequest(String request, List names, Ladder ladder, List results) { + while (!request.equals("all")) { + int playerIndex = names.indexOf(request); + if (playerIndex != -1) { + outputView.printSingleResult(names.get(playerIndex), results.get(ladder.getFinalPosition(playerIndex))); + } else { + System.out.println("잘못된 이름입니다. 다시 입력해주세요."); + } + request = inputView.readResultRequest(); + } + // 'all' 입력될 때 + outputView.printAllResults(names, results, ladder); } } diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index 6ccb7a69..97d4f3ae 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -28,7 +28,7 @@ public static Ladder generate(Width width, Height height, Random random) { public int getFinalPosition(int startPosition) { int currentPosition = startPosition; - for (Line line : getLines()) { + for (Line line : lines) { currentPosition = moveToNextPosition(currentPosition, line); } return currentPosition; @@ -47,7 +47,7 @@ private int moveToNextPosition(int currentPosition, Line line) { } private boolean canMoveLeft(int currentPosition, List points) { - return currentPosition > 0 && points.get(currentPosition - 1).isConnectedToLeft(); + return currentPosition > 0 && points.get(currentPosition - 1).isConnectedToRight(); } private boolean canMoveRight(int currentPosition, List points) { @@ -61,4 +61,8 @@ public List getLines() { public Width getWidth() { return width; } + + public Height getHeight() { + return height; + } } diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java index 9de563a7..465dbd05 100644 --- a/src/main/java/domain/Line.java +++ b/src/main/java/domain/Line.java @@ -16,7 +16,7 @@ public Line(Width width) { } public void connect(Random random) { - for (int i = 0; i < points.size() - 1; i++) { + for (int i = 0; i < points.size() - 1; i++) { // 가로줄 겹침 방지 if (i > 0 && points.get(i - 1).isConnectedToRight()) { continue; } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index cb86ceed..6ffa309f 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -3,19 +3,41 @@ import domain.Height; import domain.Width; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Scanner; public class InputView { - private final Scanner scanner = new Scanner(System.in); + private static final Scanner scanner = new Scanner(System.in); - public Width readWidth() { - System.out.println("사다리의 넓이는 몇 개인가요?"); - return new Width(scanner.nextInt()); + public List readPlayerNames() { + System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요): "); + + String userInput = scanner.nextLine(); + return new ArrayList<>(Arrays.asList(userInput.split(","))); + } + + public List readGameResults() { + System.out.println(); + System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요): "); + + String userInput = scanner.nextLine(); + return new ArrayList<>(Arrays.asList(userInput.split(","))); } public Height readHeight() { - System.out.println("사다리의 높이는 몇 개인가요?"); - return new Height(scanner.nextInt()); + System.out.println(); + System.out.println("최대 사다리 높이는 몇 개인가요?"); + int height = scanner.nextInt(); + scanner.nextLine(); + return new Height(height); + } + + public String readResultRequest() { + System.out.println(); + System.out.println("결과를 보고 싶은 사람은?"); + return scanner.nextLine().trim(); } } diff --git a/src/main/java/view/LadderPrinter.java b/src/main/java/view/LadderPrinter.java index fcbadd50..6d2393f6 100644 --- a/src/main/java/view/LadderPrinter.java +++ b/src/main/java/view/LadderPrinter.java @@ -8,6 +8,8 @@ public class LadderPrinter { + private static final int CONNECTION_WIDTH = 5; + public void printLadder(Ladder ladder) { int width = ladder.getWidth().value(); for (Line line : ladder.getLines()) { @@ -24,13 +26,13 @@ private void printLine(Line line, int width) { lineBuilder.append(printConnection(points, i)); } - System.out.println(lineBuilder.toString()); + System.out.println(lineBuilder); } private String printConnection(List points, int i) { if (i < points.size() && points.get(i).isConnectedToRight()) { - return "-----"; + return "-".repeat(CONNECTION_WIDTH); } - return " "; + return " ".repeat(CONNECTION_WIDTH); } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index e96fd557..6af9372f 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -2,16 +2,41 @@ import domain.Ladder; +import java.util.List; + public class OutputView { private final LadderPrinter ladderPrinter = new LadderPrinter(); - public void printLadderResult(Ladder ladder) { - System.out.println("실행결과"); - + public void printLadder(List playerNames, Ladder ladder, List results) { + System.out.println(); + System.out.println("사다리 결과"); + System.out.println(); + printNames(playerNames); ladderPrinter.printLadder(ladder); - for (int i = 0; i < ladder.getLines().get(0).getPoints().size(); i++) { - System.out.println(i + " -> " + ladder.getFinalPosition(i)); + printNames(results); + } + + private void printNames(List names) { + for (String name : names) { + System.out.print(String.format("%-6s", name)); + } + System.out.println(); + } + + public void printSingleResult(String name, String result) { + System.out.println(); + System.out.println("실행 결과"); + System.out.println(result); + } + + public void printAllResults(List playerNames, List results, Ladder ladder) { + System.out.println(); + System.out.println("실행 결과"); + for (int i = 0; i < playerNames.size(); i++) { + int finalIndex = ladder.getFinalPosition(i); + String result = results.get(finalIndex); + System.out.println(playerNames.get(i) + " : " + result); } } } From e159f80cecc0f16274b85cd5a45e6052d029b56d Mon Sep 17 00:00:00 2001 From: Jiwoo Kim <163404760+Ji-Woo-Kim@users.noreply.github.com> Date: Fri, 2 May 2025 22:25:50 +0900 Subject: [PATCH 06/17] Create README.md --- README.md | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..598ec25d --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# 🪜 사다리 타기 게임 +참가자의 이름과 원하는 결과를 입력하면 랜덤한 사다리를 생성하고, +각 사람이 어떤 결과에 도착하는지 확인할 수 있는 **사다리 게임**입니다. + +--- + +## 🕹️ 사용 방법 + +### 1. 참여자 이름 입력 +- 최대 5글자까지 입력 가능합니다. +- 이름은 쉼표 `,`로 구분해서 입력해야 합니다. +- 입력한 순서대로 사다리 시작 위치가 지정됩니다. + +### 2. 실행 결과 입력 +- 참여자 수와 같은 개수의 결과 입력해주세요. +- 순서는 이름과 일치해야 합니다. +- 입력한 순서대로 실행 결과 위치가 지정됩니다. + +### 3. 사다리 높이 입력 +- 사다리의 세로 줄 수를 숫자로 입력해주세요. + +### 4. 생성된 사다리 확인 +- 각 참여자의 시작 지점, 실행 결과 위치가 출력됩니다. + +### 5. 결과 확인 + +- 특정 이름을 입력하면 해당 사람의 결과가 출력됩니다. +- `"all"`을 입력하면 전체 결과를 한 번에 확인할 수 있습니다. +- `"all"`을 입력하면 모든 참여자의 최종 결과를 출력하고 프로그램이 종료됩니다. + +--- +## 🖥️ 실행 예시 +``` +참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요) +neo,brown,brie,tommy + +실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요) +꽝,5000,꽝,3000 + +최대 사다리 높이는 몇 개인가요? +5 + +사다리 결과 + + neo brown brie tommy + |-----| |-----| + | |-----| | + |-----| | | + | |-----| | + |-----| |-----| + 꽝 5000 꽝 3000 + +결과를 보고 싶은 사람은? +neo + +실행 결과 +꽝 + +결과를 보고 싶은 사람은? +all + +실행 결과 +neo : 꽝 +brown : 3000 +brie : 꽝 +tommy : 5000 +``` From 130ed3cb43e098e9f3a7013a1e9942471fb137a5 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 23:00:27 +0900 Subject: [PATCH 07/17] =?UTF-8?q?refactor:=205=EB=8B=A8=EA=B3=84=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20-=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=B6=84=EB=A6=AC=20-=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EA=B0=92=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81,=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 46 +++++++++++++++---- src/main/java/domain/Ladder.java | 10 +--- src/main/java/view/InputView.java | 6 ++- src/main/java/view/OutputView.java | 3 +- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 6e985214..462b6d87 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -20,25 +20,45 @@ public LadderController(InputView inputView, OutputView outputView) { } public void run() { - final List playerNames = inputView.readPlayerNames(); - final List gameResults = inputView.readGameResults(); + List playerNames = readValidatedPlayerNames(); + List gameResults = readValidatedGameResults(playerNames.size()); + Width width = new Width(playerNames.size()); Height height = inputView.readHeight(); - Ladder ladder = Ladder.generate(width, height, new Random()); - outputView.printLadder(playerNames, ladder, gameResults); String request = inputView.readResultRequest(); handleResultRequest(request, playerNames, ladder, gameResults); } + private List readValidatedPlayerNames() { + List names = inputView.readPlayerNames(); + for (String name : names) { + if (name.isEmpty() || name.length() > 5) { + throw new IllegalArgumentException("참여자 이름은 1자 이상 5자 이하여야 합니다: " + name); + } + } + return names; + } + + private List readValidatedGameResults(int expectedSize) { + List results = inputView.readGameResults(); + if (results.size() != expectedSize) { + throw new IllegalArgumentException("이름과 결과의 개수가 일치하지 않습니다."); + } + return results; + } + private void handleResultRequest(String request, List names, Ladder ladder, List results) { - while (!request.equals("all")) { - int playerIndex = names.indexOf(request); - if (playerIndex != -1) { - outputView.printSingleResult(names.get(playerIndex), results.get(ladder.getFinalPosition(playerIndex))); - } else { + while (!request.equals("all")) {// 입력이 'all'이 아닐 때 + try { + int playerIndex = getValidPlayerIndex(request, names); + outputView.printSingleResult( + names.get(playerIndex), + results.get(ladder.getFinalPosition(playerIndex)) + ); + } catch (IllegalArgumentException e) { System.out.println("잘못된 이름입니다. 다시 입력해주세요."); } request = inputView.readResultRequest(); @@ -46,4 +66,12 @@ private void handleResultRequest(String request, List names, Ladder ladd // 'all' 입력될 때 outputView.printAllResults(names, results, ladder); } + + private int getValidPlayerIndex(String name, List names) { + int index = names.indexOf(name); + if (index == -1) { + throw new IllegalArgumentException("잘못된 이름입니다: " + name); + } + return index; + } } diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index 97d4f3ae..99e5c162 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -8,12 +8,10 @@ public class Ladder { private final List lines; private final Width width; - private final Height height; - public Ladder(List lines, Width width, Height height) { + public Ladder(List lines, Width width) { this.lines = lines; this.width = width; - this.height = height; } public static Ladder generate(Width width, Height height, Random random) { @@ -23,7 +21,7 @@ public static Ladder generate(Width width, Height height, Random random) { line.connect(random); lines.add(line); } - return new Ladder(lines, width, height); + return new Ladder(lines, width); } public int getFinalPosition(int startPosition) { @@ -61,8 +59,4 @@ public List getLines() { public Width getWidth() { return width; } - - public Height getHeight() { - return height; - } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 6ffa309f..53b6306e 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.List; import java.util.Scanner; +import java.util.stream.Collectors; public class InputView { @@ -16,7 +17,10 @@ public List readPlayerNames() { System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요): "); String userInput = scanner.nextLine(); - return new ArrayList<>(Arrays.asList(userInput.split(","))); + return Arrays.stream(userInput.split(",")) + .map(String::trim) + .filter(name -> !name.isEmpty()) + .collect(Collectors.toList()); } public List readGameResults() { diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 6af9372f..9b2433b4 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -6,6 +6,7 @@ public class OutputView { + private static final int SPACE_WIDTH = 6; private final LadderPrinter ladderPrinter = new LadderPrinter(); public void printLadder(List playerNames, Ladder ladder, List results) { @@ -19,7 +20,7 @@ public void printLadder(List playerNames, Ladder ladder, List re private void printNames(List names) { for (String name : names) { - System.out.print(String.format("%-6s", name)); + System.out.print(String.format("%-" + SPACE_WIDTH + "s", name)); } System.out.println(); } From b295f2a21edad66a45b164071f4c1a8f7f491feb Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Fri, 2 May 2025 23:38:22 +0900 Subject: [PATCH 08/17] =?UTF-8?q?test:=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1,=20=EA=B2=B0=EA=B3=BC=20=EC=82=B0=EC=B6=9C?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= 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/Point.java | 4 --- src/test/java/LadderTest.java | 62 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 src/test/java/LadderTest.java diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java index 99e5c162..c5e6ad70 100644 --- a/src/main/java/domain/Ladder.java +++ b/src/main/java/domain/Ladder.java @@ -36,10 +36,10 @@ private int moveToNextPosition(int currentPosition, Line line) { List points = line.getPoints(); if (canMoveLeft(currentPosition, points)) { - currentPosition--; + return currentPosition - 1; } if (canMoveRight(currentPosition, points)) { - currentPosition++; + return currentPosition + 1; } return currentPosition; } diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java index 5b22a10a..5ef4dc9f 100644 --- a/src/main/java/domain/Point.java +++ b/src/main/java/domain/Point.java @@ -18,10 +18,6 @@ public void connectToRight() { this.connectedToRight = true; } - public boolean isConnectedToLeft() { - return connectedToLeft; - } - public void connectToLeft() { this.connectedToLeft = true; } diff --git a/src/test/java/LadderTest.java b/src/test/java/LadderTest.java new file mode 100644 index 00000000..0608b228 --- /dev/null +++ b/src/test/java/LadderTest.java @@ -0,0 +1,62 @@ +import domain.*; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; + +public class LadderTest { + + @Test + @DisplayName("지정한 넓이와 높이에 맞게 사다리가 올바르게 생성되어야 함.") + void ladder_size_test() { + Width width = new Width(4); + Height height = new Height(5); + Ladder ladder = Ladder.generate(width, height, new Random(20)); + + assertEquals(5, ladder.getLines().size()); + for (Line line : ladder.getLines()) { + assertEquals(4, line.getPoints().size()); + } + } + + @Test + @DisplayName("사다리 타기가 올바르게 되어야 함.") + void ladder_moving_test() { + Width width = new Width(3); // 너비 : 3 (=3명의 참가자) + Height height = new Height(1); // 높이 : 1 + Ladder ladder = Ladder.generate(width, height, new Random() { + @Override + public boolean nextBoolean() { + return true; // 너비 인덱스 기준 0-1만 연결되어 있는 사다리 생성 + } + }); + + assertEquals(1, ladder.getFinalPosition(0)); + assertEquals(0, ladder.getFinalPosition(1)); + assertEquals(2, ladder.getFinalPosition(2)); + } + + @Test + @DisplayName("사다리 생성 시, 가로줄이 중첩되지 않게 생성되어야 함.") + void ladder_generate_overlap_test() { + Line line = new Line(new Width(5)); + line.connect(new Random(20)); + + List points = line.getPoints(); + for (int i = 0; i < points.size() - 2; i++) { + if (points.get(i).isConnectedToRight()) { + assertFalse(points.get(i + 1).isConnectedToRight()); + } + } + } + + @Test + @DisplayName("입력받은 사다리 높이 값은 1이상이어야 함.") + void height_throws_exception_test() { + assertThrows(IllegalArgumentException.class, () -> new Height(0)); + assertThrows(IllegalArgumentException.class, () -> new Height(-1)); + } +} From e7080751ea3ed1b3c78e7364eeb73a42263ea071 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:35:08 +0900 Subject: [PATCH 09/17] =?UTF-8?q?feat:=20=EC=9E=85=EB=A0=A5=20=EA=B0=92?= =?UTF-8?q?=EC=9D=B8=20=EC=B0=B8=EA=B0=80=EC=9E=90,=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=20=EA=B0=9D=EC=B2=B4=20&=20=EC=9D=BC?= =?UTF-8?q?=EA=B8=89=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/Player.java | 38 +++++++++++++++++++++++++++ src/main/java/domain/Players.java | 35 ++++++++++++++++++++++++ src/main/java/domain/ResultItem.java | 21 +++++++++++++++ src/main/java/domain/ResultItems.java | 33 +++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 src/main/java/domain/Player.java create mode 100644 src/main/java/domain/Players.java create mode 100644 src/main/java/domain/ResultItem.java create mode 100644 src/main/java/domain/ResultItems.java diff --git a/src/main/java/domain/Player.java b/src/main/java/domain/Player.java new file mode 100644 index 00000000..02c1e824 --- /dev/null +++ b/src/main/java/domain/Player.java @@ -0,0 +1,38 @@ +package domain; + +import java.util.Objects; + +public class Player { + + private static final int MAX_NAME_LENGTH = 5; + + private final String name; + + public Player(String name) { + validateInput(name); + this.name = name; + } + + private void validateInput(String name) { + if (name.isEmpty() || name.length() > MAX_NAME_LENGTH) { + throw new IllegalArgumentException("참여할 사람의 이름은 1자 이상 " + MAX_NAME_LENGTH + "자 이하여야 합니다."); + } + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Player player = (Player) o; + return Objects.equals(name, player.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +} diff --git a/src/main/java/domain/Players.java b/src/main/java/domain/Players.java new file mode 100644 index 00000000..7bdd1c74 --- /dev/null +++ b/src/main/java/domain/Players.java @@ -0,0 +1,35 @@ +package domain; + +import java.util.List; + +public class Players { + + private static final int MIN_PLAYERS_COUNT = 1; + + private final List players; + + public Players(List players) { + validateCount(players); + this.players = players; + } + + private void validateCount(List players) { + if (players.isEmpty()) { + throw new IllegalArgumentException("참여 인원은 최소 " + MIN_PLAYERS_COUNT + "명 이상이어야 합니다."); + } + } + + public int count() { + return players.size(); + } + + public List extractPlayers() { + return List.copyOf(players); + } + + public List extractNames() { + return players.stream() + .map(Player::getName) + .toList(); + } +} diff --git a/src/main/java/domain/ResultItem.java b/src/main/java/domain/ResultItem.java new file mode 100644 index 00000000..a52e41a9 --- /dev/null +++ b/src/main/java/domain/ResultItem.java @@ -0,0 +1,21 @@ +package domain; + +public class ResultItem { + + private final String item; + + public ResultItem(String item) { + validate(item); + this.item = item; + } + + private void validate(String item) { + if (item.isEmpty()) { + throw new IllegalArgumentException("실행 결과 값은 필수 입력 값입니다."); + } + } + + public String getItem() { + return item; + } +} diff --git a/src/main/java/domain/ResultItems.java b/src/main/java/domain/ResultItems.java new file mode 100644 index 00000000..aa4ce82a --- /dev/null +++ b/src/main/java/domain/ResultItems.java @@ -0,0 +1,33 @@ +package domain; + +import java.util.List; + +public class ResultItems { + + private final List items; + + public ResultItems(List items, int expectedSize) { + validateCount(items, expectedSize); + this.items = items; + } + + private void validateCount(List items, int expectedSize) { + if (items.size() != expectedSize) { + throw new IllegalArgumentException("참여자의 수와 실행 결과 개수가 일치하지 않습니다."); + } + } + + public int count() { + return items.size(); + } + + public List extractItems() { + return List.copyOf(items); + } + + public List extractNames() { + return items.stream() + .map(ResultItem::getItem) + .toList(); + } +} From 37f13b457bd0e5262af7a8353cd662301d47e5ee Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:35:35 +0900 Subject: [PATCH 10/17] =?UTF-8?q?refactor:=20Enum=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Point.java | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java index 5ef4dc9f..43e0fc4f 100644 --- a/src/main/java/domain/Point.java +++ b/src/main/java/domain/Point.java @@ -1,24 +1,33 @@ package domain; -public class Point { +public enum Point { - private boolean connectedToRight; - private boolean connectedToLeft; + // 왼쪽으로 연결됨 + CONNECTED_LEFT(-1), + // 오른쪽으로 연결됨 + CONNECTED_RIGHT(1), + // 양쪽 아무 곳에도 연결되지 않음 + NOT_CONNECTED(0); - public Point() { - this.connectedToRight = false; - this.connectedToLeft = false; + private final int offset; + + Point(int offset) { + this.offset = offset; + } + + public int moveFrom(int currentPosition) { + return currentPosition + offset; } - public boolean isConnectedToRight() { - return connectedToRight; + public boolean isConnectedLeft() { + return this == CONNECTED_LEFT; } - public void connectToRight() { - this.connectedToRight = true; + public boolean isConnectedRight() { + return this == CONNECTED_RIGHT; } - public void connectToLeft() { - this.connectedToLeft = true; + public boolean isNotConnected() { + return this == NOT_CONNECTED; } } From 8c728c72f174cb1d484092af26f5eff007106e3f Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:36:19 +0900 Subject: [PATCH 11/17] =?UTF-8?q?refactor:=20=EB=84=A4=EC=9D=B4=EB=B0=8D?= =?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/{Height.java => LadderHeight.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/main/java/domain/{Height.java => LadderHeight.java} (77%) diff --git a/src/main/java/domain/Height.java b/src/main/java/domain/LadderHeight.java similarity index 77% rename from src/main/java/domain/Height.java rename to src/main/java/domain/LadderHeight.java index e812b500..d1b33fdc 100644 --- a/src/main/java/domain/Height.java +++ b/src/main/java/domain/LadderHeight.java @@ -1,10 +1,10 @@ package domain; -public record Height(int value) { +public record LadderHeight(int value) { private static final int MIN_HEIGHT_VALUE = 1; - public Height { + public LadderHeight { if (value < MIN_HEIGHT_VALUE) { throw new IllegalArgumentException("사다리의 높이는 1 이상이어야 합니다."); } From 8f398dfd5d40288d00acb2d5c16e9b14d6b18285 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:37:22 +0900 Subject: [PATCH 12/17] =?UTF-8?q?feat:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20Poi?= =?UTF-8?q?nt=20=EB=A1=9C=EC=A7=81=20=EC=A0=81=EC=9A=A9,=20=EC=9D=BC?= =?UTF-8?q?=EA=B8=89=EC=BB=AC=EB=A0=89=EC=85=98=EC=9C=BC=EB=A1=9C=20Line?= =?UTF-8?q?=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/LadderLine.java | 63 +++++++++++++++++++++++++++ src/main/java/domain/LadderLines.java | 40 +++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/main/java/domain/LadderLine.java create mode 100644 src/main/java/domain/LadderLines.java diff --git a/src/main/java/domain/LadderLine.java b/src/main/java/domain/LadderLine.java new file mode 100644 index 00000000..5824cc66 --- /dev/null +++ b/src/main/java/domain/LadderLine.java @@ -0,0 +1,63 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class LadderLine { + + private final List points; + + public LadderLine(int width, Random random) { + points = new ArrayList<>(); + Point previous = Point.NOT_CONNECTED; + + for (int i = 0; i < width; i++) { + Point nextPoint = createNextPoint(previous, random); + + // 마지막 포인트 연결 방지 + if (i == width - 1) { + nextPoint = Point.NOT_CONNECTED; + } + + points.add(nextPoint); + previous = nextPoint; + } + } + + public LadderLine(List points) { + this.points = List.copyOf(points); + } + + public List getPoints() { + return List.copyOf(points); + } + + private Point createNextPoint(Point previous, Random random) { + // 이전 포인트가 오른쪽으로 연결되어 있으면, 현재 포인트는 왼쪽과 연결되어 있다는 것과 같음 + if (previous.isConnectedRight()) { + return Point.CONNECTED_LEFT; + } + // 랜덤하게 오른쪽 연결 여부 결정 + if (random.nextBoolean()) { + return Point.CONNECTED_RIGHT; + } + return Point.NOT_CONNECTED; + } + + public int move(int currentPosition) { + // 오른쪽으로 가려할 때, 맨 끝부분에서는 더 이동하지 않도록 + if (currentPosition < 0 || currentPosition >= points.size()) { + return currentPosition; + } + + Point currentPoint = points.get(currentPosition); + int nextPosition = currentPoint.moveFrom(currentPosition); + // 다음 위치가 범위를 넘어서면 현재 위치 유지 + if (nextPosition >= 0 && nextPosition < points.size()) { + return nextPosition; + } + + return nextPosition; + } +} diff --git a/src/main/java/domain/LadderLines.java b/src/main/java/domain/LadderLines.java new file mode 100644 index 00000000..90f69b5e --- /dev/null +++ b/src/main/java/domain/LadderLines.java @@ -0,0 +1,40 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class LadderLines { + + private final List lines; + + public LadderLines(List lines) { + this.lines = List.copyOf(lines); + } + + public static LadderLines generate(int width, LadderHeight height, Random random) { + List lines = new ArrayList<>(); + for (int i = 0; i < height.value(); i++) { + lines.add(new LadderLine(width, random)); + } + + return new LadderLines(lines); + } + + public int getFinalPosition(int startPosition) { + int currentPosition = startPosition; + + for (LadderLine line : lines) { + int nextPosition = line.move(currentPosition); + if (nextPosition != currentPosition) { + currentPosition = nextPosition; + } + } + + return currentPosition; + } + + public List getLines() { + return List.copyOf(lines); + } +} From 72751c34b5cbc0b89c48a20b05f0ddb0ed389dda Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:38:50 +0900 Subject: [PATCH 13/17] =?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=20=EA=B4=80=EB=A6=AC,?= =?UTF-8?q?=20=EA=B2=B0=EA=B3=BC=20=EB=A7=A4=ED=95=91=20=EB=8B=B4=EB=8B=B9?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B0=9D=EC=B2=B4=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/LadderGameResult.java | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/main/java/domain/LadderGameResult.java diff --git a/src/main/java/domain/LadderGameResult.java b/src/main/java/domain/LadderGameResult.java new file mode 100644 index 00000000..93d01124 --- /dev/null +++ b/src/main/java/domain/LadderGameResult.java @@ -0,0 +1,44 @@ +package domain; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class LadderGameResult { + + private final Map results = new LinkedHashMap<>(); + + public LadderGameResult(Players players, ResultItems resultItems, LadderGame ladder) { + List playerList = players.extractPlayers(); + List resultList = resultItems.extractItems(); + + for (int i = 0; i < playerList.size(); i++) { + int finalPosition = ladder.getFinalPosition(i); + + if (finalPosition >= resultItems.count()) { + throw new IllegalArgumentException("최종 위치가 결과의 범위를 벗어났습니다."); + } + + results.put(playerList.get(i), resultList.get(finalPosition)); + } + } + + public ResultItem getSingleResultFor(Player player) { + if (!results.containsKey(player)) { + throw new IllegalArgumentException("존재하지 않는 플레이어입니다: " + player.getName()); + } + return results.get(player); + } + + public Map getAllResults() { + return results.entrySet() + .stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (e1, e2) -> e1, + LinkedHashMap::new + )); + } +} From 495dccc6a574f045b3d483ca0e439ec3657bdfa9 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:39:25 +0900 Subject: [PATCH 14/17] =?UTF-8?q?refactor:=20=EB=B3=80=EA=B2=BD=EB=90=9C?= =?UTF-8?q?=20domain=20=EB=B0=98=EC=98=81=ED=95=98=EC=97=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 77 +++++++++---------- src/main/java/domain/LadderGame.java | 25 ++++++ 2 files changed, 62 insertions(+), 40 deletions(-) create mode 100644 src/main/java/domain/LadderGame.java diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 462b6d87..38e0e52a 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -1,13 +1,13 @@ package controller; -import domain.Height; -import domain.Ladder; -import domain.Width; +import domain.*; import view.InputView; import view.OutputView; import java.util.List; +import java.util.Map; import java.util.Random; +import java.util.stream.Collectors; public class LadderController { @@ -20,58 +20,55 @@ public LadderController(InputView inputView, OutputView outputView) { } public void run() { - List playerNames = readValidatedPlayerNames(); - List gameResults = readValidatedGameResults(playerNames.size()); + Players players = readPlayers(); + ResultItems resultItems = readResultItems(players.count()); - Width width = new Width(playerNames.size()); - Height height = inputView.readHeight(); - Ladder ladder = Ladder.generate(width, height, new Random()); - outputView.printLadder(playerNames, ladder, gameResults); + LadderHeight height = inputView.readHeight(); + LadderGame ladderGame = LadderGame.start(players.count(), height, new Random()); - String request = inputView.readResultRequest(); - handleResultRequest(request, playerNames, ladder, gameResults); + List playerNames = players.extractNames(); + List resultItemNames = resultItems.extractNames(); + outputView.printLadder(playerNames, ladderGame, resultItemNames); + + String requestName = inputView.readResultRequest(); + handleResultRequest(requestName, players, ladderGame, resultItems); } - private List readValidatedPlayerNames() { + private Players readPlayers() { List names = inputView.readPlayerNames(); - for (String name : names) { - if (name.isEmpty() || name.length() > 5) { - throw new IllegalArgumentException("참여자 이름은 1자 이상 5자 이하여야 합니다: " + name); - } - } - return names; + List players = names.stream() + .map(Player::new) + .toList(); + return new Players(players); } - private List readValidatedGameResults(int expectedSize) { - List results = inputView.readGameResults(); - if (results.size() != expectedSize) { - throw new IllegalArgumentException("이름과 결과의 개수가 일치하지 않습니다."); - } - return results; + private ResultItems readResultItems(int expectedSize) { + List results = inputView.readResultItems(); + List resultItems = results.stream() + .map(ResultItem::new) + .toList(); + return new ResultItems(resultItems, expectedSize); } - private void handleResultRequest(String request, List names, Ladder ladder, List results) { - while (!request.equals("all")) {// 입력이 'all'이 아닐 때 + private void handleResultRequest(String request, Players players, LadderGame ladder, ResultItems resultItems) { + LadderGameResult gameResult = new LadderGameResult(players, resultItems, ladder); + + while (!request.equals("all")) { try { - int playerIndex = getValidPlayerIndex(request, names); - outputView.printSingleResult( - names.get(playerIndex), - results.get(ladder.getFinalPosition(playerIndex)) - ); + Player player = new Player(request); + outputView.printSingleResult(player.getName(), gameResult.getSingleResultFor(player).getItem()); } catch (IllegalArgumentException e) { System.out.println("잘못된 이름입니다. 다시 입력해주세요."); } request = inputView.readResultRequest(); } - // 'all' 입력될 때 - outputView.printAllResults(names, results, ladder); - } - private int getValidPlayerIndex(String name, List names) { - int index = names.indexOf(name); - if (index == -1) { - throw new IllegalArgumentException("잘못된 이름입니다: " + name); - } - return index; + Map resultMap = gameResult.getAllResults().entrySet().stream() + .collect(Collectors.toMap( + entry -> entry.getKey().getName(), + entry -> entry.getValue().getItem() + )); + + outputView.printAllResults(resultMap); } } diff --git a/src/main/java/domain/LadderGame.java b/src/main/java/domain/LadderGame.java new file mode 100644 index 00000000..d3fe6066 --- /dev/null +++ b/src/main/java/domain/LadderGame.java @@ -0,0 +1,25 @@ +package domain; + +import java.util.List; +import java.util.Random; + +public class LadderGame { + + private final LadderLines ladderLines; + + public LadderGame(LadderLines ladderLines) { + this.ladderLines = ladderLines; + } + + public static LadderGame start(int width, LadderHeight height, Random random) { + return new LadderGame(LadderLines.generate(width, height, random)); + } + + public int getFinalPosition(int startPosition) { + return ladderLines.getFinalPosition(startPosition); + } + + public List getLadderStructure() { + return ladderLines.getLines(); + } +} From b1c8c29f3a03288c97959bbbc301f028762ce1f3 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:39:43 +0900 Subject: [PATCH 15/17] =?UTF-8?q?refactor:=20=EB=B3=80=EA=B2=BD=EB=90=9C?= =?UTF-8?q?=20domain=20=EB=B0=98=EC=98=81=ED=95=98=EC=97=AC=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=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/view/InputView.java | 9 +++--- src/main/java/view/LadderPrinter.java | 40 ++++++++++++--------------- src/main/java/view/OutputView.java | 26 +++++++++-------- 3 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index 53b6306e..d1b47db0 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,7 +1,6 @@ package view; -import domain.Height; -import domain.Width; +import domain.LadderHeight; import java.util.ArrayList; import java.util.Arrays; @@ -23,7 +22,7 @@ public List readPlayerNames() { .collect(Collectors.toList()); } - public List readGameResults() { + public List readResultItems() { System.out.println(); System.out.println("실행 결과를 입력하세요. (결과는 쉼표(,)로 구분하세요): "); @@ -31,12 +30,12 @@ public List readGameResults() { return new ArrayList<>(Arrays.asList(userInput.split(","))); } - public Height readHeight() { + public LadderHeight readHeight() { System.out.println(); System.out.println("최대 사다리 높이는 몇 개인가요?"); int height = scanner.nextInt(); scanner.nextLine(); - return new Height(height); + return new LadderHeight(height); } public String readResultRequest() { diff --git a/src/main/java/view/LadderPrinter.java b/src/main/java/view/LadderPrinter.java index 6d2393f6..5d82ca86 100644 --- a/src/main/java/view/LadderPrinter.java +++ b/src/main/java/view/LadderPrinter.java @@ -1,38 +1,32 @@ package view; -import domain.Ladder; -import domain.Line; -import domain.Point; - -import java.util.List; +import domain.LadderGame; +import domain.LadderLine; public class LadderPrinter { + private static final String POINT = "|"; + private static final String CONNECT_LINE = "-"; + private static final String NO_CONNECT = " "; private static final int CONNECTION_WIDTH = 5; - public void printLadder(Ladder ladder) { - int width = ladder.getWidth().value(); - for (Line line : ladder.getLines()) { - printLine(line, width); - } + public static void printLadder(LadderGame ladderGame) { + ladderGame.getLadderStructure().forEach(LadderPrinter::printLine); } - private void printLine(Line line, int width) { + private static void printLine(LadderLine line) { StringBuilder lineBuilder = new StringBuilder(); - List points = line.getPoints(); - for (int i = 0; i < width; i++) { - lineBuilder.append("|"); - lineBuilder.append(printConnection(points, i)); - } + lineBuilder.append(POINT); // 첫 번째 세로줄 + line.getPoints().forEach(point -> { + if (point.isConnectedRight()) { + lineBuilder.append(CONNECT_LINE.repeat(CONNECTION_WIDTH)); + } else { + lineBuilder.append(NO_CONNECT.repeat(CONNECTION_WIDTH)); + } + lineBuilder.append(POINT); // 다음 세로줄 + }); System.out.println(lineBuilder); } - - private String printConnection(List points, int i) { - if (i < points.size() && points.get(i).isConnectedToRight()) { - return "-".repeat(CONNECTION_WIDTH); - } - return " ".repeat(CONNECTION_WIDTH); - } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 9b2433b4..ffb1734e 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,21 +1,24 @@ package view; -import domain.Ladder; +import domain.LadderGame; +import domain.LadderLine; import java.util.List; +import java.util.Map; public class OutputView { private static final int SPACE_WIDTH = 6; private final LadderPrinter ladderPrinter = new LadderPrinter(); - public void printLadder(List playerNames, Ladder ladder, List results) { + public void printLadder(List playerNames, LadderGame ladderGame, List resultItems) { System.out.println(); System.out.println("사다리 결과"); System.out.println(); + printNames(playerNames); - ladderPrinter.printLadder(ladder); - printNames(results); + ladderPrinter.printLadder(ladderGame); + printNames(resultItems); } private void printNames(List names) { @@ -25,19 +28,18 @@ private void printNames(List names) { System.out.println(); } - public void printSingleResult(String name, String result) { + public void printSingleResult(String player, String resultItem) { System.out.println(); System.out.println("실행 결과"); - System.out.println(result); + System.out.println(player + " : " + resultItem); } - public void printAllResults(List playerNames, List results, Ladder ladder) { + public void printAllResults(Map ladderGameResult) { System.out.println(); System.out.println("실행 결과"); - for (int i = 0; i < playerNames.size(); i++) { - int finalIndex = ladder.getFinalPosition(i); - String result = results.get(finalIndex); - System.out.println(playerNames.get(i) + " : " + result); - } + + ladderGameResult.forEach((player, result) -> + System.out.println(player + " : " + result) + ); } } From 4c286125ccc6422d698acdb0b3d375e70ca51792 Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 07:40:09 +0900 Subject: [PATCH 16/17] =?UTF-8?q?test:=20=EB=B3=80=EA=B2=BD=EB=90=9C=20dom?= =?UTF-8?q?ain=EC=97=90=20=EB=94=B0=EB=A5=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Ladder.java | 62 --------------- src/main/java/domain/Line.java | 33 -------- src/main/java/domain/Width.java | 12 --- src/test/java/LadderTest.java | 62 --------------- src/test/java/domain/LadderLineTest.java | 96 +++++++++++++++++++++++ src/test/java/domain/LadderLinesTest.java | 85 ++++++++++++++++++++ src/test/java/domain/PlayerTest.java | 43 ++++++++++ src/test/java/domain/PlayersTest.java | 54 +++++++++++++ src/test/java/domain/PointTest.java | 66 ++++++++++++++++ src/test/java/domain/ResultItemTest.java | 25 ++++++ src/test/java/domain/ResultItemsTest.java | 56 +++++++++++++ 11 files changed, 425 insertions(+), 169 deletions(-) delete mode 100644 src/main/java/domain/Ladder.java delete mode 100644 src/main/java/domain/Line.java delete mode 100644 src/main/java/domain/Width.java delete mode 100644 src/test/java/LadderTest.java create mode 100644 src/test/java/domain/LadderLineTest.java create mode 100644 src/test/java/domain/LadderLinesTest.java create mode 100644 src/test/java/domain/PlayerTest.java create mode 100644 src/test/java/domain/PlayersTest.java create mode 100644 src/test/java/domain/PointTest.java create mode 100644 src/test/java/domain/ResultItemTest.java create mode 100644 src/test/java/domain/ResultItemsTest.java diff --git a/src/main/java/domain/Ladder.java b/src/main/java/domain/Ladder.java deleted file mode 100644 index c5e6ad70..00000000 --- a/src/main/java/domain/Ladder.java +++ /dev/null @@ -1,62 +0,0 @@ -package domain; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -public class Ladder { - - private final List lines; - private final Width width; - - public Ladder(List lines, Width width) { - this.lines = lines; - this.width = width; - } - - public static Ladder generate(Width width, Height height, Random random) { - List lines = new ArrayList<>(); - for (int i = 0; i < height.value(); i++) { - Line line = new Line(width); - line.connect(random); - lines.add(line); - } - return new Ladder(lines, width); - } - - public int getFinalPosition(int startPosition) { - int currentPosition = startPosition; - for (Line line : lines) { - currentPosition = moveToNextPosition(currentPosition, line); - } - return currentPosition; - } - - private int moveToNextPosition(int currentPosition, Line line) { - List points = line.getPoints(); - - if (canMoveLeft(currentPosition, points)) { - return currentPosition - 1; - } - if (canMoveRight(currentPosition, points)) { - return currentPosition + 1; - } - return currentPosition; - } - - private boolean canMoveLeft(int currentPosition, List points) { - return currentPosition > 0 && points.get(currentPosition - 1).isConnectedToRight(); - } - - private boolean canMoveRight(int currentPosition, List points) { - return currentPosition < points.size() - 1 && points.get(currentPosition).isConnectedToRight(); - } - - public List getLines() { - return lines; - } - - public Width getWidth() { - return width; - } -} diff --git a/src/main/java/domain/Line.java b/src/main/java/domain/Line.java deleted file mode 100644 index 465dbd05..00000000 --- a/src/main/java/domain/Line.java +++ /dev/null @@ -1,33 +0,0 @@ -package domain; - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -public class Line { - - private final List points; - - public Line(Width width) { - points = new ArrayList<>(); - for (int i = 0; i < width.value(); i++) { - points.add(new Point()); - } - } - - public void connect(Random random) { - for (int i = 0; i < points.size() - 1; i++) { // 가로줄 겹침 방지 - if (i > 0 && points.get(i - 1).isConnectedToRight()) { - continue; - } - if (random.nextBoolean()) { - points.get(i).connectToRight(); - points.get(i + 1).connectToLeft(); - } - } - } - - public List getPoints() { - return points; - } -} diff --git a/src/main/java/domain/Width.java b/src/main/java/domain/Width.java deleted file mode 100644 index e9c80434..00000000 --- a/src/main/java/domain/Width.java +++ /dev/null @@ -1,12 +0,0 @@ -package domain; - -public record Width(int value) { - - private static final int MIN_WIDTH_VALUE = 1; - - public Width { - if (value < MIN_WIDTH_VALUE) { - throw new IllegalArgumentException("사다리의 넓이는 1 이상이어야 합니다."); - } - } -} diff --git a/src/test/java/LadderTest.java b/src/test/java/LadderTest.java deleted file mode 100644 index 0608b228..00000000 --- a/src/test/java/LadderTest.java +++ /dev/null @@ -1,62 +0,0 @@ -import domain.*; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.Random; - -import static org.junit.jupiter.api.Assertions.*; - -public class LadderTest { - - @Test - @DisplayName("지정한 넓이와 높이에 맞게 사다리가 올바르게 생성되어야 함.") - void ladder_size_test() { - Width width = new Width(4); - Height height = new Height(5); - Ladder ladder = Ladder.generate(width, height, new Random(20)); - - assertEquals(5, ladder.getLines().size()); - for (Line line : ladder.getLines()) { - assertEquals(4, line.getPoints().size()); - } - } - - @Test - @DisplayName("사다리 타기가 올바르게 되어야 함.") - void ladder_moving_test() { - Width width = new Width(3); // 너비 : 3 (=3명의 참가자) - Height height = new Height(1); // 높이 : 1 - Ladder ladder = Ladder.generate(width, height, new Random() { - @Override - public boolean nextBoolean() { - return true; // 너비 인덱스 기준 0-1만 연결되어 있는 사다리 생성 - } - }); - - assertEquals(1, ladder.getFinalPosition(0)); - assertEquals(0, ladder.getFinalPosition(1)); - assertEquals(2, ladder.getFinalPosition(2)); - } - - @Test - @DisplayName("사다리 생성 시, 가로줄이 중첩되지 않게 생성되어야 함.") - void ladder_generate_overlap_test() { - Line line = new Line(new Width(5)); - line.connect(new Random(20)); - - List points = line.getPoints(); - for (int i = 0; i < points.size() - 2; i++) { - if (points.get(i).isConnectedToRight()) { - assertFalse(points.get(i + 1).isConnectedToRight()); - } - } - } - - @Test - @DisplayName("입력받은 사다리 높이 값은 1이상이어야 함.") - void height_throws_exception_test() { - assertThrows(IllegalArgumentException.class, () -> new Height(0)); - assertThrows(IllegalArgumentException.class, () -> new Height(-1)); - } -} diff --git a/src/test/java/domain/LadderLineTest.java b/src/test/java/domain/LadderLineTest.java new file mode 100644 index 00000000..bf8dc537 --- /dev/null +++ b/src/test/java/domain/LadderLineTest.java @@ -0,0 +1,96 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class LadderLineTest { + + @Test + @DisplayName("랜덤 생성 시, 사다리 라인이 정상적으로 생성된다.") + void createRandomLadderLine() { + Random random = new Random(1); + LadderLine ladderLine = new LadderLine(3, random); + + // 랜덤 시드 1로 생성했을 때 기대하는 포맷 + String expected = "|-----| | |"; + assertEquals(expected, formatForView(ladderLine)); + } + + @Test + @DisplayName("커스텀 포인트로 생성 시, 올바르게 시각적으로 표현된다.") + void createCustomLadderLine() { + // 직접 포인트 지정 + LadderLine ladderLine = new LadderLine(List.of( + Point.NOT_CONNECTED, + Point.CONNECTED_RIGHT, + Point.NOT_CONNECTED + )); + + // 기대하는 포맷 + String expected = "| |-----| |"; + assertEquals(expected, formatForView(ladderLine)); + } + + @Test + @DisplayName("사다리 타기에서 올바르게 이동한다.") + void moveCorrectly() { + LadderLine ladderLine = new LadderLine(List.of( + Point.CONNECTED_RIGHT, + Point.CONNECTED_LEFT, + Point.NOT_CONNECTED + )); + + // |-----|-----| | + assertEquals(1, ladderLine.move(0)); // 0 → 1 (오른쪽 연결) + assertEquals(0, ladderLine.move(1)); // 1 → 0 (왼쪽 연결) + assertEquals(2, ladderLine.move(2)); // 2 → 2 (연결 안 됨) + } + + @Test + @DisplayName("사다리의 끝에 도달했을 때 이동하지 않는다.") + void doNotMoveWhenAtTheEnd() { + LadderLine ladderLine = new LadderLine(List.of( + Point.NOT_CONNECTED, + Point.NOT_CONNECTED, + Point.NOT_CONNECTED + )); + + assertEquals(2, ladderLine.move(2)); // 끝에 도달하면 이동하지 않음 + } + + @Test + @DisplayName("포인트가 정상적으로 반환된다.") + void getPoints() { + LadderLine ladderLine = new LadderLine(List.of( + Point.NOT_CONNECTED, + Point.CONNECTED_RIGHT, + Point.NOT_CONNECTED + )); + + List points = ladderLine.getPoints(); + assertEquals(3, points.size()); + assertEquals(Point.NOT_CONNECTED, points.get(0)); + assertEquals(Point.CONNECTED_RIGHT, points.get(1)); + assertEquals(Point.NOT_CONNECTED, points.get(2)); + } + + // 테스트 전용 사다리 출력 포맷 메서드 + private String formatForView(LadderLine ladderLine) { + StringBuilder lineBuilder = new StringBuilder(); + lineBuilder.append("|"); + + for (Point point : ladderLine.getPoints()) { + if (point.isConnectedRight()) { + lineBuilder.append("-----|"); + } else { + lineBuilder.append(" |"); + } + } + return lineBuilder.toString(); + } +} diff --git a/src/test/java/domain/LadderLinesTest.java b/src/test/java/domain/LadderLinesTest.java new file mode 100644 index 00000000..57fc299c --- /dev/null +++ b/src/test/java/domain/LadderLinesTest.java @@ -0,0 +1,85 @@ +//package domain; +// +//import org.junit.jupiter.api.DisplayName; +//import org.junit.jupiter.api.Test; +// +//import java.util.List; +//import java.util.Random; +// +//import static org.junit.jupiter.api.Assertions.assertEquals; +//import static org.junit.jupiter.api.Assertions.assertNotNull; +// +//public class LadderLinesTest { +// +// @Test +// @DisplayName("LadderLines가 정상적으로 생성된다.") +// void createLadderLines() { +// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(5), new Random(1)); +// +// assertNotNull(ladderLines); +// assertEquals(5, ladderLines.getLines().size()); // 높이 5만큼 라인 생성 확인 +// } +// +// @Test +// @DisplayName("LadderLines가 랜덤하게 연결된다.") +// void ladderLinesShouldBeConnectedRandomly() { +// // ✅ 랜덤 시드 고정 +// Random random = new Random(42); // 시드 값을 42로 고정하면 동일한 결과가 나옵니다. +// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(3), random); +// +// List visualLines = ladderLines.getLines().stream() +// .map(this::formatForView) +// .toList(); +// +// // ✅ 시드값 42로 생성된 예상 결과 +// assertEquals("| |-----| |", visualLines.get(0)); +// assertEquals("| | | |", visualLines.get(1)); +// assertEquals("| | |-----|", visualLines.get(2)); +// } +// +// @Test +// @DisplayName("사다리 타기 시, 최종 위치가 예상대로 반환된다.") +// void getFinalPosition() { +// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(3), new Random(1)); +// +// // 시작 인덱스가 0일 때 → 1로 이동 (첫 번째 라인에서 오른쪽) +// int finalPosition = ladderLines.getFinalPosition(0); +// assertEquals(1, finalPosition); +// +// // 시작 인덱스가 1일 때 → 2로 이동 (두 번째 라인에서 오른쪽) +// finalPosition = ladderLines.getFinalPosition(1); +// assertEquals(2, finalPosition); +// +// // 시작 인덱스가 2일 때 → 2 그대로 유지 (연결 없음) +// finalPosition = ladderLines.getFinalPosition(2); +// assertEquals(2, finalPosition); +// } +// +// @Test +// @DisplayName("모든 라인이 올바르게 반환된다.") +// void getAllLines() { +// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(3), new Random(1)); +// +// List lines = ladderLines.getLines(); +// assertEquals(3, lines.size()); +// +// // 첫 번째 줄이 올바르게 생성되었는지 체크 +// String expectedLine = formatForView(lines.get(0)); +// assertEquals("|-----| | |", expectedLine); +// } +// +// // 테스트 전용 사다리 출력 포맷 메서드 +// private String formatForView(LadderLine ladderLine) { +// StringBuilder lineBuilder = new StringBuilder(); +// lineBuilder.append("|"); +// +// for (Point point : ladderLine.getPoints()) { +// if (point.isConnectedRight()) { +// lineBuilder.append("-----|"); +// } else { +// lineBuilder.append(" |"); +// } +// } +// return lineBuilder.toString(); +// } +//} diff --git a/src/test/java/domain/PlayerTest.java b/src/test/java/domain/PlayerTest.java new file mode 100644 index 00000000..9a1969bb --- /dev/null +++ b/src/test/java/domain/PlayerTest.java @@ -0,0 +1,43 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class PlayerTest { + + @Test + @DisplayName("정상적인 이름이 주어졌을 때, 플레이어가 생성되어야 한다.") + void create() { + Player player = new Player("Tom"); + assertEquals("Tom", player.getName()); + } + + @Test + @DisplayName("이름이 비어 있을 경우 예외가 발생해야 한다.") + void emptyNameThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Player(""); + }); + assertEquals("참여할 사람의 이름은 1자 이상 5자 이하여야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("이름이 5자를 초과하면 예외가 발생해야 한다.") + void longNameThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Player("TommyLee"); + }); + assertEquals("참여할 사람의 이름은 1자 이상 5자 이하여야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("다른 이름의 플레이어를 서로 다른 플레이어(객체)로 판단해야 한다.") + void playersWithDifferentNamesShouldNotBeEqual() { + Player player1 = new Player("Tom"); + Player player2 = new Player("Jerry"); + + assertNotEquals(player1, player2); + } +} diff --git a/src/test/java/domain/PlayersTest.java b/src/test/java/domain/PlayersTest.java new file mode 100644 index 00000000..d10ac2e6 --- /dev/null +++ b/src/test/java/domain/PlayersTest.java @@ -0,0 +1,54 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class PlayersTest { + + @Test + @DisplayName("정상적인 플레이어 목록으로 생성된다.") + void create() { + List playerList = List.of(new Player("Tom"), new Player("Jerry"), new Player("Max")); + Players players = new Players(playerList); + + assertEquals(3, players.count()); + } + + @Test + @DisplayName("플레이어 수가 0명일 경우 예외가 발생해야 한다.") + void emptyThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Players(List.of()); + }); + assertEquals("참여 인원은 최소 1명 이상이어야 합니다.", exception.getMessage()); + } + + @Test + @DisplayName("플레이어의 이름 목록을 정확히 추출한다.") + void extractNames() { + List playerList = List.of(new Player("Tom"), new Player("Jerry"), new Player("Max")); + Players players = new Players(playerList); + + List names = players.extractNames(); + assertEquals(List.of("Tom", "Jerry", "Max"), names); + } + + @Test + @DisplayName("플레이어 객체 목록을 정확히 반환한다.") + void extractPlayers() { + List playerList = List.of(new Player("Tom"), new Player("Jerry"), new Player("Max")); + Players players = new Players(playerList); + + List extractedPlayers = players.extractPlayers(); + assertEquals(3, extractedPlayers.size()); + assertEquals(playerList, extractedPlayers); + + assertThrows(UnsupportedOperationException.class, () -> { + extractedPlayers.add(new Player("John")); + }); + } +} diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java new file mode 100644 index 00000000..8944213e --- /dev/null +++ b/src/test/java/domain/PointTest.java @@ -0,0 +1,66 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class PointTest { + + @Test + @DisplayName("왼쪽으로 연결되어 있을 때, 인덱스가 -1 이동한다.") + void moveLeft() { + Point point = Point.CONNECTED_LEFT; + int newPosition = point.moveFrom(2); + + assertEquals(1, newPosition); + } + + @Test + @DisplayName("오른쪽으로 연결되어 있을 때, 인덱스가 +1 이동한다.") + void moveRight() { + Point point = Point.CONNECTED_RIGHT; + int newPosition = point.moveFrom(2); + + assertEquals(3, newPosition); + } + + @Test + @DisplayName("연결되지 않은 경우, 인덱스가 그대로 유지된다.") + void stay() { + Point point = Point.NOT_CONNECTED; + int newPosition = point.moveFrom(2); + + assertEquals(2, newPosition); + } + + @Test + @DisplayName("오른쪽 연결 여부 확인") + void isRight() { + Point point = Point.CONNECTED_RIGHT; + + assertEquals(true, point.isConnectedRight()); + assertEquals(false, point.isConnectedLeft()); + assertEquals(false, point.isNotConnected()); + } + + @Test + @DisplayName("왼쪽 연결 여부 확인") + void isLeft() { + Point point = Point.CONNECTED_LEFT; + + assertEquals(false, point.isConnectedRight()); + assertEquals(true, point.isConnectedLeft()); + assertEquals(false, point.isNotConnected()); + } + + @Test + @DisplayName("연결 안 됨 여부 확인") + void isNotConnected() { + Point point = Point.NOT_CONNECTED; + + assertEquals(false, point.isConnectedRight()); + assertEquals(false, point.isConnectedLeft()); + assertEquals(true, point.isNotConnected()); + } +} diff --git a/src/test/java/domain/ResultItemTest.java b/src/test/java/domain/ResultItemTest.java new file mode 100644 index 00000000..d730ecd8 --- /dev/null +++ b/src/test/java/domain/ResultItemTest.java @@ -0,0 +1,25 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResultItemTest { + + @Test + @DisplayName("정상적인 값이 주어졌을 때, ResultItem이 생성되어야 한다.") + void create() { + ResultItem resultItem = new ResultItem("1등"); + assertEquals("1등", resultItem.getItem()); + } + + @Test + @DisplayName("값이 비어 있을 경우 예외가 발생해야 한다.") + void emptyThrowsException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new ResultItem(""); + }); + assertEquals("실행 결과 값은 필수 입력 값입니다.", exception.getMessage()); + } +} diff --git a/src/test/java/domain/ResultItemsTest.java b/src/test/java/domain/ResultItemsTest.java new file mode 100644 index 00000000..37cd8876 --- /dev/null +++ b/src/test/java/domain/ResultItemsTest.java @@ -0,0 +1,56 @@ +package domain; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class ResultItemsTest { + + @Test + @DisplayName("정상적인 결과 목록으로 생성된다.") + void create() { + List items = List.of(new ResultItem("1등"), new ResultItem("2등"), new ResultItem("꽝")); + ResultItems resultItems = new ResultItems(items, 3); + + assertEquals(3, resultItems.count()); + } + + @Test + @DisplayName("결과 개수가 예상 개수와 일치하지 않으면 예외가 발생해야 한다.") + void sizeMismatchThrowsException() { + List items = List.of(new ResultItem("1등"), new ResultItem("꽝")); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new ResultItems(items, 3); + }); + assertEquals("참여자의 수와 실행 결과 개수가 일치하지 않습니다.", exception.getMessage()); + } + + @Test + @DisplayName("결과 목록의 값을 정확히 추출한다.") + void extractNames() { + List items = List.of(new ResultItem("1등"), new ResultItem("2등"), new ResultItem("꽝")); + ResultItems resultItems = new ResultItems(items, 3); + + List names = resultItems.extractNames(); + assertEquals(List.of("1등", "2등", "꽝"), names); + } + + @Test + @DisplayName("결과 객체 목록을 정확히 반환한다.") + void extractItems() { + List items = List.of(new ResultItem("1등"), new ResultItem("2등"), new ResultItem("꽝")); + ResultItems resultItems = new ResultItems(items, 3); + + List extractedItems = resultItems.extractItems(); + assertEquals(3, extractedItems.size()); + assertEquals(items, extractedItems); + + assertThrows(UnsupportedOperationException.class, () -> { + extractedItems.add(new ResultItem("4등")); + }); + } +} From fe5128b54390017599c3e1d9d7ecedeecda864cf Mon Sep 17 00:00:00 2001 From: Jiwoo Kim Date: Sun, 11 May 2025 23:26:52 +0900 Subject: [PATCH 17/17] =?UTF-8?q?fix:=20=EC=82=AC=EB=8B=A4=EB=A6=AC=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=A4=91=20-=20=EB=9D=BC=EC=9D=B8=20=EA=B2=B9=EC=B9=A8=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20-=20main=EC=97=90=20=EC=A7=84=EC=9E=85=20?= =?UTF-8?q?=EB=B6=88=EA=B0=80=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/LadderController.java | 6 +- src/main/java/domain/LadderGame.java | 5 +- src/main/java/domain/LadderLine.java | 54 +++-------- src/main/java/domain/LadderLines.java | 21 ++-- src/main/java/domain/Point.java | 28 ++---- src/main/java/domain/RandomGenerator.java | 21 ++++ src/main/java/domain/RandomStrategy.java | 5 + src/main/java/view/LadderPrinter.java | 32 ++++--- src/main/java/view/OutputView.java | 1 - src/test/java/domain/LadderLineTest.java | 96 ------------------- src/test/java/domain/LadderLinesTest.java | 85 ---------------- src/test/java/domain/LadderPrinterTest.java | 30 ++++++ src/test/java/domain/PointTest.java | 66 ------------- 13 files changed, 112 insertions(+), 338 deletions(-) create mode 100644 src/main/java/domain/RandomGenerator.java create mode 100644 src/main/java/domain/RandomStrategy.java delete mode 100644 src/test/java/domain/LadderLineTest.java delete mode 100644 src/test/java/domain/LadderLinesTest.java create mode 100644 src/test/java/domain/LadderPrinterTest.java delete mode 100644 src/test/java/domain/PointTest.java diff --git a/src/main/java/controller/LadderController.java b/src/main/java/controller/LadderController.java index 38e0e52a..936c7732 100644 --- a/src/main/java/controller/LadderController.java +++ b/src/main/java/controller/LadderController.java @@ -6,7 +6,6 @@ import java.util.List; import java.util.Map; -import java.util.Random; import java.util.stream.Collectors; public class LadderController { @@ -20,11 +19,12 @@ public LadderController(InputView inputView, OutputView outputView) { } public void run() { + System.out.println("Starting Ladder Game..."); // 초기 진입 확인 + Players players = readPlayers(); ResultItems resultItems = readResultItems(players.count()); - LadderHeight height = inputView.readHeight(); - LadderGame ladderGame = LadderGame.start(players.count(), height, new Random()); + LadderGame ladderGame = LadderGame.of(players.count(), height, new RandomGenerator()); List playerNames = players.extractNames(); List resultItemNames = resultItems.extractNames(); diff --git a/src/main/java/domain/LadderGame.java b/src/main/java/domain/LadderGame.java index d3fe6066..dddbc76c 100644 --- a/src/main/java/domain/LadderGame.java +++ b/src/main/java/domain/LadderGame.java @@ -1,7 +1,6 @@ package domain; import java.util.List; -import java.util.Random; public class LadderGame { @@ -11,8 +10,8 @@ public LadderGame(LadderLines ladderLines) { this.ladderLines = ladderLines; } - public static LadderGame start(int width, LadderHeight height, Random random) { - return new LadderGame(LadderLines.generate(width, height, random)); + public static LadderGame of(int width, LadderHeight height, RandomStrategy strategy) { + return new LadderGame(LadderLines.of(width, height, strategy)); } public int getFinalPosition(int startPosition) { diff --git a/src/main/java/domain/LadderLine.java b/src/main/java/domain/LadderLine.java index 5824cc66..b4722b76 100644 --- a/src/main/java/domain/LadderLine.java +++ b/src/main/java/domain/LadderLine.java @@ -1,63 +1,35 @@ package domain; -import java.util.ArrayList; import java.util.List; -import java.util.Random; +import java.util.stream.IntStream; public class LadderLine { private final List points; - public LadderLine(int width, Random random) { - points = new ArrayList<>(); - Point previous = Point.NOT_CONNECTED; - - for (int i = 0; i < width; i++) { - Point nextPoint = createNextPoint(previous, random); - - // 마지막 포인트 연결 방지 - if (i == width - 1) { - nextPoint = Point.NOT_CONNECTED; - } - - points.add(nextPoint); - previous = nextPoint; - } - } - - public LadderLine(List points) { - this.points = List.copyOf(points); + // 라인 겹침 로직 수정 필요 + // 삼항 제거, else 사용 불가능, depth 체크 + public LadderLine(int width, RandomStrategy strategy) { + this.points = List.copyOf(IntStream.range(0, width) + .mapToObj(i -> { + if (i == width - 1) { + return Point.NOT_CONNECTED; + } + return strategy.nextBoolean() ? Point.CONNECTED_RIGHT : Point.NOT_CONNECTED; + }) + .toList()); } public List getPoints() { return List.copyOf(points); } - private Point createNextPoint(Point previous, Random random) { - // 이전 포인트가 오른쪽으로 연결되어 있으면, 현재 포인트는 왼쪽과 연결되어 있다는 것과 같음 - if (previous.isConnectedRight()) { - return Point.CONNECTED_LEFT; - } - // 랜덤하게 오른쪽 연결 여부 결정 - if (random.nextBoolean()) { - return Point.CONNECTED_RIGHT; - } - return Point.NOT_CONNECTED; - } - public int move(int currentPosition) { - // 오른쪽으로 가려할 때, 맨 끝부분에서는 더 이동하지 않도록 if (currentPosition < 0 || currentPosition >= points.size()) { return currentPosition; } Point currentPoint = points.get(currentPosition); - int nextPosition = currentPoint.moveFrom(currentPosition); - // 다음 위치가 범위를 넘어서면 현재 위치 유지 - if (nextPosition >= 0 && nextPosition < points.size()) { - return nextPosition; - } - - return nextPosition; + return currentPoint.move(currentPosition, points.size()); } } diff --git a/src/main/java/domain/LadderLines.java b/src/main/java/domain/LadderLines.java index 90f69b5e..aaea15d4 100644 --- a/src/main/java/domain/LadderLines.java +++ b/src/main/java/domain/LadderLines.java @@ -1,8 +1,7 @@ package domain; -import java.util.ArrayList; import java.util.List; -import java.util.Random; +import java.util.stream.IntStream; public class LadderLines { @@ -12,23 +11,19 @@ public LadderLines(List lines) { this.lines = List.copyOf(lines); } - public static LadderLines generate(int width, LadderHeight height, Random random) { - List lines = new ArrayList<>(); - for (int i = 0; i < height.value(); i++) { - lines.add(new LadderLine(width, random)); - } - - return new LadderLines(lines); + public static LadderLines of(int width, LadderHeight height, RandomStrategy strategy) { + return new LadderLines( + IntStream.range(0, height.value()) + .mapToObj(i -> new LadderLine(width, strategy)) + .toList() + ); } public int getFinalPosition(int startPosition) { int currentPosition = startPosition; for (LadderLine line : lines) { - int nextPosition = line.move(currentPosition); - if (nextPosition != currentPosition) { - currentPosition = nextPosition; - } + currentPosition = line.move(currentPosition); } return currentPosition; diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java index 43e0fc4f..235ecb2c 100644 --- a/src/main/java/domain/Point.java +++ b/src/main/java/domain/Point.java @@ -1,33 +1,25 @@ package domain; +import java.util.function.BiFunction; + public enum Point { // 왼쪽으로 연결됨 - CONNECTED_LEFT(-1), + CONNECTED_LEFT(-1, (current, size) -> Math.max(0, current - 1)), // 오른쪽으로 연결됨 - CONNECTED_RIGHT(1), + CONNECTED_RIGHT(1, (current, size) -> Math.min(size - 1, current + 1)), // 양쪽 아무 곳에도 연결되지 않음 - NOT_CONNECTED(0); + NOT_CONNECTED(0, (current, size) -> current); private final int offset; + private final BiFunction moveLogic; - Point(int offset) { + Point(int offset, BiFunction moveLogic) { this.offset = offset; + this.moveLogic = moveLogic; } - public int moveFrom(int currentPosition) { - return currentPosition + offset; - } - - public boolean isConnectedLeft() { - return this == CONNECTED_LEFT; - } - - public boolean isConnectedRight() { - return this == CONNECTED_RIGHT; - } - - public boolean isNotConnected() { - return this == NOT_CONNECTED; + public int move(int currentPosition, int size) { + return moveLogic.apply(currentPosition, size); } } diff --git a/src/main/java/domain/RandomGenerator.java b/src/main/java/domain/RandomGenerator.java new file mode 100644 index 00000000..c1af500e --- /dev/null +++ b/src/main/java/domain/RandomGenerator.java @@ -0,0 +1,21 @@ +package domain; + +import java.util.Random; + +public class RandomGenerator implements RandomStrategy { + + private final Random random; + + public RandomGenerator() { + this.random = new Random(); + } + + public RandomGenerator(long seed) { + this.random = new Random(seed); + } + + @Override + public boolean nextBoolean() { + return random.nextBoolean(); + } +} diff --git a/src/main/java/domain/RandomStrategy.java b/src/main/java/domain/RandomStrategy.java new file mode 100644 index 00000000..a7f59209 --- /dev/null +++ b/src/main/java/domain/RandomStrategy.java @@ -0,0 +1,5 @@ +package domain; + +public interface RandomStrategy { + boolean nextBoolean(); +} diff --git a/src/main/java/view/LadderPrinter.java b/src/main/java/view/LadderPrinter.java index 5d82ca86..e418df77 100644 --- a/src/main/java/view/LadderPrinter.java +++ b/src/main/java/view/LadderPrinter.java @@ -2,6 +2,9 @@ import domain.LadderGame; import domain.LadderLine; +import domain.Point; + +import java.util.List; public class LadderPrinter { @@ -11,22 +14,27 @@ public class LadderPrinter { private static final int CONNECTION_WIDTH = 5; public static void printLadder(LadderGame ladderGame) { - ladderGame.getLadderStructure().forEach(LadderPrinter::printLine); - } + List ladderLines = ladderGame.getLadderStructure(); + ladderLines.forEach(line -> { + StringBuilder lineBuilder = new StringBuilder(); + lineBuilder.append(POINT); // 첫 번째 포인트 - private static void printLine(LadderLine line) { - StringBuilder lineBuilder = new StringBuilder(); + List points = line.getPoints(); + int lastIndex = points.size() - 1; - lineBuilder.append(POINT); // 첫 번째 세로줄 - line.getPoints().forEach(point -> { - if (point.isConnectedRight()) { - lineBuilder.append(CONNECT_LINE.repeat(CONNECTION_WIDTH)); - } else { - lineBuilder.append(NO_CONNECT.repeat(CONNECTION_WIDTH)); + for (int i = 0; i < lastIndex; i++) { + appendConnection(lineBuilder, points.get(i)); + lineBuilder.append(POINT); // 다음 포인트 } - lineBuilder.append(POINT); // 다음 세로줄 + System.out.println(lineBuilder); // 한 줄 출력 }); + } - System.out.println(lineBuilder); + private static void appendConnection(StringBuilder lineBuilder, Point point) { + if (point.move(0, CONNECTION_WIDTH) == 1) { + lineBuilder.append(CONNECT_LINE.repeat(CONNECTION_WIDTH)); + return; + } + lineBuilder.append(NO_CONNECT.repeat(CONNECTION_WIDTH)); } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index ffb1734e..b39d188a 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,7 +1,6 @@ package view; import domain.LadderGame; -import domain.LadderLine; import java.util.List; import java.util.Map; diff --git a/src/test/java/domain/LadderLineTest.java b/src/test/java/domain/LadderLineTest.java deleted file mode 100644 index bf8dc537..00000000 --- a/src/test/java/domain/LadderLineTest.java +++ /dev/null @@ -1,96 +0,0 @@ -package domain; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.Random; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class LadderLineTest { - - @Test - @DisplayName("랜덤 생성 시, 사다리 라인이 정상적으로 생성된다.") - void createRandomLadderLine() { - Random random = new Random(1); - LadderLine ladderLine = new LadderLine(3, random); - - // 랜덤 시드 1로 생성했을 때 기대하는 포맷 - String expected = "|-----| | |"; - assertEquals(expected, formatForView(ladderLine)); - } - - @Test - @DisplayName("커스텀 포인트로 생성 시, 올바르게 시각적으로 표현된다.") - void createCustomLadderLine() { - // 직접 포인트 지정 - LadderLine ladderLine = new LadderLine(List.of( - Point.NOT_CONNECTED, - Point.CONNECTED_RIGHT, - Point.NOT_CONNECTED - )); - - // 기대하는 포맷 - String expected = "| |-----| |"; - assertEquals(expected, formatForView(ladderLine)); - } - - @Test - @DisplayName("사다리 타기에서 올바르게 이동한다.") - void moveCorrectly() { - LadderLine ladderLine = new LadderLine(List.of( - Point.CONNECTED_RIGHT, - Point.CONNECTED_LEFT, - Point.NOT_CONNECTED - )); - - // |-----|-----| | - assertEquals(1, ladderLine.move(0)); // 0 → 1 (오른쪽 연결) - assertEquals(0, ladderLine.move(1)); // 1 → 0 (왼쪽 연결) - assertEquals(2, ladderLine.move(2)); // 2 → 2 (연결 안 됨) - } - - @Test - @DisplayName("사다리의 끝에 도달했을 때 이동하지 않는다.") - void doNotMoveWhenAtTheEnd() { - LadderLine ladderLine = new LadderLine(List.of( - Point.NOT_CONNECTED, - Point.NOT_CONNECTED, - Point.NOT_CONNECTED - )); - - assertEquals(2, ladderLine.move(2)); // 끝에 도달하면 이동하지 않음 - } - - @Test - @DisplayName("포인트가 정상적으로 반환된다.") - void getPoints() { - LadderLine ladderLine = new LadderLine(List.of( - Point.NOT_CONNECTED, - Point.CONNECTED_RIGHT, - Point.NOT_CONNECTED - )); - - List points = ladderLine.getPoints(); - assertEquals(3, points.size()); - assertEquals(Point.NOT_CONNECTED, points.get(0)); - assertEquals(Point.CONNECTED_RIGHT, points.get(1)); - assertEquals(Point.NOT_CONNECTED, points.get(2)); - } - - // 테스트 전용 사다리 출력 포맷 메서드 - private String formatForView(LadderLine ladderLine) { - StringBuilder lineBuilder = new StringBuilder(); - lineBuilder.append("|"); - - for (Point point : ladderLine.getPoints()) { - if (point.isConnectedRight()) { - lineBuilder.append("-----|"); - } else { - lineBuilder.append(" |"); - } - } - return lineBuilder.toString(); - } -} diff --git a/src/test/java/domain/LadderLinesTest.java b/src/test/java/domain/LadderLinesTest.java deleted file mode 100644 index 57fc299c..00000000 --- a/src/test/java/domain/LadderLinesTest.java +++ /dev/null @@ -1,85 +0,0 @@ -//package domain; -// -//import org.junit.jupiter.api.DisplayName; -//import org.junit.jupiter.api.Test; -// -//import java.util.List; -//import java.util.Random; -// -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.junit.jupiter.api.Assertions.assertNotNull; -// -//public class LadderLinesTest { -// -// @Test -// @DisplayName("LadderLines가 정상적으로 생성된다.") -// void createLadderLines() { -// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(5), new Random(1)); -// -// assertNotNull(ladderLines); -// assertEquals(5, ladderLines.getLines().size()); // 높이 5만큼 라인 생성 확인 -// } -// -// @Test -// @DisplayName("LadderLines가 랜덤하게 연결된다.") -// void ladderLinesShouldBeConnectedRandomly() { -// // ✅ 랜덤 시드 고정 -// Random random = new Random(42); // 시드 값을 42로 고정하면 동일한 결과가 나옵니다. -// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(3), random); -// -// List visualLines = ladderLines.getLines().stream() -// .map(this::formatForView) -// .toList(); -// -// // ✅ 시드값 42로 생성된 예상 결과 -// assertEquals("| |-----| |", visualLines.get(0)); -// assertEquals("| | | |", visualLines.get(1)); -// assertEquals("| | |-----|", visualLines.get(2)); -// } -// -// @Test -// @DisplayName("사다리 타기 시, 최종 위치가 예상대로 반환된다.") -// void getFinalPosition() { -// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(3), new Random(1)); -// -// // 시작 인덱스가 0일 때 → 1로 이동 (첫 번째 라인에서 오른쪽) -// int finalPosition = ladderLines.getFinalPosition(0); -// assertEquals(1, finalPosition); -// -// // 시작 인덱스가 1일 때 → 2로 이동 (두 번째 라인에서 오른쪽) -// finalPosition = ladderLines.getFinalPosition(1); -// assertEquals(2, finalPosition); -// -// // 시작 인덱스가 2일 때 → 2 그대로 유지 (연결 없음) -// finalPosition = ladderLines.getFinalPosition(2); -// assertEquals(2, finalPosition); -// } -// -// @Test -// @DisplayName("모든 라인이 올바르게 반환된다.") -// void getAllLines() { -// LadderLines ladderLines = LadderLines.generate(3, new LadderHeight(3), new Random(1)); -// -// List lines = ladderLines.getLines(); -// assertEquals(3, lines.size()); -// -// // 첫 번째 줄이 올바르게 생성되었는지 체크 -// String expectedLine = formatForView(lines.get(0)); -// assertEquals("|-----| | |", expectedLine); -// } -// -// // 테스트 전용 사다리 출력 포맷 메서드 -// private String formatForView(LadderLine ladderLine) { -// StringBuilder lineBuilder = new StringBuilder(); -// lineBuilder.append("|"); -// -// for (Point point : ladderLine.getPoints()) { -// if (point.isConnectedRight()) { -// lineBuilder.append("-----|"); -// } else { -// lineBuilder.append(" |"); -// } -// } -// return lineBuilder.toString(); -// } -//} diff --git a/src/test/java/domain/LadderPrinterTest.java b/src/test/java/domain/LadderPrinterTest.java new file mode 100644 index 00000000..64c7bb59 --- /dev/null +++ b/src/test/java/domain/LadderPrinterTest.java @@ -0,0 +1,30 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import view.LadderPrinter; + +public class LadderPrinterTest { + + LadderGame ladderGame; + + @BeforeEach + @DisplayName("사다리 게임 초기화") + void setUp() { + // 고정된 전략으로 테스트 (항상 오른쪽으로 연결됨) + RandomStrategy fixedStrategy = () -> true; + // 가로 5, 높이 3, 전략 주입 + ladderGame = LadderGame.of(5, new LadderHeight(3), fixedStrategy); + } + + @Test + @DisplayName("전체 사다리 출력 테스트") + void printLadderStructure() { + System.out.println("\n=== Ladder Structure ==="); + LadderPrinter.printLadder(ladderGame); + } + + // 출력 로직 오류 + // 1. line 겹침 +} diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java deleted file mode 100644 index 8944213e..00000000 --- a/src/test/java/domain/PointTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package domain; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class PointTest { - - @Test - @DisplayName("왼쪽으로 연결되어 있을 때, 인덱스가 -1 이동한다.") - void moveLeft() { - Point point = Point.CONNECTED_LEFT; - int newPosition = point.moveFrom(2); - - assertEquals(1, newPosition); - } - - @Test - @DisplayName("오른쪽으로 연결되어 있을 때, 인덱스가 +1 이동한다.") - void moveRight() { - Point point = Point.CONNECTED_RIGHT; - int newPosition = point.moveFrom(2); - - assertEquals(3, newPosition); - } - - @Test - @DisplayName("연결되지 않은 경우, 인덱스가 그대로 유지된다.") - void stay() { - Point point = Point.NOT_CONNECTED; - int newPosition = point.moveFrom(2); - - assertEquals(2, newPosition); - } - - @Test - @DisplayName("오른쪽 연결 여부 확인") - void isRight() { - Point point = Point.CONNECTED_RIGHT; - - assertEquals(true, point.isConnectedRight()); - assertEquals(false, point.isConnectedLeft()); - assertEquals(false, point.isNotConnected()); - } - - @Test - @DisplayName("왼쪽 연결 여부 확인") - void isLeft() { - Point point = Point.CONNECTED_LEFT; - - assertEquals(false, point.isConnectedRight()); - assertEquals(true, point.isConnectedLeft()); - assertEquals(false, point.isNotConnected()); - } - - @Test - @DisplayName("연결 안 됨 여부 확인") - void isNotConnected() { - Point point = Point.NOT_CONNECTED; - - assertEquals(false, point.isConnectedRight()); - assertEquals(false, point.isConnectedLeft()); - assertEquals(true, point.isNotConnected()); - } -}