From 4529e0c54cbd52b54882918cd366cacf1735438d Mon Sep 17 00:00:00 2001 From: poketopa Date: Tue, 24 Mar 2026 19:11:31 +0900 Subject: [PATCH 01/41] =?UTF-8?q?docs(gitignore):=20macOS=20.gitignore=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 9 +++++++++ src/test/java/PointTest.java | 4 ++++ 2 files changed, 13 insertions(+) create mode 100644 src/test/java/PointTest.java diff --git a/.gitignore b/.gitignore index 6c01878138..8956079db5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,12 @@ out/ ### VS Code ### .vscode/ + +### macOS ### +.DS_Store +.AppleDouble +.LSOverride +Icon? +._* +.Spotlight-V100 +.Trashes diff --git a/src/test/java/PointTest.java b/src/test/java/PointTest.java new file mode 100644 index 0000000000..10e1366edc --- /dev/null +++ b/src/test/java/PointTest.java @@ -0,0 +1,4 @@ +package PACKAGE_NAME; + +public class PointTest { +} From b54e335c0591de539989c206e006354b7c16108c Mon Sep 17 00:00:00 2001 From: koreaioi Date: Tue, 24 Mar 2026 19:13:16 +0900 Subject: [PATCH 02/41] =?UTF-8?q?test:=20=EC=9E=90=EB=8F=99=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EB=90=9C=20PACKAGE=5FNAME=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/PointTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/PointTest.java b/src/test/java/PointTest.java index 10e1366edc..0ba4a0eac9 100644 --- a/src/test/java/PointTest.java +++ b/src/test/java/PointTest.java @@ -1,4 +1,3 @@ -package PACKAGE_NAME; public class PointTest { } From 24e02059662bc398be1f1eaf7af18082923eedb8 Mon Sep 17 00:00:00 2001 From: poketopa Date: Tue, 24 Mar 2026 19:14:46 +0900 Subject: [PATCH 03/41] =?UTF-8?q?test:=20=ED=8E=98=EC=96=B4=20=EB=A6=AC?= =?UTF-8?q?=EB=AA=A8=ED=8A=B8=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/test/java/TestClass.java | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/test/java/TestClass.java diff --git a/src/test/java/TestClass.java b/src/test/java/TestClass.java new file mode 100644 index 0000000000..96f05a0b74 --- /dev/null +++ b/src/test/java/TestClass.java @@ -0,0 +1,2 @@ +public class TestClass { +} From d9e796e808778f9d6889c1dda9fcf76d0b6c27b9 Mon Sep 17 00:00:00 2001 From: poketopa Date: Tue, 24 Mar 2026 19:41:58 +0900 Subject: [PATCH 04/41] =?UTF-8?q?feat(domain):=20Point=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Point.java | 19 +++++++++++++++++++ src/test/java/PointTest.java | 13 +++++++++++++ src/test/java/TestClass.java | 2 -- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/main/java/domain/Point.java delete mode 100644 src/test/java/TestClass.java diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java new file mode 100644 index 0000000000..1f6674b0e2 --- /dev/null +++ b/src/main/java/domain/Point.java @@ -0,0 +1,19 @@ +package domain; + +public class Point { + private final int y; + private final int x; + + public Point(int y, int x) { + validate(y, x); + this.y = y; + this.x = x; + } + + private void validate(int y, int x){ + if(0 <= y && y <= 9 && 0 <= x && x <= 8){ + return; + } + throw new IllegalArgumentException(); + } +} diff --git a/src/test/java/PointTest.java b/src/test/java/PointTest.java index 0ba4a0eac9..044208dc6b 100644 --- a/src/test/java/PointTest.java +++ b/src/test/java/PointTest.java @@ -1,3 +1,16 @@ +import domain.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; public class PointTest { + @Test + void Point의_좌표가_범위를_벗어나는_경우에_에러_발생(){ + int outOfIndexY = 10; + int outOfIndexX = 9; + + Assertions.assertThatThrownBy(() -> { + new Point(outOfIndexY, outOfIndexX); + }).isInstanceOf(IllegalArgumentException.class); + } } diff --git a/src/test/java/TestClass.java b/src/test/java/TestClass.java deleted file mode 100644 index 96f05a0b74..0000000000 --- a/src/test/java/TestClass.java +++ /dev/null @@ -1,2 +0,0 @@ -public class TestClass { -} From 2249919419c4de2d59b14755f31e8ea81db3d7fe Mon Sep 17 00:00:00 2001 From: poketopa Date: Tue, 24 Mar 2026 19:49:09 +0900 Subject: [PATCH 05/41] =?UTF-8?q?feat(domain):=20Point=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20equals=20/=20hashcode=20=EC=98=A4=EB=B2=84=EB=9D=BC?= =?UTF-8?q?=EC=9D=B4=EB=94=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/Point.java | 19 +++++++++++++++++++ src/test/java/PointTest.java | 14 +++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/Point.java index 1f6674b0e2..ece172f910 100644 --- a/src/main/java/domain/Point.java +++ b/src/main/java/domain/Point.java @@ -1,5 +1,7 @@ package domain; +import java.util.Objects; + public class Point { private final int y; private final int x; @@ -16,4 +18,21 @@ private void validate(int y, int x){ } throw new IllegalArgumentException(); } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Point point = (Point) o; + return y == point.y && x == point.x; + } + + @Override + public int hashCode() { + return Objects.hash(y, x); + } } diff --git a/src/test/java/PointTest.java b/src/test/java/PointTest.java index 044208dc6b..96341f8388 100644 --- a/src/test/java/PointTest.java +++ b/src/test/java/PointTest.java @@ -5,7 +5,7 @@ public class PointTest { @Test - void Point의_좌표가_범위를_벗어나는_경우에_에러_발생(){ + void 좌표가_범위를_벗어나는_경우에_에러가_발생한다(){ int outOfIndexY = 10; int outOfIndexX = 9; @@ -13,4 +13,16 @@ public class PointTest { new Point(outOfIndexY, outOfIndexX); }).isInstanceOf(IllegalArgumentException.class); } + + @Test + void 좌표가_같으면_동등한_객체로_취급한다(){ + int y = 3; + int x = 3; + + Point actual = new Point(y, x); + Point expected = new Point(y, x); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } } From 102c9a9e1530122029ff7f759a09593865f0b7a2 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 14:18:34 +0900 Subject: [PATCH 06/41] =?UTF-8?q?refactor:=20=ED=8C=A8=ED=82=A4=EC=A7=80?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/{ => domain}/PointTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/test/java/{ => domain}/PointTest.java (91%) diff --git a/src/test/java/PointTest.java b/src/test/java/domain/PointTest.java similarity index 91% rename from src/test/java/PointTest.java rename to src/test/java/domain/PointTest.java index 96341f8388..cbc414dab3 100644 --- a/src/test/java/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -1,6 +1,6 @@ -import domain.Point; +package domain; + import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class PointTest { From f917dfdde9f7890c6e953c6c098cb75d7797b980 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 14:57:12 +0900 Subject: [PATCH 07/41] =?UTF-8?q?feat(domain):=20=EA=B8=B0=EB=AC=BC=20?= =?UTF-8?q?=EC=A2=85=EB=A5=98=20=EC=A0=95=EC=9D=98=20=EB=B0=8F=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/piece/Cannon.java | 9 +++++++ src/main/java/domain/piece/Chariot.java | 9 +++++++ src/main/java/domain/piece/Elephant.java | 9 +++++++ src/main/java/domain/piece/Guard.java | 9 +++++++ src/main/java/domain/piece/Horse.java | 9 +++++++ src/main/java/domain/piece/NonePiece.java | 9 +++++++ src/main/java/domain/piece/Piece.java | 29 +++++++++++++++++++++++ src/main/java/domain/piece/PieceType.java | 14 +++++++++++ src/main/java/domain/piece/Soldier.java | 9 +++++++ src/main/java/domain/piece/Team.java | 9 +++++++ src/test/java/domain/PieceTest.java | 19 +++++++++++++++ 11 files changed, 134 insertions(+) create mode 100644 src/main/java/domain/piece/Cannon.java create mode 100644 src/main/java/domain/piece/Chariot.java create mode 100644 src/main/java/domain/piece/Elephant.java create mode 100644 src/main/java/domain/piece/Guard.java create mode 100644 src/main/java/domain/piece/Horse.java create mode 100644 src/main/java/domain/piece/NonePiece.java create mode 100644 src/main/java/domain/piece/Piece.java create mode 100644 src/main/java/domain/piece/PieceType.java create mode 100644 src/main/java/domain/piece/Soldier.java create mode 100644 src/main/java/domain/piece/Team.java create mode 100644 src/test/java/domain/PieceTest.java diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java new file mode 100644 index 0000000000..919e6a8d5c --- /dev/null +++ b/src/main/java/domain/piece/Cannon.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class Cannon extends Piece{ + + public Cannon(Team team) { + super(team, PieceType.CANNON); + } + +} diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java new file mode 100644 index 0000000000..47a31e3eb2 --- /dev/null +++ b/src/main/java/domain/piece/Chariot.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class Chariot extends Piece{ + + public Chariot(Team team) { + super(team, PieceType.CHARIOT); + } + +} diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java new file mode 100644 index 0000000000..3d5bb5438d --- /dev/null +++ b/src/main/java/domain/piece/Elephant.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class Elephant extends Piece{ + + public Elephant(Team team) { + super(team, PieceType.ELEPHANT); + } + +} diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java new file mode 100644 index 0000000000..c103119830 --- /dev/null +++ b/src/main/java/domain/piece/Guard.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class Guard extends Piece{ + + public Guard(Team team) { + super(team, PieceType.GUARD); + } + +} diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java new file mode 100644 index 0000000000..1f748b4b75 --- /dev/null +++ b/src/main/java/domain/piece/Horse.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class Horse extends Piece{ + + public Horse(Team team) { + super(team, PieceType.HORSE); + } + +} diff --git a/src/main/java/domain/piece/NonePiece.java b/src/main/java/domain/piece/NonePiece.java new file mode 100644 index 0000000000..be74095ce6 --- /dev/null +++ b/src/main/java/domain/piece/NonePiece.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class NonePiece extends Piece{ + + public NonePiece(Team team) { + super(team, PieceType.NONE); + } + +} diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java new file mode 100644 index 0000000000..d7bdfe098b --- /dev/null +++ b/src/main/java/domain/piece/Piece.java @@ -0,0 +1,29 @@ +package domain.piece; + +import java.util.Objects; + +public abstract class Piece { + + protected final Team team; + protected final PieceType pieceType; + // THINK + // protected final MoveRule moveRule; + + public Piece(Team team, PieceType pieceType) { + this.team = team; + this.pieceType = pieceType; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Piece piece = (Piece) o; + return pieceType == piece.pieceType; + } + + @Override + public int hashCode() { + return Objects.hashCode(pieceType); + } + +} diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java new file mode 100644 index 0000000000..71a2dff48d --- /dev/null +++ b/src/main/java/domain/piece/PieceType.java @@ -0,0 +1,14 @@ +package domain.piece; + +public enum PieceType { + + CHARIOT, // 차 + CANNON, // 포 + HORSE, // 마 + ELEPHANT, // 상 + GUARD, // 사 + SOLDIER, // 졸 + NONE, // null 포장 + ; + +} diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java new file mode 100644 index 0000000000..4bd18a27ab --- /dev/null +++ b/src/main/java/domain/piece/Soldier.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class Soldier extends Piece{ + + public Soldier(Team team) { + super(team, PieceType.SOLDIER); + } + +} diff --git a/src/main/java/domain/piece/Team.java b/src/main/java/domain/piece/Team.java new file mode 100644 index 0000000000..044dc96191 --- /dev/null +++ b/src/main/java/domain/piece/Team.java @@ -0,0 +1,9 @@ +package domain.piece; + +public enum Team { + + CHO, + HAN, + ; + +} diff --git a/src/test/java/domain/PieceTest.java b/src/test/java/domain/PieceTest.java new file mode 100644 index 0000000000..11d6d042b9 --- /dev/null +++ b/src/test/java/domain/PieceTest.java @@ -0,0 +1,19 @@ +package domain; + +import domain.piece.Cannon; +import domain.piece.Team; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class PieceTest { + + @Test + void 소속팀이_달라도_기물은_동등하다() { + Cannon cannonCho = new Cannon(Team.CHO); + Cannon cannonHan = new Cannon(Team.HAN); + + Assertions.assertThat(cannonCho) + .isEqualTo(cannonHan); + } + +} From a167ab1c54a3c79a17a201bcb2939395b6345abb Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 15:07:32 +0900 Subject: [PATCH 08/41] =?UTF-8?q?refactor(domain):=20NonePiece=EB=8A=94=20?= =?UTF-8?q?=EC=86=8C=EC=86=8D=EB=90=9C=20=ED=8C=80=EC=9D=B4=20=EC=97=86?= =?UTF-8?q?=EC=9C=BC=EB=AF=80=EB=A1=9C,=20Team=20Null=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/piece/NonePiece.java | 4 ++-- src/main/java/domain/piece/Piece.java | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/domain/piece/NonePiece.java b/src/main/java/domain/piece/NonePiece.java index be74095ce6..d5454278df 100644 --- a/src/main/java/domain/piece/NonePiece.java +++ b/src/main/java/domain/piece/NonePiece.java @@ -2,8 +2,8 @@ public class NonePiece extends Piece{ - public NonePiece(Team team) { - super(team, PieceType.NONE); + public NonePiece() { + super(PieceType.NONE); } } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index d7bdfe098b..244adfd36e 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -9,11 +9,16 @@ public abstract class Piece { // THINK // protected final MoveRule moveRule; - public Piece(Team team, PieceType pieceType) { + protected Piece(Team team, PieceType pieceType) { this.team = team; this.pieceType = pieceType; } + protected Piece(PieceType pieceType) { + this.team = null; + this.pieceType = pieceType; + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; From f36482ffbe50e21121745e6f98dff0922bd907ca Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 15:08:45 +0900 Subject: [PATCH 09/41] =?UTF-8?q?refactor(domain):=20Point=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/{ => point}/Point.java | 2 +- src/test/java/domain/PointTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename src/main/java/domain/{ => point}/Point.java (97%) diff --git a/src/main/java/domain/Point.java b/src/main/java/domain/point/Point.java similarity index 97% rename from src/main/java/domain/Point.java rename to src/main/java/domain/point/Point.java index ece172f910..0115d54aa8 100644 --- a/src/main/java/domain/Point.java +++ b/src/main/java/domain/point/Point.java @@ -1,4 +1,4 @@ -package domain; +package domain.point; import java.util.Objects; diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java index cbc414dab3..bb545ecbd0 100644 --- a/src/test/java/domain/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -1,5 +1,6 @@ package domain; +import domain.point.Point; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; From 4bc50fd11023ccd417e5912834ae21ecad9bdea2 Mon Sep 17 00:00:00 2001 From: poketopa Date: Wed, 25 Mar 2026 18:15:43 +0900 Subject: [PATCH 10/41] =?UTF-8?q?feat(domain):=20=EC=9E=A5=EA=B8=B0?= =?UTF-8?q?=ED=8C=90=20=EA=B8=B0=EB=AC=BC=20=EB=B0=B0=EC=B9=98=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/board/IntersectionGenerator.java | 8 ++++ src/main/java/domain/board/JanggiBoard.java | 40 +++++++++++++++++++ .../java/domain/board/JanggiGenerator.java | 11 +++++ .../domain/intersection/Intersection.java | 22 ++++++++++ src/main/java/domain/piece/Cannon.java | 2 +- src/main/java/domain/piece/Chariot.java | 2 +- src/main/java/domain/piece/Elephant.java | 2 +- src/main/java/domain/piece/General.java | 9 +++++ src/main/java/domain/piece/Guard.java | 2 +- src/main/java/domain/piece/Horse.java | 2 +- src/main/java/domain/piece/NonePiece.java | 2 +- src/main/java/domain/piece/Piece.java | 4 +- src/main/java/domain/piece/PieceType.java | 1 + src/main/java/domain/piece/Soldier.java | 2 +- src/main/java/domain/point/Point.java | 4 +- src/test/java/domain/BoardTest.java | 27 +++++++++++++ src/test/java/domain/PointTest.java | 4 +- .../domain/TestIntersectionGenerator.java | 17 ++++++++ 18 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 src/main/java/domain/board/IntersectionGenerator.java create mode 100644 src/main/java/domain/board/JanggiBoard.java create mode 100644 src/main/java/domain/board/JanggiGenerator.java create mode 100644 src/main/java/domain/intersection/Intersection.java create mode 100644 src/main/java/domain/piece/General.java create mode 100644 src/test/java/domain/BoardTest.java create mode 100644 src/test/java/domain/TestIntersectionGenerator.java diff --git a/src/main/java/domain/board/IntersectionGenerator.java b/src/main/java/domain/board/IntersectionGenerator.java new file mode 100644 index 0000000000..3afd8def9a --- /dev/null +++ b/src/main/java/domain/board/IntersectionGenerator.java @@ -0,0 +1,8 @@ +package domain.board; + +import domain.intersection.Intersection; +import java.util.List; + +public interface IntersectionGenerator { + List makeIntersection(); +} diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java new file mode 100644 index 0000000000..7acfc07f66 --- /dev/null +++ b/src/main/java/domain/board/JanggiBoard.java @@ -0,0 +1,40 @@ +package domain.board; + +import domain.intersection.Intersection; +import domain.piece.NonePiece; +import domain.point.Point; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class JanggiBoard { + private final Map intersections; + + public JanggiBoard(IntersectionGenerator intersectionGenerator) { + this.intersections = fillEmptyIntersections(); + setInitialIntersections(this.intersections, intersectionGenerator.makeIntersection()); + } + + private static Map fillEmptyIntersections() { + Map intersections = new HashMap<>(); + NonePiece nonePiece = new NonePiece(); + for (int row = 0; row < 10; row++) { + for (int file = 0; file < 9; file++) { + Point point = new Point(row, file); + intersections.put(point, new Intersection(point, nonePiece)); + } + } + return intersections; + } + + private static void setInitialIntersections(Map intersections, + List initialIntersections) { + for (Intersection intersection : initialIntersections) { + intersections.put(intersection.getPoint(), intersection); + } + } + + public Intersection getIntersection(Point point) { + return intersections.get(point); + } +} diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java new file mode 100644 index 0000000000..2c799656a6 --- /dev/null +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -0,0 +1,11 @@ +package domain.board; + +import domain.intersection.Intersection; +import java.util.ArrayList; +import java.util.List; + +public class JanggiGenerator implements IntersectionGenerator { + public List makeIntersection() { + return new ArrayList<>(); + } +} diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java new file mode 100644 index 0000000000..18960a4503 --- /dev/null +++ b/src/main/java/domain/intersection/Intersection.java @@ -0,0 +1,22 @@ +package domain.intersection; + +import domain.piece.Piece; +import domain.point.Point; + +public class Intersection { + private final Point point; + private Piece piece; + + public Intersection(Point point, Piece piece) { + this.point = point; + this.piece = piece; + } + + public Point getPoint() { + return point; + } + + public boolean isSamePiece(Intersection intersection) { + return this.piece.equals(intersection.piece); + } +} diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java index 919e6a8d5c..88aa840001 100644 --- a/src/main/java/domain/piece/Cannon.java +++ b/src/main/java/domain/piece/Cannon.java @@ -1,6 +1,6 @@ package domain.piece; -public class Cannon extends Piece{ +public class Cannon extends Piece { public Cannon(Team team) { super(team, PieceType.CANNON); diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java index 47a31e3eb2..735a5992ea 100644 --- a/src/main/java/domain/piece/Chariot.java +++ b/src/main/java/domain/piece/Chariot.java @@ -1,6 +1,6 @@ package domain.piece; -public class Chariot extends Piece{ +public class Chariot extends Piece { public Chariot(Team team) { super(team, PieceType.CHARIOT); diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java index 3d5bb5438d..48c0b9e75e 100644 --- a/src/main/java/domain/piece/Elephant.java +++ b/src/main/java/domain/piece/Elephant.java @@ -1,6 +1,6 @@ package domain.piece; -public class Elephant extends Piece{ +public class Elephant extends Piece { public Elephant(Team team) { super(team, PieceType.ELEPHANT); diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/General.java new file mode 100644 index 0000000000..0eaef4e8af --- /dev/null +++ b/src/main/java/domain/piece/General.java @@ -0,0 +1,9 @@ +package domain.piece; + +public class General extends Piece { + + public General(Team team) { + super(team, PieceType.GENERAL); + } + +} diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java index c103119830..eca1c0e9e1 100644 --- a/src/main/java/domain/piece/Guard.java +++ b/src/main/java/domain/piece/Guard.java @@ -1,6 +1,6 @@ package domain.piece; -public class Guard extends Piece{ +public class Guard extends Piece { public Guard(Team team) { super(team, PieceType.GUARD); diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java index 1f748b4b75..b301acdf6c 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/Horse.java @@ -1,6 +1,6 @@ package domain.piece; -public class Horse extends Piece{ +public class Horse extends Piece { public Horse(Team team) { super(team, PieceType.HORSE); diff --git a/src/main/java/domain/piece/NonePiece.java b/src/main/java/domain/piece/NonePiece.java index d5454278df..f32b5d30bf 100644 --- a/src/main/java/domain/piece/NonePiece.java +++ b/src/main/java/domain/piece/NonePiece.java @@ -1,6 +1,6 @@ package domain.piece; -public class NonePiece extends Piece{ +public class NonePiece extends Piece { public NonePiece() { super(PieceType.NONE); diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 244adfd36e..1582ef4094 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -21,7 +21,9 @@ protected Piece(PieceType pieceType) { @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } Piece piece = (Piece) o; return pieceType == piece.pieceType; } diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 71a2dff48d..5d23fd92ad 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -2,6 +2,7 @@ public enum PieceType { + GENERAL, // 궁 CHARIOT, // 차 CANNON, // 포 HORSE, // 마 diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java index 4bd18a27ab..86522134e5 100644 --- a/src/main/java/domain/piece/Soldier.java +++ b/src/main/java/domain/piece/Soldier.java @@ -1,6 +1,6 @@ package domain.piece; -public class Soldier extends Piece{ +public class Soldier extends Piece { public Soldier(Team team) { super(team, PieceType.SOLDIER); diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index 0115d54aa8..a840aa2be7 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -12,8 +12,8 @@ public Point(int y, int x) { this.x = x; } - private void validate(int y, int x){ - if(0 <= y && y <= 9 && 0 <= x && x <= 8){ + private void validate(int y, int x) { + if (0 <= y && y <= 9 && 0 <= x && x <= 8) { return; } throw new IllegalArgumentException(); diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java new file mode 100644 index 0000000000..293d1945b0 --- /dev/null +++ b/src/test/java/domain/BoardTest.java @@ -0,0 +1,27 @@ +package domain; + +import domain.board.JanggiBoard; +import domain.intersection.Intersection; +import domain.piece.General; +import domain.piece.Team; +import domain.point.Point; +import java.util.Arrays; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + +public class BoardTest { + @Test + void 장기판_기물_배치를_테스트한다() { + Point point = new Point(1, 4); + General general = new General(Team.HAN); + Intersection actualIntersection = new Intersection(point, general); + TestIntersectionGenerator testIntersectionGenerator = new TestIntersectionGenerator( + Arrays.asList(actualIntersection)); + + JanggiBoard janggiBoard = new JanggiBoard(testIntersectionGenerator); + Intersection expectedIntersection = janggiBoard.getIntersection(point); + + Assertions.assertThat(actualIntersection.isSamePiece(expectedIntersection)) + .isTrue(); + } +} diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java index bb545ecbd0..8139ffccbc 100644 --- a/src/test/java/domain/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -6,7 +6,7 @@ public class PointTest { @Test - void 좌표가_범위를_벗어나는_경우에_에러가_발생한다(){ + void 좌표가_범위를_벗어나는_경우에_에러가_발생한다() { int outOfIndexY = 10; int outOfIndexX = 9; @@ -16,7 +16,7 @@ public class PointTest { } @Test - void 좌표가_같으면_동등한_객체로_취급한다(){ + void 좌표가_같으면_동등한_객체로_취급한다() { int y = 3; int x = 3; diff --git a/src/test/java/domain/TestIntersectionGenerator.java b/src/test/java/domain/TestIntersectionGenerator.java new file mode 100644 index 0000000000..a69c4cadad --- /dev/null +++ b/src/test/java/domain/TestIntersectionGenerator.java @@ -0,0 +1,17 @@ +package domain; + +import domain.board.IntersectionGenerator; +import domain.intersection.Intersection; +import java.util.List; + +public class TestIntersectionGenerator implements IntersectionGenerator { + List intersections; + + public TestIntersectionGenerator(List intersections) { + this.intersections = intersections; + } + + public List makeIntersection() { + return this.intersections; + } +} From 210b039d5b95f18f2dbb259b5226979cd27d014c Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 19:02:34 +0900 Subject: [PATCH 11/41] =?UTF-8?q?feat(domain):=20=EB=B9=88=20=EC=B9=B8=20?= =?UTF-8?q?=EC=A0=95=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/JanggiBoard.java | 3 +-- src/main/java/domain/intersection/Intersection.java | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index 7acfc07f66..c7d6bc5888 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -17,11 +17,10 @@ public JanggiBoard(IntersectionGenerator intersectionGenerator) { private static Map fillEmptyIntersections() { Map intersections = new HashMap<>(); - NonePiece nonePiece = new NonePiece(); for (int row = 0; row < 10; row++) { for (int file = 0; file < 9; file++) { Point point = new Point(row, file); - intersections.put(point, new Intersection(point, nonePiece)); + intersections.put(point, Intersection.empty(point)); } } return intersections; diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index 18960a4503..dabd61de27 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -1,5 +1,6 @@ package domain.intersection; +import domain.piece.NonePiece; import domain.piece.Piece; import domain.point.Point; @@ -12,6 +13,10 @@ public Intersection(Point point, Piece piece) { this.piece = piece; } + public static Intersection empty(Point point) { + return new Intersection(point, new NonePiece()); + } + public Point getPoint() { return point; } From 74d0a0e4532e25a94017c7f856953d5673cd4990 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 21:25:29 +0900 Subject: [PATCH 12/41] =?UTF-8?q?feat(domain):=20=EC=83=81=EC=B0=A8?= =?UTF-8?q?=EB=A6=BC=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/Formation.java | 38 +++++++ .../java/domain/board/JanggiGenerator.java | 106 +++++++++++++++++- src/test/java/domain/BoardTest.java | 42 +++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 src/main/java/domain/board/Formation.java diff --git a/src/main/java/domain/board/Formation.java b/src/main/java/domain/board/Formation.java new file mode 100644 index 0000000000..54e056f315 --- /dev/null +++ b/src/main/java/domain/board/Formation.java @@ -0,0 +1,38 @@ +package domain.board; + +import java.util.Arrays; +import java.util.List; + +public enum Formation { + + ELEPHANT_HORSE_ELEPHANT_HORSE(1, List.of(1, 6), List.of(2, 7)), + ELEPHANT_HORSE_HORSE_ELEPHANT(2, List.of(1, 7), List.of(2, 6)), + HORSE_ELEPHANT_ELEPHANT_HORSE(3, List.of(2, 6), List.of(1, 7)), + HORSE_ELEPHANT_HORSE_ELEPHANT(4, List.of(2, 7), List.of(1, 6)), + ; + + private final int formatNumber; + private final List elephantFormations; + private final List horseFormations; + + Formation(int formatNumber, List elephantFormations, List horseFormations) { + this.formatNumber = formatNumber; + this.elephantFormations = elephantFormations; + this.horseFormations = horseFormations; + } + + public static Formation valueOf(int formatNumber) { + return Arrays.stream(Formation.values()) + .filter(formation -> formation.formatNumber == formatNumber) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + } + + public List elephantFormations() { + return elephantFormations; + } + + public List horseFormations() { + return horseFormations; + } +} diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java index 2c799656a6..a4b24004be 100644 --- a/src/main/java/domain/board/JanggiGenerator.java +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -1,11 +1,115 @@ package domain.board; import domain.intersection.Intersection; +import domain.piece.*; +import domain.point.Point; + import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class JanggiGenerator implements IntersectionGenerator { + + public static final int DEFAULT_SOLDIER_ROW = 3; + public static final int DEFAULT_CANNON_ROW = 2; + public static final int DEFAULT_GENERAL_ROW = 1; + public static final int DEFAULT_CHARIOT_AND_GUARD_ROW = 0; + public static final int DEFAULT_ELEPHANT_AND_HORSE_ROW = 0; + + private final Formation hanFormation; + private final Formation choFormation; + + public JanggiGenerator(Formation hanFormation, Formation choFormation) { + this.hanFormation = hanFormation; + this.choFormation = choFormation; + } + public List makeIntersection() { - return new ArrayList<>(); + return Stream.of(Team.values()) + .flatMap(team -> Stream.of( + createDefaultSoldierIntersection(team, DEFAULT_SOLDIER_ROW), + createDefaultCannonIntersection(team, DEFAULT_CANNON_ROW), + createDefaultGeneralIntersection(team, DEFAULT_GENERAL_ROW), + createDefaultGuardAndChariotIntersection(team, DEFAULT_CHARIOT_AND_GUARD_ROW), + createDefaultElephantAndHorseIntersection(team, DEFAULT_ELEPHANT_AND_HORSE_ROW), + createElephantAndHorseByFormation() + )) + .flatMap(List::stream) + .collect(Collectors.toCollection(ArrayList::new)); + } + + private List createDefaultSoldierIntersection(Team team, int row) { + row = reverseRow(team, row); + List intersections = new ArrayList<>(); + + for (int file = 0; file <= 8; file += 2) { + intersections.add(new Intersection(new Point(row, file), new Soldier(team))); + } + return intersections; + } + + private List createDefaultCannonIntersection(Team team, int row) { + row = reverseRow(team, row); + return List.of( + new Intersection(new Point(row, 1), new Cannon(team)), + new Intersection(new Point(row, 7), new Cannon(team)) + ); } + + private List createDefaultGeneralIntersection(Team team, int row) { + row = reverseRow(team, row); + return List.of(new Intersection(new Point(row, 4), new General(team))); + } + + private List createDefaultGuardAndChariotIntersection(Team team, int row) { + row = reverseRow(team, row); + return List.of( + new Intersection(new Point(row, 0), new Chariot(team)), + new Intersection(new Point(row, 8), new Chariot(team)), + new Intersection(new Point(row, 3), new Guard(team)), + new Intersection(new Point(row, 5), new Guard(team)) + ); + } + + private List createDefaultElephantAndHorseIntersection(Team team, int row) { + row = reverseRow(team, row); + return List.of( + new Intersection(new Point(row, 1), new Elephant(team)), + new Intersection(new Point(row, 2), new Horse(team)), + new Intersection(new Point(row, 6), new Elephant(team)), + new Intersection(new Point(row, 7), new Horse(team)) + ); + } + + public List createElephantAndHorseByFormation() { + return Stream.concat( + createElephantAndHorseByFormation(Team.HAN, hanFormation).stream(), + createElephantAndHorseByFormation(Team.CHO, choFormation).stream() + ).collect(Collectors.toCollection(ArrayList::new)); + } + + public List createElephantAndHorseByFormation(Team team, Formation formation) { + int correctedRow = reverseRow(team, DEFAULT_ELEPHANT_AND_HORSE_ROW); + + return Stream.concat( + createIntersections(correctedRow, formation.elephantFormations(), new Elephant(team)).stream(), + createIntersections(correctedRow, formation.horseFormations(), new Horse(team)).stream() + ).collect(Collectors.toCollection(ArrayList::new)); + } + + private List createIntersections(int row, List files, Piece piece) { + return files.stream() + .map(file -> new Intersection(new Point(row, file), piece)) + .toList(); + } + + private int reverseRow(Team team, int row) { + int maxRow = 9; + if (team == Team.CHO) { + return maxRow - row; + } + return row; + } + } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 293d1945b0..9569381264 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -1,15 +1,25 @@ package domain; +import domain.board.Formation; import domain.board.JanggiBoard; +import domain.board.JanggiGenerator; import domain.intersection.Intersection; import domain.piece.General; import domain.piece.Team; import domain.point.Point; import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; +import java.util.stream.Stream; + import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; public class BoardTest { + + public static final int DEFAULT_ELEPHANT_AND_HORSE_ROW = 0; + @Test void 장기판_기물_배치를_테스트한다() { Point point = new Point(1, 4); @@ -24,4 +34,36 @@ public class BoardTest { Assertions.assertThat(actualIntersection.isSamePiece(expectedIntersection)) .isTrue(); } + + // TODO method 리팩토링 + @Test + void 차림이_선택되었을_때_상과_마를_정확한_위치에_배치해야_한다() { + Formation elephantHorseHorseElephant = Formation.ELEPHANT_HORSE_HORSE_ELEPHANT; + JanggiGenerator janggiGenerator = new JanggiGenerator( + elephantHorseHorseElephant, elephantHorseHorseElephant + ); + JanggiBoard janggiBoard = new JanggiBoard(janggiGenerator); + + List elephantAndHorsePoints = Stream.concat( + elephantHorseHorseElephant.elephantFormations().stream() + .map(x -> new Point(DEFAULT_ELEPHANT_AND_HORSE_ROW, x)), + elephantHorseHorseElephant.horseFormations().stream() + .map(x -> new Point(DEFAULT_ELEPHANT_AND_HORSE_ROW, x)) + ).toList(); + + List actual = elephantAndHorsePoints.stream() + .map(janggiBoard::getIntersection) + .toList(); + + List expected = + janggiGenerator.createElephantAndHorseByFormation(Team.HAN, Formation.ELEPHANT_HORSE_HORSE_ELEPHANT); + + for (int i = 0; i < actual.size(); i++) { + Intersection actualIntersection = actual.get(i); + Intersection expectedIntersection = expected.get(i); + + Assertions.assertThat(actualIntersection.isSamePiece(expectedIntersection)) + .isTrue(); + } + } } From d9f8370b3c2dff31e9f2aa3b208fa2ab26a5d949 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Wed, 25 Mar 2026 21:27:12 +0900 Subject: [PATCH 13/41] =?UTF-8?q?chore(domain):=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=A4=EC=85=98=EC=97=90=20=EB=A7=9E=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/Formation.java | 1 + src/main/java/domain/board/IntersectionGenerator.java | 2 ++ src/main/java/domain/board/JanggiBoard.java | 2 ++ src/main/java/domain/intersection/Intersection.java | 2 ++ src/main/java/domain/point/Point.java | 2 ++ 5 files changed, 9 insertions(+) diff --git a/src/main/java/domain/board/Formation.java b/src/main/java/domain/board/Formation.java index 54e056f315..2bf020e8bd 100644 --- a/src/main/java/domain/board/Formation.java +++ b/src/main/java/domain/board/Formation.java @@ -35,4 +35,5 @@ public List elephantFormations() { public List horseFormations() { return horseFormations; } + } diff --git a/src/main/java/domain/board/IntersectionGenerator.java b/src/main/java/domain/board/IntersectionGenerator.java index 3afd8def9a..b6ea857e38 100644 --- a/src/main/java/domain/board/IntersectionGenerator.java +++ b/src/main/java/domain/board/IntersectionGenerator.java @@ -4,5 +4,7 @@ import java.util.List; public interface IntersectionGenerator { + List makeIntersection(); + } diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index c7d6bc5888..ef17fc2a64 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -8,6 +8,7 @@ import java.util.Map; public class JanggiBoard { + private final Map intersections; public JanggiBoard(IntersectionGenerator intersectionGenerator) { @@ -36,4 +37,5 @@ private static void setInitialIntersections(Map intersectio public Intersection getIntersection(Point point) { return intersections.get(point); } + } diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index dabd61de27..e27b550a00 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -5,6 +5,7 @@ import domain.point.Point; public class Intersection { + private final Point point; private Piece piece; @@ -24,4 +25,5 @@ public Point getPoint() { public boolean isSamePiece(Intersection intersection) { return this.piece.equals(intersection.piece); } + } diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index a840aa2be7..9d2b55e026 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -3,6 +3,7 @@ import java.util.Objects; public class Point { + private final int y; private final int x; @@ -35,4 +36,5 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(y, x); } + } From ff153309ccbc11fb3720a272636ee9a8ac2be8da Mon Sep 17 00:00:00 2001 From: koreaioi Date: Thu, 26 Mar 2026 14:57:21 +0900 Subject: [PATCH 14/41] =?UTF-8?q?refactor(domain):=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/JanggiBoard.java | 37 ++++---- .../java/domain/board/JanggiGenerator.java | 91 +++++++------------ src/test/java/domain/BoardTest.java | 6 +- 3 files changed, 54 insertions(+), 80 deletions(-) diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index ef17fc2a64..85c1e9c066 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -1,40 +1,41 @@ package domain.board; import domain.intersection.Intersection; -import domain.piece.NonePiece; import domain.point.Point; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; public class JanggiBoard { + private static final int MAX_ROW = 10; + private static final int MAX_FILE = 9; + private final Map intersections; public JanggiBoard(IntersectionGenerator intersectionGenerator) { this.intersections = fillEmptyIntersections(); - setInitialIntersections(this.intersections, intersectionGenerator.makeIntersection()); + for (Intersection intersection : intersectionGenerator.makeIntersection()) { + intersections.put(intersection.getPoint(), intersection); + } } private static Map fillEmptyIntersections() { - Map intersections = new HashMap<>(); - for (int row = 0; row < 10; row++) { - for (int file = 0; file < 9; file++) { - Point point = new Point(row, file); - intersections.put(point, Intersection.empty(point)); - } - } - return intersections; + return getAllPoints() + .collect(Collectors.toMap(point -> point, Intersection::empty)); } - private static void setInitialIntersections(Map intersections, - List initialIntersections) { - for (Intersection intersection : initialIntersections) { - intersections.put(intersection.getPoint(), intersection); - } + private static Stream getAllPoints() { + return range(MAX_ROW).boxed() + .flatMap(row -> range(MAX_FILE).mapToObj(f -> new Point(row, f))); + } + + private static IntStream range(int maxRange) { + return IntStream.range(0, maxRange); } - public Intersection getIntersection(Point point) { + public Intersection findIntersection(Point point) { return intersections.get(point); } diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java index a4b24004be..79ef8d936b 100644 --- a/src/main/java/domain/board/JanggiGenerator.java +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -11,11 +11,17 @@ public class JanggiGenerator implements IntersectionGenerator { + public static final int MAX_ROW = 9; public static final int DEFAULT_SOLDIER_ROW = 3; public static final int DEFAULT_CANNON_ROW = 2; public static final int DEFAULT_GENERAL_ROW = 1; - public static final int DEFAULT_CHARIOT_AND_GUARD_ROW = 0; - public static final int DEFAULT_ELEPHANT_AND_HORSE_ROW = 0; + public static final int DEFAULT_BACK_ROW = 0; + + private static final List DEFAULT_SOLDIER_FILES = List.of(0, 2, 4, 6, 8); + private static final List DEFAULT_CANNON_FILES = List.of(1, 7); + private static final List DEFAULT_GENERAL_FILES = List.of(4); + private static final List DEFAULT_GUARD_FILES = List.of(3,5); + private static final List DEFAULT_CHARIOT_FILES = List.of(0, 8); private final Formation hanFormation; private final Formation choFormation; @@ -28,73 +34,42 @@ public JanggiGenerator(Formation hanFormation, Formation choFormation) { public List makeIntersection() { return Stream.of(Team.values()) .flatMap(team -> Stream.of( - createDefaultSoldierIntersection(team, DEFAULT_SOLDIER_ROW), - createDefaultCannonIntersection(team, DEFAULT_CANNON_ROW), - createDefaultGeneralIntersection(team, DEFAULT_GENERAL_ROW), - createDefaultGuardAndChariotIntersection(team, DEFAULT_CHARIOT_AND_GUARD_ROW), - createDefaultElephantAndHorseIntersection(team, DEFAULT_ELEPHANT_AND_HORSE_ROW), - createElephantAndHorseByFormation() + createDefaultSoldierIntersectionV2(team), + createDefaultCannonIntersectionV2(team), + createDefaultGeneralIntersectionV2(team), + createDefaultGuardIntersectionV2(team), + createDefaultChariotIntersectionV2(team), + createElephantAndHorseByFormation(team, getFormationByTeam(team)) )) .flatMap(List::stream) .collect(Collectors.toCollection(ArrayList::new)); } - private List createDefaultSoldierIntersection(Team team, int row) { - row = reverseRow(team, row); - List intersections = new ArrayList<>(); - - for (int file = 0; file <= 8; file += 2) { - intersections.add(new Intersection(new Point(row, file), new Soldier(team))); - } - return intersections; + private List createDefaultSoldierIntersectionV2(Team team) { + return createIntersections(getRow(team, DEFAULT_SOLDIER_ROW), DEFAULT_SOLDIER_FILES, new Soldier(team)); } - private List createDefaultCannonIntersection(Team team, int row) { - row = reverseRow(team, row); - return List.of( - new Intersection(new Point(row, 1), new Cannon(team)), - new Intersection(new Point(row, 7), new Cannon(team)) - ); + private List createDefaultCannonIntersectionV2(Team team) { + return createIntersections(getRow(team, DEFAULT_CANNON_ROW), DEFAULT_CANNON_FILES, new Cannon(team)); } - private List createDefaultGeneralIntersection(Team team, int row) { - row = reverseRow(team, row); - return List.of(new Intersection(new Point(row, 4), new General(team))); + private List createDefaultGeneralIntersectionV2(Team team) { + return createIntersections(getRow(team, DEFAULT_GENERAL_ROW), DEFAULT_GENERAL_FILES, new General(team)); } - private List createDefaultGuardAndChariotIntersection(Team team, int row) { - row = reverseRow(team, row); - return List.of( - new Intersection(new Point(row, 0), new Chariot(team)), - new Intersection(new Point(row, 8), new Chariot(team)), - new Intersection(new Point(row, 3), new Guard(team)), - new Intersection(new Point(row, 5), new Guard(team)) - ); + private List createDefaultGuardIntersectionV2(Team team) { + return createIntersections(getRow(team, DEFAULT_BACK_ROW), DEFAULT_GUARD_FILES, new Guard(team)); } - private List createDefaultElephantAndHorseIntersection(Team team, int row) { - row = reverseRow(team, row); - return List.of( - new Intersection(new Point(row, 1), new Elephant(team)), - new Intersection(new Point(row, 2), new Horse(team)), - new Intersection(new Point(row, 6), new Elephant(team)), - new Intersection(new Point(row, 7), new Horse(team)) - ); - } - - public List createElephantAndHorseByFormation() { - return Stream.concat( - createElephantAndHorseByFormation(Team.HAN, hanFormation).stream(), - createElephantAndHorseByFormation(Team.CHO, choFormation).stream() - ).collect(Collectors.toCollection(ArrayList::new)); + private List createDefaultChariotIntersectionV2(Team team) { + return createIntersections(getRow(team, DEFAULT_BACK_ROW), DEFAULT_CHARIOT_FILES, new Chariot(team)); } public List createElephantAndHorseByFormation(Team team, Formation formation) { - int correctedRow = reverseRow(team, DEFAULT_ELEPHANT_AND_HORSE_ROW); - + int row = getRow(team, DEFAULT_BACK_ROW); return Stream.concat( - createIntersections(correctedRow, formation.elephantFormations(), new Elephant(team)).stream(), - createIntersections(correctedRow, formation.horseFormations(), new Horse(team)).stream() + createIntersections(row, formation.elephantFormations(), new Elephant(team)).stream(), + createIntersections(row, formation.horseFormations(), new Horse(team)).stream() ).collect(Collectors.toCollection(ArrayList::new)); } @@ -104,12 +79,12 @@ private List createIntersections(int row, List files, Pie .toList(); } - private int reverseRow(Team team, int row) { - int maxRow = 9; - if (team == Team.CHO) { - return maxRow - row; - } - return row; + private Formation getFormationByTeam(Team team) { + return team == Team.HAN ? hanFormation : choFormation; + } + + private int getRow(Team team, int row) { + return team == Team.CHO ? MAX_ROW - row : row; } } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 9569381264..d045293742 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -9,8 +9,6 @@ import domain.point.Point; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.stream.IntStream; import java.util.stream.Stream; import org.assertj.core.api.Assertions; @@ -29,7 +27,7 @@ public class BoardTest { Arrays.asList(actualIntersection)); JanggiBoard janggiBoard = new JanggiBoard(testIntersectionGenerator); - Intersection expectedIntersection = janggiBoard.getIntersection(point); + Intersection expectedIntersection = janggiBoard.findIntersection(point); Assertions.assertThat(actualIntersection.isSamePiece(expectedIntersection)) .isTrue(); @@ -52,7 +50,7 @@ public class BoardTest { ).toList(); List actual = elephantAndHorsePoints.stream() - .map(janggiBoard::getIntersection) + .map(janggiBoard::findIntersection) .toList(); List expected = From a3e3d93488d2936896e644c132224493c33e455f Mon Sep 17 00:00:00 2001 From: poketopa Date: Thu, 26 Mar 2026 15:14:42 +0900 Subject: [PATCH 15/41] =?UTF-8?q?feat(domain):=20Point=20=EC=B6=95=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=20=EB=B9=84=EA=B5=90=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/point/Point.java | 27 +++++++----------------- src/test/java/domain/PointTest.java | 30 +++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index 9d2b55e026..f2da53e3ff 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -1,11 +1,9 @@ package domain.point; -import java.util.Objects; - -public class Point { - - private final int y; - private final int x; +public record Point( + int y, + int x +) { public Point(int y, int x) { validate(y, x); @@ -20,21 +18,12 @@ private void validate(int y, int x) { throw new IllegalArgumentException(); } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Point point = (Point) o; - return y == point.y && x == point.x; + public boolean isSameFile(Point other) { + return this.y == other.y; } - @Override - public int hashCode() { - return Objects.hash(y, x); + public boolean isSameRow(Point other) { + return this.x == other.x; } } diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java index 8139ffccbc..33b87b5430 100644 --- a/src/test/java/domain/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -2,11 +2,13 @@ import domain.point.Point; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class PointTest { @Test - void 좌표가_범위를_벗어나는_경우에_에러가_발생한다() { + @DisplayName("좌표가 범위를 벗어나는 경우에 에러가 발생한다") + void shouldThrowExceptionWhenCoordinateIsOutOfBounds() { int outOfIndexY = 10; int outOfIndexX = 9; @@ -16,7 +18,8 @@ public class PointTest { } @Test - void 좌표가_같으면_동등한_객체로_취급한다() { + @DisplayName("좌표가 같으면 동등한 객체로 취급한다") + void shouldBeEqualWhenPointsAreSame() { int y = 3; int x = 3; @@ -26,4 +29,27 @@ public class PointTest { Assertions.assertThat(actual) .isEqualTo(expected); } + + @Test + @DisplayName("(0, 0)과 (0, 7)은 Y축이 같아야 한다") + void returnTrueWhenFilesMatch(){ + int y = 0; + int seven = 7; + int zero = 0; + + Assertions.assertThat(new Point(y, seven).isSameFile(new Point(y, zero))) + .isTrue(); + } + + @Test + @DisplayName("(0, 0)과 (7, 0)은 X축이 같아야 한다") + void returnTrueWhenRowsMatch(){ + int x = 0; + int seven = 7; + int zero = 0; + + Assertions.assertThat(new Point(seven, x).isSameRow(new Point(zero, x))) + .isTrue(); + } + } From e4f4709626159e0aee50dfa73932098d99c1009e Mon Sep 17 00:00:00 2001 From: koreaioi Date: Thu, 26 Mar 2026 15:34:47 +0900 Subject: [PATCH 16/41] =?UTF-8?q?feat(domain):=20Point=EC=9D=98=20?= =?UTF-8?q?=EB=8B=A4=EC=9D=8C=20=EB=B0=A9=ED=96=A5=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=EC=9D=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/piece/move/Direction.java | 32 ++++++++++ src/main/java/domain/point/Point.java | 5 ++ src/test/java/domain/PointTest.java | 59 ++++++++++++++++++- 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/main/java/domain/piece/move/Direction.java diff --git a/src/main/java/domain/piece/move/Direction.java b/src/main/java/domain/piece/move/Direction.java new file mode 100644 index 0000000000..ac0106f6bc --- /dev/null +++ b/src/main/java/domain/piece/move/Direction.java @@ -0,0 +1,32 @@ +package domain.piece.move; + +public enum Direction { + + UP(-1, 0), + DOWN(1, 0), + LEFT(0, -1), + RIGHT(0, 1), + + LEFT_UP(-1, -1), + LEFT_DOWN(1, -1), + RIGHT_UP(-1, 1), + RIGHT_DOWN(1, 1), + ; + + private final int dy; + private final int dx; + + Direction(int dy, int dx) { + this.dy = dy; + this.dx = dx; + } + + public int dy() { + return dy; + } + + public int dx() { + return dx; + } + +} diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index f2da53e3ff..b7468c4425 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -1,5 +1,7 @@ package domain.point; +import domain.piece.move.Direction; + public record Point( int y, int x @@ -26,4 +28,7 @@ public boolean isSameRow(Point other) { return this.x == other.x; } + public Point next(Direction direction) { + return new Point(y + direction.dy(), x + direction.dx()); + } } diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java index 33b87b5430..b6541ab149 100644 --- a/src/test/java/domain/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -1,9 +1,12 @@ package domain; +import domain.piece.move.Direction; import domain.point.Point; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class PointTest { @Test @@ -32,7 +35,7 @@ void shouldBeEqualWhenPointsAreSame() { @Test @DisplayName("(0, 0)과 (0, 7)은 Y축이 같아야 한다") - void returnTrueWhenFilesMatch(){ + void returnTrueWhenFilesMatch() { int y = 0; int seven = 7; int zero = 0; @@ -43,7 +46,7 @@ void returnTrueWhenFilesMatch(){ @Test @DisplayName("(0, 0)과 (7, 0)은 X축이 같아야 한다") - void returnTrueWhenRowsMatch(){ + void returnTrueWhenRowsMatch() { int x = 0; int seven = 7; int zero = 0; @@ -52,4 +55,56 @@ void returnTrueWhenRowsMatch(){ .isTrue(); } + @Test + @DisplayName("(1,1)에서 DOWN시 (2,1)로 가야한다.") + void increaseRowDirectionWhenMovingDown() { + int y = 1; + int x = 1; + Direction down = Direction.DOWN; + + Point point = new Point(1, 1); + + Point actual = point.next(Direction.DOWN); + Point expected = new Point(2, 1); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + @Test + @DisplayName("(1,1)에서 UP시 (0,1)로 가야한다.") + void increaseRowDirectionWhenMovingUp() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.UP); + Point expected = new Point(0, 1); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + @Test + @DisplayName("(1,1)에서 LEFT시 (1,0)로 가야한다.") + void decreaseFileDirectionWhenMovingLeft() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.LEFT); + Point expected = new Point(1, 0); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + @Test + @DisplayName("(1,1)에서 DOWN시 (1,2)로 가야한다.") + void increaseFileDirectionWhenMovingRight() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.RIGHT); + Point expected = new Point(1, 2); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + } From 51e36132c2e42757ec51030f08d105357011bfd1 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Thu, 26 Mar 2026 15:54:31 +0900 Subject: [PATCH 17/41] =?UTF-8?q?feat(domain):=20Point=20=EC=9C=84?= =?UTF-8?q?=EC=B9=98=20=EC=9D=B4=EB=8F=99=20=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/piece/move/Directions.java | 21 +++ src/test/java/domain/PointTest.java | 142 +++++++++++++----- 2 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 src/main/java/domain/piece/move/Directions.java diff --git a/src/main/java/domain/piece/move/Directions.java b/src/main/java/domain/piece/move/Directions.java new file mode 100644 index 0000000000..884e018e31 --- /dev/null +++ b/src/main/java/domain/piece/move/Directions.java @@ -0,0 +1,21 @@ +package domain.piece.move; + +import java.util.List; + +public enum Directions { + + UP_LEFT_UP(List.of(Direction.UP, Direction.LEFT_UP)), + UP_LEFT_DOWN(List.of(Direction.UP, Direction.LEFT_DOWN)), + DOWN_RIGHT_DOWN(List.of(Direction.DOWN, Direction.RIGHT_DOWN)), + ; + + private final List directions; + + Directions(List directions) { + this.directions = directions; + } + + public List directions() { + return directions; + } +} diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java index b6541ab149..2f88aa5cc0 100644 --- a/src/test/java/domain/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -4,9 +4,8 @@ import domain.point.Point; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; public class PointTest { @Test @@ -55,56 +54,119 @@ void returnTrueWhenRowsMatch() { .isTrue(); } - @Test - @DisplayName("(1,1)에서 DOWN시 (2,1)로 가야한다.") - void increaseRowDirectionWhenMovingDown() { - int y = 1; - int x = 1; - Direction down = Direction.DOWN; + @Nested + @DisplayName("Point 위치 이동 검증") + class shouldUpdateDirectionWhenPointMove { - Point point = new Point(1, 1); + @Test + @DisplayName("DOWN시 Y축이 1증가해야한다.") + void increaseRowWhenMovingDown() { + Point point = new Point(1, 1); - Point actual = point.next(Direction.DOWN); - Point expected = new Point(2, 1); + Point actual = point.next(Direction.DOWN); + Point expected = new Point(2, 1); - Assertions.assertThat(actual) - .isEqualTo(expected); - } + Assertions.assertThat(actual) + .isEqualTo(expected); + } - @Test - @DisplayName("(1,1)에서 UP시 (0,1)로 가야한다.") - void increaseRowDirectionWhenMovingUp() { - Point point = new Point(1, 1); + @Test + @DisplayName("UP시 Y축이 1감소해야한다.") + void increaseRowWhenMovingUp() { + Point point = new Point(1, 1); - Point actual = point.next(Direction.UP); - Point expected = new Point(0, 1); + Point actual = point.next(Direction.UP); + Point expected = new Point(0, 1); - Assertions.assertThat(actual) - .isEqualTo(expected); - } + Assertions.assertThat(actual) + .isEqualTo(expected); + } - @Test - @DisplayName("(1,1)에서 LEFT시 (1,0)로 가야한다.") - void decreaseFileDirectionWhenMovingLeft() { - Point point = new Point(1, 1); + @Test + @DisplayName("LEFT시 X축이 1감소해야한다.") + void decreaseFileWhenMovingLeft() { + Point point = new Point(1, 1); - Point actual = point.next(Direction.LEFT); - Point expected = new Point(1, 0); + Point actual = point.next(Direction.LEFT); + Point expected = new Point(1, 0); - Assertions.assertThat(actual) - .isEqualTo(expected); - } + Assertions.assertThat(actual) + .isEqualTo(expected); + } - @Test - @DisplayName("(1,1)에서 DOWN시 (1,2)로 가야한다.") - void increaseFileDirectionWhenMovingRight() { - Point point = new Point(1, 1); + @Test + @DisplayName("RIGHT시 X축이 1증가해야한다.") + void increaseFileWhenMovingRight() { + Point point = new Point(1, 1); - Point actual = point.next(Direction.RIGHT); - Point expected = new Point(1, 2); + Point actual = point.next(Direction.RIGHT); + Point expected = new Point(1, 2); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + @Test + @DisplayName("LEFT_UP시 X축은 1감소하고 Y축도 1감소한다.") + void decreaseRowAndFileWhenMovingLeftAndUp() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.LEFT_UP); + Point expected = new Point(0, 0); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + @Test + @DisplayName("LEFT_DOWN시 X축은 1감소하고 Y축은 1증가한다.") + void increaseRowAndDecreaseFileWhenMovingLeftAndDown() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.LEFT_DOWN); + Point expected = new Point(2, 0); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + + @Test + @DisplayName("RIGHT_UP시 X축은 1증가하고 Y축은 1감소한다.") + void decreaseRowAndIncreaseFileWhenMovingRightUp() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.RIGHT_UP); + Point expected = new Point(0, 2); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + + @Test + @DisplayName("RIGHT_DOWN시 X축은 1증가하고 Y축은 1증가한다.") + void increaseRowAndFileWhenMovingRightDown() { + Point point = new Point(1, 1); + + Point actual = point.next(Direction.RIGHT_DOWN); + Point expected = new Point(2, 2); + + Assertions.assertThat(actual) + .isEqualTo(expected); + } + + @Test + @DisplayName("이동 시, 장기판 범위를 이탈하면 예외가 발생한다.") + void shouldThrowException_WhenPointMovingIsOutOfBound() { + Point point = new Point(0, 0); + + Assertions.assertThatThrownBy(() -> { + point.next(Direction.LEFT_UP); + }).isInstanceOf(IllegalArgumentException.class); + + } - Assertions.assertThat(actual) - .isEqualTo(expected); } } From 3f01333caf7f32d243632d7c66da8e4b2e18db47 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Thu, 26 Mar 2026 17:50:13 +0900 Subject: [PATCH 18/41] =?UTF-8?q?feat(domain):=20=EC=A3=BC=EC=96=B4?= =?UTF-8?q?=EC=A7=84=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20=EC=88=9C=EC=B0=A8?= =?UTF-8?q?=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99=20=EC=8B=9C,?= =?UTF-8?q?=20=EC=B5=9C=EC=A2=85=20=EB=AA=A9=EC=A0=81=EC=A7=80=EC=97=90=20?= =?UTF-8?q?=EB=8F=84=EB=8B=AC=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/point/Point.java | 12 +++++++++++- src/test/java/domain/DirectionTest.java | 26 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/test/java/domain/DirectionTest.java diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index b7468c4425..92f66de3a6 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -2,6 +2,8 @@ import domain.piece.move.Direction; +import java.util.List; + public record Point( int y, int x @@ -13,13 +15,21 @@ public Point(int y, int x) { this.x = x; } + public Point movePoint(int y, int x) { + return new Point(this.y + y, this.x + x); + } + private void validate(int y, int x) { - if (0 <= y && y <= 9 && 0 <= x && x <= 8) { + if (checkPointRange(y, x)) { return; } throw new IllegalArgumentException(); } + private boolean checkPointRange(int y, int x) { + return 0 <= y && y <= 9 && 0 <= x && x <= 8; + } + public boolean isSameFile(Point other) { return this.y == other.y; } diff --git a/src/test/java/domain/DirectionTest.java b/src/test/java/domain/DirectionTest.java new file mode 100644 index 0000000000..5238633a11 --- /dev/null +++ b/src/test/java/domain/DirectionTest.java @@ -0,0 +1,26 @@ +package domain; + +import domain.piece.move.Direction; +import domain.piece.move.Directions; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class DirectionTest { + + @Test + @DisplayName("주어진 경로를 순차적으로 이동했을 때 최종 목적지에 도달하는지 확인한다.") + void shouldReachTargetWhenFollowingDirections() { + Point current = new Point(0, 0); + Point target = new Point(2, 1); + + Directions directions = new Directions(List.of(Direction.DOWN, Direction.RIGHT_DOWN)); + + Assertions.assertThat(directions.canReach(current, target)) + .isTrue(); + } + +} From 2c4084bbb87853a0f069f78c283b535e45353642 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Thu, 26 Mar 2026 17:53:53 +0900 Subject: [PATCH 19/41] =?UTF-8?q?refactor(domain):=20direction=EC=9D=84=20?= =?UTF-8?q?=ED=95=9C=EB=8B=A8=EA=B3=84=20=EB=82=AE=EC=9D=80=20vector?= =?UTF-8?q?=EB=A1=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/piece/move/Direction.java | 31 +++++++----------- .../java/domain/piece/move/Directions.java | 15 ++++----- src/main/java/domain/piece/move/Vector.java | 32 +++++++++++++++++++ src/main/java/domain/point/Point.java | 8 ++--- src/test/java/domain/DirectionTest.java | 4 +-- src/test/java/domain/PointTest.java | 20 ++++++------ 6 files changed, 64 insertions(+), 46 deletions(-) create mode 100644 src/main/java/domain/piece/move/Vector.java diff --git a/src/main/java/domain/piece/move/Direction.java b/src/main/java/domain/piece/move/Direction.java index ac0106f6bc..dda7232f0b 100644 --- a/src/main/java/domain/piece/move/Direction.java +++ b/src/main/java/domain/piece/move/Direction.java @@ -1,32 +1,23 @@ package domain.piece.move; -public enum Direction { +import domain.point.Point; - UP(-1, 0), - DOWN(1, 0), - LEFT(0, -1), - RIGHT(0, 1), +import java.util.List; - LEFT_UP(-1, -1), - LEFT_DOWN(1, -1), - RIGHT_UP(-1, 1), - RIGHT_DOWN(1, 1), - ; +public class Direction { - private final int dy; - private final int dx; + List vectors; - Direction(int dy, int dx) { - this.dy = dy; - this.dx = dx; + public Direction(List vectors) { + this.vectors = vectors; } - public int dy() { - return dy; - } + public boolean canReach(Point start, Point target) { + int dy = vectors.stream().mapToInt(Vector::dy).sum(); + int dx = vectors.stream().mapToInt(Vector::dx).sum(); - public int dx() { - return dx; + Point destination = start.movePoint(dy, dx); + return destination.equals(target); } } diff --git a/src/main/java/domain/piece/move/Directions.java b/src/main/java/domain/piece/move/Directions.java index 884e018e31..892f3e268f 100644 --- a/src/main/java/domain/piece/move/Directions.java +++ b/src/main/java/domain/piece/move/Directions.java @@ -1,21 +1,18 @@ package domain.piece.move; +import java.util.Collections; import java.util.List; -public enum Directions { - - UP_LEFT_UP(List.of(Direction.UP, Direction.LEFT_UP)), - UP_LEFT_DOWN(List.of(Direction.UP, Direction.LEFT_DOWN)), - DOWN_RIGHT_DOWN(List.of(Direction.DOWN, Direction.RIGHT_DOWN)), - ; +public class Directions { private final List directions; - Directions(List directions) { + public Directions(List directions) { this.directions = directions; } - public List directions() { - return directions; + public List getDirections() { + return Collections.unmodifiableList(directions); } + } diff --git a/src/main/java/domain/piece/move/Vector.java b/src/main/java/domain/piece/move/Vector.java new file mode 100644 index 0000000000..d00a4a8847 --- /dev/null +++ b/src/main/java/domain/piece/move/Vector.java @@ -0,0 +1,32 @@ +package domain.piece.move; + +public enum Vector { + + UP(-1, 0), + DOWN(1, 0), + LEFT(0, -1), + RIGHT(0, 1), + + LEFT_UP(-1, -1), + LEFT_DOWN(1, -1), + RIGHT_UP(-1, 1), + RIGHT_DOWN(1, 1), + ; + + private final int dy; + private final int dx; + + Vector(int dy, int dx) { + this.dy = dy; + this.dx = dx; + } + + public int dy() { + return dy; + } + + public int dx() { + return dx; + } + +} diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index 92f66de3a6..150416d29f 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -1,8 +1,6 @@ package domain.point; -import domain.piece.move.Direction; - -import java.util.List; +import domain.piece.move.Vector; public record Point( int y, @@ -38,7 +36,7 @@ public boolean isSameRow(Point other) { return this.x == other.x; } - public Point next(Direction direction) { - return new Point(y + direction.dy(), x + direction.dx()); + public Point next(Vector vector) { + return new Point(y + vector.dy(), x + vector.dx()); } } diff --git a/src/test/java/domain/DirectionTest.java b/src/test/java/domain/DirectionTest.java index 5238633a11..3c05585fa9 100644 --- a/src/test/java/domain/DirectionTest.java +++ b/src/test/java/domain/DirectionTest.java @@ -1,7 +1,7 @@ package domain; import domain.piece.move.Direction; -import domain.piece.move.Directions; +import domain.piece.move.Vector; import domain.point.Point; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -17,7 +17,7 @@ void shouldReachTargetWhenFollowingDirections() { Point current = new Point(0, 0); Point target = new Point(2, 1); - Directions directions = new Directions(List.of(Direction.DOWN, Direction.RIGHT_DOWN)); + Direction directions = new Direction(List.of(Vector.DOWN, Vector.RIGHT_DOWN)); Assertions.assertThat(directions.canReach(current, target)) .isTrue(); diff --git a/src/test/java/domain/PointTest.java b/src/test/java/domain/PointTest.java index 2f88aa5cc0..59bd371f35 100644 --- a/src/test/java/domain/PointTest.java +++ b/src/test/java/domain/PointTest.java @@ -1,6 +1,6 @@ package domain; -import domain.piece.move.Direction; +import domain.piece.move.Vector; import domain.point.Point; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; @@ -63,7 +63,7 @@ class shouldUpdateDirectionWhenPointMove { void increaseRowWhenMovingDown() { Point point = new Point(1, 1); - Point actual = point.next(Direction.DOWN); + Point actual = point.next(Vector.DOWN); Point expected = new Point(2, 1); Assertions.assertThat(actual) @@ -75,7 +75,7 @@ void increaseRowWhenMovingDown() { void increaseRowWhenMovingUp() { Point point = new Point(1, 1); - Point actual = point.next(Direction.UP); + Point actual = point.next(Vector.UP); Point expected = new Point(0, 1); Assertions.assertThat(actual) @@ -87,7 +87,7 @@ void increaseRowWhenMovingUp() { void decreaseFileWhenMovingLeft() { Point point = new Point(1, 1); - Point actual = point.next(Direction.LEFT); + Point actual = point.next(Vector.LEFT); Point expected = new Point(1, 0); Assertions.assertThat(actual) @@ -99,7 +99,7 @@ void decreaseFileWhenMovingLeft() { void increaseFileWhenMovingRight() { Point point = new Point(1, 1); - Point actual = point.next(Direction.RIGHT); + Point actual = point.next(Vector.RIGHT); Point expected = new Point(1, 2); Assertions.assertThat(actual) @@ -111,7 +111,7 @@ void increaseFileWhenMovingRight() { void decreaseRowAndFileWhenMovingLeftAndUp() { Point point = new Point(1, 1); - Point actual = point.next(Direction.LEFT_UP); + Point actual = point.next(Vector.LEFT_UP); Point expected = new Point(0, 0); Assertions.assertThat(actual) @@ -123,7 +123,7 @@ void decreaseRowAndFileWhenMovingLeftAndUp() { void increaseRowAndDecreaseFileWhenMovingLeftAndDown() { Point point = new Point(1, 1); - Point actual = point.next(Direction.LEFT_DOWN); + Point actual = point.next(Vector.LEFT_DOWN); Point expected = new Point(2, 0); Assertions.assertThat(actual) @@ -136,7 +136,7 @@ void increaseRowAndDecreaseFileWhenMovingLeftAndDown() { void decreaseRowAndIncreaseFileWhenMovingRightUp() { Point point = new Point(1, 1); - Point actual = point.next(Direction.RIGHT_UP); + Point actual = point.next(Vector.RIGHT_UP); Point expected = new Point(0, 2); Assertions.assertThat(actual) @@ -149,7 +149,7 @@ void decreaseRowAndIncreaseFileWhenMovingRightUp() { void increaseRowAndFileWhenMovingRightDown() { Point point = new Point(1, 1); - Point actual = point.next(Direction.RIGHT_DOWN); + Point actual = point.next(Vector.RIGHT_DOWN); Point expected = new Point(2, 2); Assertions.assertThat(actual) @@ -162,7 +162,7 @@ void shouldThrowException_WhenPointMovingIsOutOfBound() { Point point = new Point(0, 0); Assertions.assertThatThrownBy(() -> { - point.next(Direction.LEFT_UP); + point.next(Vector.LEFT_UP); }).isInstanceOf(IllegalArgumentException.class); } From 69e688ffba8d390173e43a17c699093488d1c2aa Mon Sep 17 00:00:00 2001 From: poketopa Date: Thu, 26 Mar 2026 19:03:56 +0900 Subject: [PATCH 20/41] =?UTF-8?q?feat(domain):=20=EC=A3=BC=EC=96=B4?= =?UTF-8?q?=EC=A7=84=20=EA=B2=BD=EB=A1=9C=EC=9D=98=20=EC=A2=8C=ED=91=9C?= =?UTF-8?q?=EB=93=A4=EC=9D=84=20=EB=B3=80=ED=99=98=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/piece/move/Direction.java | 18 +++++++++++++-- .../java/domain/piece/move/Directions.java | 11 ++++++++++ src/main/java/domain/point/Point.java | 4 ++++ src/test/java/domain/DirectionTest.java | 22 +++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/main/java/domain/piece/move/Direction.java b/src/main/java/domain/piece/move/Direction.java index dda7232f0b..8052d84486 100644 --- a/src/main/java/domain/piece/move/Direction.java +++ b/src/main/java/domain/piece/move/Direction.java @@ -2,6 +2,7 @@ import domain.point.Point; +import java.util.ArrayList; import java.util.List; public class Direction { @@ -16,8 +17,21 @@ public boolean canReach(Point start, Point target) { int dy = vectors.stream().mapToInt(Vector::dy).sum(); int dx = vectors.stream().mapToInt(Vector::dx).sum(); - Point destination = start.movePoint(dy, dx); - return destination.equals(target); + if(start.canMake(dy, dx)){ + Point destination = start.movePoint(dy, dx); + return destination.equals(target); + } + + return false; + } + + public List getPoints(Point current){ + List points = new ArrayList<>(); + for(Vector vector : this.vectors){ + current = current.next(vector); + points.add(current); + } + return points; } } diff --git a/src/main/java/domain/piece/move/Directions.java b/src/main/java/domain/piece/move/Directions.java index 892f3e268f..100f64eb30 100644 --- a/src/main/java/domain/piece/move/Directions.java +++ b/src/main/java/domain/piece/move/Directions.java @@ -1,5 +1,7 @@ package domain.piece.move; +import domain.point.Point; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -15,4 +17,13 @@ public List getDirections() { return Collections.unmodifiableList(directions); } + public List findPoints(Point from, Point to){ + for(Direction direction : directions){ + if(direction.canReach(from, to)){ + return direction.getPoints(from); + } + } + throw new IllegalArgumentException(); + } + } diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index 150416d29f..d646bb674b 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -13,6 +13,10 @@ public Point(int y, int x) { this.x = x; } + public boolean canMake(int y, int x){ + return checkPointRange(this.y + y, this.x + x); + } + public Point movePoint(int y, int x) { return new Point(this.y + y, this.x + x); } diff --git a/src/test/java/domain/DirectionTest.java b/src/test/java/domain/DirectionTest.java index 3c05585fa9..accc39884f 100644 --- a/src/test/java/domain/DirectionTest.java +++ b/src/test/java/domain/DirectionTest.java @@ -1,8 +1,11 @@ package domain; import domain.piece.move.Direction; +import domain.piece.move.Directions; import domain.piece.move.Vector; import domain.point.Point; +import java.awt.dnd.DragGestureEvent; +import java.util.ArrayList; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -23,4 +26,23 @@ void shouldReachTargetWhenFollowingDirections() { .isTrue(); } + @Test + @DisplayName("주어진 경로의 좌표들을 최종적으로 반환하는지 확인한다.") + void returnAllPointsAlongDestination(){ + Direction direction1 = new Direction(List.of(Vector.UP, Vector.LEFT_UP)); + Direction direction2 = new Direction(List.of(Vector.DOWN, Vector.RIGHT_DOWN)); + Point from = new Point(0, 0); + Point to = new Point(2, 1); + + Directions directions = new Directions(List.of(direction1, direction2)); + + List actual = directions.findPoints(from, to); + + Assertions.assertThat(actual).containsExactlyInAnyOrder( + new Point(1, 0), + new Point(2, 1) + ); + } + + } From cb7c525c582c610eea50e67014dc40d549a4cef1 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 17:11:41 +0900 Subject: [PATCH 21/41] =?UTF-8?q?feat(domain):=20=EB=A7=88=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/intersection/Intersection.java | 8 ++ src/main/java/domain/piece/Piece.java | 8 ++ .../java/domain/piece/move/HorseMoveRule.java | 64 +++++++++++ src/main/java/domain/piece/move/MoveRule.java | 19 ++++ src/test/java/domain/BoardTest.java | 1 + .../TestIntersectionGenerator.java | 2 +- .../java/domain/rule/HorseMoveRuleTest.java | 100 ++++++++++++++++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/main/java/domain/piece/move/HorseMoveRule.java create mode 100644 src/main/java/domain/piece/move/MoveRule.java rename src/test/java/domain/{ => fixture}/TestIntersectionGenerator.java (94%) create mode 100644 src/test/java/domain/rule/HorseMoveRuleTest.java diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index e27b550a00..f3a9be0595 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -26,4 +26,12 @@ public boolean isSamePiece(Intersection intersection) { return this.piece.equals(intersection.piece); } + public boolean isSameTeam(Intersection to) { + return piece.isSameTeam(to.piece); + } + + public boolean hasPiece() { + return piece.hasPiece(); + } + } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 1582ef4094..28972eb43c 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -19,6 +19,14 @@ protected Piece(PieceType pieceType) { this.pieceType = pieceType; } + public boolean isSameTeam(Piece other) { + return this.team == other.team; + } + + public boolean hasPiece() { + return this.pieceType != PieceType.NONE; + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { diff --git a/src/main/java/domain/piece/move/HorseMoveRule.java b/src/main/java/domain/piece/move/HorseMoveRule.java new file mode 100644 index 0000000000..86556bdabd --- /dev/null +++ b/src/main/java/domain/piece/move/HorseMoveRule.java @@ -0,0 +1,64 @@ +package domain.piece.move; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.point.Point; + +import java.util.List; +import java.util.stream.IntStream; + +import static domain.piece.move.Vector.*; + +public class HorseMoveRule extends MoveRule { + + public HorseMoveRule() { + super(PieceType.HORSE, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + return true; + } + + // 같은 팀 인지 확인 + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + private void validateObstacleCondition(List path) { + List routeWithoutTarget = path.subList(0, path.size() - 1); + + boolean hasObstacle = routeWithoutTarget.stream() + .anyMatch(Intersection::hasPiece); + + if (hasObstacle) { + throw new IllegalArgumentException("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + } + + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP, LEFT_UP)), + new Direction(List.of(UP, RIGHT_UP)), + new Direction(List.of(DOWN, LEFT_DOWN)), + new Direction(List.of(DOWN, RIGHT_DOWN)), + new Direction(List.of(LEFT, LEFT_UP)), + new Direction(List.of(LEFT, LEFT_DOWN)), + new Direction(List.of(RIGHT, RIGHT_UP)), + new Direction(List.of(RIGHT, RIGHT_DOWN)) + )); + } + +} diff --git a/src/main/java/domain/piece/move/MoveRule.java b/src/main/java/domain/piece/move/MoveRule.java new file mode 100644 index 0000000000..fc81cbce2a --- /dev/null +++ b/src/main/java/domain/piece/move/MoveRule.java @@ -0,0 +1,19 @@ +package domain.piece.move; + +import domain.piece.PieceType; + +public abstract class MoveRule { + + /** + * 어떤 피스의 이동 전략인지. + * */ + + protected final PieceType pieceType; + protected final Directions directions; + + public MoveRule(PieceType pieceType, Directions directions) { + this.pieceType = pieceType; + this.directions = directions; + } + +} diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index d045293742..71630b3776 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -3,6 +3,7 @@ import domain.board.Formation; import domain.board.JanggiBoard; import domain.board.JanggiGenerator; +import domain.fixture.TestIntersectionGenerator; import domain.intersection.Intersection; import domain.piece.General; import domain.piece.Team; diff --git a/src/test/java/domain/TestIntersectionGenerator.java b/src/test/java/domain/fixture/TestIntersectionGenerator.java similarity index 94% rename from src/test/java/domain/TestIntersectionGenerator.java rename to src/test/java/domain/fixture/TestIntersectionGenerator.java index a69c4cadad..e775bab2bd 100644 --- a/src/test/java/domain/TestIntersectionGenerator.java +++ b/src/test/java/domain/fixture/TestIntersectionGenerator.java @@ -1,4 +1,4 @@ -package domain; +package domain.fixture; import domain.board.IntersectionGenerator; import domain.intersection.Intersection; diff --git a/src/test/java/domain/rule/HorseMoveRuleTest.java b/src/test/java/domain/rule/HorseMoveRuleTest.java new file mode 100644 index 0000000000..d6c534506a --- /dev/null +++ b/src/test/java/domain/rule/HorseMoveRuleTest.java @@ -0,0 +1,100 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.Horse; +import domain.piece.Team; +import domain.piece.move.HorseMoveRule; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class HorseMoveRuleTest { + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Point start = new Point(0, 0); + Point middlePoint = new Point(1, 0); + Point end = new Point(2, 1); + + Horse horse = new Horse(Team.CHO); + Horse sameTeamPiece = new Horse(Team.CHO); + + Intersection from = new Intersection(start, horse); + Intersection middleIntersection = Intersection.empty(middlePoint); + Intersection to = new Intersection(end, sameTeamPiece); + + HorseMoveRule horseRule = new HorseMoveRule(); + + Assertions.assertThatThrownBy(() -> { + horseRule.checkMoveRule(from, List.of(middleIntersection, to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("마의 이동 경로에 장애물이 있으면 예외가 발생한다.") + void shouldThrowExceptionWhenPathHasObstacle() { + Point start = new Point(0, 0); + Point middlePoint = new Point(1, 0); + Point end = new Point(2, 1); + + Horse horse = new Horse(Team.CHO); + Horse obstacle = new Horse(Team.CHO); + + Intersection from = new Intersection(start, horse); + Intersection middleIntersection = new Intersection(middlePoint, obstacle); + Intersection to = Intersection.empty(end); + + HorseMoveRule horseRule = new HorseMoveRule(); + + Assertions.assertThatThrownBy(() -> { + horseRule.checkMoveRule(from, List.of(middleIntersection, to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + + @Test + @DisplayName("마는 경로에 장애물이 없고 도착지가 비어 있으면 이동한다.") + void horseCanMove_WhenNoObstacle_AndDestinationIsEmpty() { + Point start = new Point(0, 0); + Point middlePoint = new Point(1, 0); + Point end = new Point(2, 1); + + Horse horse = new Horse(Team.CHO); + + Intersection from = new Intersection(start, horse); + Intersection middleIntersection = Intersection.empty(middlePoint); + Intersection to = Intersection.empty(end); + + HorseMoveRule horseRule = new HorseMoveRule(); + + Assertions.assertThat(horseRule.checkMoveRule(from, List.of(middleIntersection, to))) + .isTrue(); + } + + @Test + @DisplayName("마는 경로에 장애물이 없고 도착지에 상대팀이 있으면 이동한다.") + void horseCanMoveWhenNoObstacleAndDestinationIsOpponent() { + Point start = new Point(0, 0); + Point middlePoint = new Point(1, 0); + Point end = new Point(2, 1); + + Horse horse = new Horse(Team.CHO); + Horse opponent = new Horse(Team.HAN); + + Intersection from = new Intersection(start, horse); + Intersection middleIntersection = Intersection.empty(middlePoint); + Intersection to = new Intersection(start, opponent); + + HorseMoveRule horseRule = new HorseMoveRule(); + + Assertions.assertThat(horseRule.checkMoveRule(from, List.of(middleIntersection, to))) + .isTrue(); + } + + +} From 21321cd7a2dac1d19a635572c559c73a77906961 Mon Sep 17 00:00:00 2001 From: poketopa Date: Fri, 27 Mar 2026 17:43:18 +0900 Subject: [PATCH 22/41] =?UTF-8?q?feat(domain):=20=EC=83=81=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/move/ChariotMoveRule.java | 69 +++++++++++ .../domain/piece/move/ElephantMoveRule.java | 69 +++++++++++ .../domain/rule/ElephantMoveRuleTest.java | 108 ++++++++++++++++++ 3 files changed, 246 insertions(+) create mode 100644 src/main/java/domain/piece/move/ChariotMoveRule.java create mode 100644 src/main/java/domain/piece/move/ElephantMoveRule.java create mode 100644 src/test/java/domain/rule/ElephantMoveRuleTest.java diff --git a/src/main/java/domain/piece/move/ChariotMoveRule.java b/src/main/java/domain/piece/move/ChariotMoveRule.java new file mode 100644 index 0000000000..ab7e4a33f4 --- /dev/null +++ b/src/main/java/domain/piece/move/ChariotMoveRule.java @@ -0,0 +1,69 @@ +package domain.piece.move; + +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.LEFT_DOWN; +import static domain.piece.move.Vector.LEFT_UP; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.RIGHT_DOWN; +import static domain.piece.move.Vector.RIGHT_UP; +import static domain.piece.move.Vector.UP; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.point.Point; +import java.util.List; + +public class ChariotMoveRule extends MoveRule{ + + public ChariotMoveRule() { + super(PieceType.CHARIOT, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + return true; + } + + // 같은 팀 인지 확인 + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + private void validateObstacleCondition(List path) { + List routeWithoutTarget = path.subList(0, path.size() - 1); + + boolean hasObstacle = routeWithoutTarget.stream() + .anyMatch(Intersection::hasPiece); + + if (hasObstacle) { + throw new IllegalArgumentException("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + } + + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP, LEFT_UP, LEFT_UP)), + new Direction(List.of(UP, RIGHT_UP, RIGHT_UP)), + new Direction(List.of(DOWN, LEFT_DOWN, LEFT_DOWN)), + new Direction(List.of(DOWN, RIGHT_DOWN, RIGHT_DOWN)), + new Direction(List.of(LEFT, LEFT_UP, LEFT_UP)), + new Direction(List.of(LEFT, LEFT_DOWN, LEFT_DOWN)), + new Direction(List.of(RIGHT, RIGHT_UP, RIGHT_UP)), + new Direction(List.of(RIGHT, RIGHT_DOWN, RIGHT_DOWN)) + )); + } + +} diff --git a/src/main/java/domain/piece/move/ElephantMoveRule.java b/src/main/java/domain/piece/move/ElephantMoveRule.java new file mode 100644 index 0000000000..8f5479052f --- /dev/null +++ b/src/main/java/domain/piece/move/ElephantMoveRule.java @@ -0,0 +1,69 @@ +package domain.piece.move; + +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.LEFT_DOWN; +import static domain.piece.move.Vector.LEFT_UP; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.RIGHT_DOWN; +import static domain.piece.move.Vector.RIGHT_UP; +import static domain.piece.move.Vector.UP; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.point.Point; +import java.util.List; + +public class ElephantMoveRule extends MoveRule { + + public ElephantMoveRule() { + super(PieceType.ELEPHANT, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + return true; + } + + // 같은 팀 인지 확인 + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + private void validateObstacleCondition(List path) { + List routeWithoutTarget = path.subList(0, path.size() - 1); + + boolean hasObstacle = routeWithoutTarget.stream() + .anyMatch(Intersection::hasPiece); + + if (hasObstacle) { + throw new IllegalArgumentException("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + } + + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP, LEFT_UP, LEFT_UP)), + new Direction(List.of(UP, RIGHT_UP, RIGHT_UP)), + new Direction(List.of(DOWN, LEFT_DOWN, LEFT_DOWN)), + new Direction(List.of(DOWN, RIGHT_DOWN, RIGHT_DOWN)), + new Direction(List.of(LEFT, LEFT_UP, LEFT_UP)), + new Direction(List.of(LEFT, LEFT_DOWN, LEFT_DOWN)), + new Direction(List.of(RIGHT, RIGHT_UP, RIGHT_UP)), + new Direction(List.of(RIGHT, RIGHT_DOWN, RIGHT_DOWN)) + )); + } + +} diff --git a/src/test/java/domain/rule/ElephantMoveRuleTest.java b/src/test/java/domain/rule/ElephantMoveRuleTest.java new file mode 100644 index 0000000000..c39d730744 --- /dev/null +++ b/src/test/java/domain/rule/ElephantMoveRuleTest.java @@ -0,0 +1,108 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.Elephant; +import domain.piece.Team; +import domain.piece.move.ElephantMoveRule; +import domain.point.Point; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ElephantMoveRuleTest { + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Point start = new Point(0, 0); + Point middlePoint1 = new Point(1, 0); + Point middlePoint2 = new Point(2, 1); + Point end = new Point(3, 2); + + Elephant elephant = new Elephant(Team.CHO); + Elephant sameTeamPiece = new Elephant(Team.CHO); + + Intersection from = new Intersection(start, elephant); + Intersection middleIntersection1 = Intersection.empty(middlePoint1); + Intersection middleIntersection2 = Intersection.empty(middlePoint2); + Intersection to = new Intersection(end, sameTeamPiece); + + ElephantMoveRule elephantRule = new ElephantMoveRule(); + + Assertions.assertThatThrownBy(() -> { + elephantRule.checkMoveRule(from, List.of(middleIntersection1, middleIntersection2, to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("상의 이동 경로에 장애물이 있으면 예외가 발생한다.") + void shouldThrowExceptionWhenPathHasObstacle() { + Point start = new Point(0, 0); + Point middlePoint1 = new Point(1, 0); + Point middlePoint2 = new Point(2, 1); + Point end = new Point(3, 2); + + Elephant elephant = new Elephant(Team.CHO); + Elephant obstacle = new Elephant(Team.CHO); + + Intersection from = new Intersection(start, elephant); + Intersection middleIntersection1 = new Intersection(middlePoint1, obstacle); + Intersection middleIntersection2 = Intersection.empty(middlePoint2); + Intersection to = Intersection.empty(end); + + ElephantMoveRule elephantMoveRule = new ElephantMoveRule(); + + Assertions.assertThatThrownBy(() -> { + elephantMoveRule.checkMoveRule(from, List.of(middleIntersection1, middleIntersection2, to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + + @Test + @DisplayName("상은 경로에 장애물이 없고 도착지가 비어 있으면 이동한다.") + void horseCanMove_WhenNoObstacle_AndDestinationIsEmpty() { + Point start = new Point(0, 0); + Point middlePoint1 = new Point(1, 0); + Point middlePoint2 = new Point(2, 1); + Point end = new Point(3, 2); + + Elephant elephant = new Elephant(Team.CHO); + + Intersection from = new Intersection(start, elephant); + Intersection middleIntersection1 = Intersection.empty(middlePoint1); + Intersection middleIntersection2 = Intersection.empty(middlePoint2); + Intersection to = Intersection.empty(end); + + ElephantMoveRule elephantMoveRule = new ElephantMoveRule(); + + Assertions.assertThat( + elephantMoveRule.checkMoveRule(from, List.of(middleIntersection1, middleIntersection2, to))) + .isTrue(); + } + + @Test + @DisplayName("상은 경로에 장애물이 없고 도착지에 상대팀이 있으면 이동한다.") + void elephantCanMoveWhenNoObstacleAndDestinationIsOpponent() { + Point start = new Point(0, 0); + Point middlePoint1 = new Point(1, 0); + Point middlePoint2 = new Point(2, 1); + Point end = new Point(3, 2); + + Elephant elephant = new Elephant(Team.CHO); + Elephant opponent = new Elephant(Team.HAN); + + Intersection from = new Intersection(start, elephant); + Intersection middleIntersection1 = Intersection.empty(middlePoint1); + Intersection middleIntersection2 = Intersection.empty(middlePoint2); + Intersection to = new Intersection(start, opponent); + + ElephantMoveRule elephantMoveRule = new ElephantMoveRule(); + + Assertions.assertThat( + elephantMoveRule.checkMoveRule(from, List.of(middleIntersection1, middleIntersection2, to))) + .isTrue(); + } + +} From e5ffff4fa30ba9b44fc90b59217aa6dc89a6b207 Mon Sep 17 00:00:00 2001 From: poketopa Date: Fri, 27 Mar 2026 18:07:15 +0900 Subject: [PATCH 23/41] =?UTF-8?q?feat(domain):=20=EC=B0=A8=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/move/ChariotMoveRule.java | 45 ++++-- .../java/domain/rule/ChariotMoveRuleTest.java | 128 ++++++++++++++++++ 2 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 src/test/java/domain/rule/ChariotMoveRuleTest.java diff --git a/src/main/java/domain/piece/move/ChariotMoveRule.java b/src/main/java/domain/piece/move/ChariotMoveRule.java index ab7e4a33f4..75cfec76b8 100644 --- a/src/main/java/domain/piece/move/ChariotMoveRule.java +++ b/src/main/java/domain/piece/move/ChariotMoveRule.java @@ -55,14 +55,43 @@ private void validateObstacleCondition(List path) { public static Directions initializeDirections() { return new Directions(List.of( - new Direction(List.of(UP, LEFT_UP, LEFT_UP)), - new Direction(List.of(UP, RIGHT_UP, RIGHT_UP)), - new Direction(List.of(DOWN, LEFT_DOWN, LEFT_DOWN)), - new Direction(List.of(DOWN, RIGHT_DOWN, RIGHT_DOWN)), - new Direction(List.of(LEFT, LEFT_UP, LEFT_UP)), - new Direction(List.of(LEFT, LEFT_DOWN, LEFT_DOWN)), - new Direction(List.of(RIGHT, RIGHT_UP, RIGHT_UP)), - new Direction(List.of(RIGHT, RIGHT_DOWN, RIGHT_DOWN)) + new Direction(List.of(UP)), + new Direction(List.of(UP, UP)), + new Direction(List.of(UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP, UP, UP, UP)), + + new Direction(List.of(DOWN)), + new Direction(List.of(DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + + new Direction(List.of(RIGHT)), + new Direction(List.of(RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + + new Direction(List.of(LEFT)), + new Direction(List.of(LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT)) )); } diff --git a/src/test/java/domain/rule/ChariotMoveRuleTest.java b/src/test/java/domain/rule/ChariotMoveRuleTest.java new file mode 100644 index 0000000000..70ab25034c --- /dev/null +++ b/src/test/java/domain/rule/ChariotMoveRuleTest.java @@ -0,0 +1,128 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.Chariot; +import domain.piece.Elephant; +import domain.piece.Team; +import domain.piece.move.ChariotMoveRule; +import domain.piece.move.ElephantMoveRule; +import domain.point.Point; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +public class ChariotMoveRuleTest { + + final Point start = new Point(0, 0); + final Point middlePoint1 = new Point(1, 0); + final Point middlePoint2 = new Point(2, 0); + final Point middlePoint3 = new Point(3, 0); + final Point middlePoint4 = new Point(4, 0); + final Point middlePoint5 = new Point(5, 0); + final Point middlePoint6 = new Point(6, 0); + final Point middlePoint7 = new Point(7, 0); + final Point middlePoint8 = new Point(8, 0); + final Point end = new Point(9, 0); + + final Intersection intersection1 = Intersection.empty(middlePoint1); + final Intersection intersection2 = Intersection.empty(middlePoint2); + final Intersection intersection3 = Intersection.empty(middlePoint3); + final Intersection intersection4 = Intersection.empty(middlePoint4); + final Intersection intersection5 = Intersection.empty(middlePoint5); + final Intersection intersection6 = Intersection.empty(middlePoint6); + final Intersection intersection7 = Intersection.empty(middlePoint7); + final Intersection intersection8 = Intersection.empty(middlePoint8); + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Team sameTeam = Team.CHO; + + Intersection from = new Intersection(start, new Chariot(sameTeam)); + Intersection to = new Intersection(end, new Chariot(sameTeam)); + + ChariotMoveRule chariotMoveRule = new ChariotMoveRule(); + + Assertions.assertThatThrownBy(() -> { + chariotMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + intersection7, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("차의 이동 경로에 장애물이 있으면 예외가 발생한다.") + void shouldThrowExceptionWhenPathHasObstacle() { + Team sameTeam = Team.CHO; + + Intersection from = new Intersection(start, new Chariot(sameTeam)); + Intersection obstacle = new Intersection(middlePoint7, new Chariot(sameTeam)); + Intersection to = Intersection.empty(end); + + ChariotMoveRule chariotMoveRule = new ChariotMoveRule(); + + Assertions.assertThatThrownBy(() -> { + chariotMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + obstacle, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + + @Test + @DisplayName("차는 경로에 장애물이 없고 도착지가 비어 있으면 이동한다.") + void chariotCanMove_WhenNoObstacle_AndDestinationIsEmpty() { + Intersection from = new Intersection(start, new Chariot(Team.CHO)); + Intersection to = Intersection.empty(end); + + ChariotMoveRule chariotMoveRule = new ChariotMoveRule(); + + Assertions.assertThat( + chariotMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + intersection7, + intersection8, + to))) + .isTrue(); + } + + @Test + @DisplayName("차는 경로에 장애물이 없고 도착지에 상대팀이 있으면 이동한다.") + void chariotCanMoveWhenNoObstacleAndDestinationIsOpponent() { + Intersection from = new Intersection(start, new Chariot(Team.CHO)); + Intersection to = new Intersection(end, new Chariot(Team.HAN)); + + ChariotMoveRule chariotMoveRule = new ChariotMoveRule(); + + Assertions.assertThat( + chariotMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + intersection7, + intersection8, + to))) + .isTrue(); + } + +} From 87c8986f3c87bb9e979b45c147c39b50693f5981 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 18:28:03 +0900 Subject: [PATCH 24/41] =?UTF-8?q?feat(domain):=20=ED=8F=AC=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/move/CannonMoveRule.java | 111 ++++++++++++ .../java/domain/rule/CannonMoveRuleTest.java | 166 ++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 src/main/java/domain/piece/move/CannonMoveRule.java create mode 100644 src/test/java/domain/rule/CannonMoveRuleTest.java diff --git a/src/main/java/domain/piece/move/CannonMoveRule.java b/src/main/java/domain/piece/move/CannonMoveRule.java new file mode 100644 index 0000000000..5c188dfd13 --- /dev/null +++ b/src/main/java/domain/piece/move/CannonMoveRule.java @@ -0,0 +1,111 @@ +package domain.piece.move; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.point.Point; + +import java.util.List; + +import static domain.piece.move.Vector.*; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; + +public class CannonMoveRule extends MoveRule{ + + public CannonMoveRule() { + super(PieceType.CANNON, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateObstacleCondition(from, path); // 장애물 검사 + validateDestinationIsNotCannon(from, to); // 도착지가 포인지 확인한다. + return true; + } + + // 같은 팀 인지 확인 + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + private void validateObstacleCondition(Intersection from, List path) { + List obstacles = path.subList(0, path.size() - 1).stream() + .filter(Intersection::hasPiece) + .toList(); + + validateObstacleIsOnly(obstacles); + validateObstacleIsNotCannon(from, obstacles); + } + + private void validateObstacleIsOnly(List list) { + if (list.size() != 1) { + throw new IllegalArgumentException("포는 반드시 기물 하나를 넘어야 합니다."); + } + } + + private static void validateObstacleIsNotCannon(Intersection from, List list) { + if (list.getFirst().isSamePiece(from)) { + throw new IllegalArgumentException("포는 포를 넘어갈 수 없습니다."); + } + } + + private void validateDestinationIsNotCannon(Intersection from, Intersection to) { + if (from.isSamePiece(to)) { + throw new IllegalArgumentException("포는 포를 공격할 수 없습니다."); + } + } + + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP)), + new Direction(List.of(UP, UP)), + new Direction(List.of(UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP, UP, UP)), + new Direction(List.of(UP, UP, UP, UP, UP, UP, UP, UP, UP)), + + new Direction(List.of(DOWN)), + new Direction(List.of(DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + new Direction(List.of(DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN, DOWN)), + + new Direction(List.of(RIGHT)), + new Direction(List.of(RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + new Direction(List.of(RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT, RIGHT)), + + new Direction(List.of(LEFT)), + new Direction(List.of(LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT)), + new Direction(List.of(LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT)) + )); + } + +} diff --git a/src/test/java/domain/rule/CannonMoveRuleTest.java b/src/test/java/domain/rule/CannonMoveRuleTest.java new file mode 100644 index 0000000000..9bfc4d1161 --- /dev/null +++ b/src/test/java/domain/rule/CannonMoveRuleTest.java @@ -0,0 +1,166 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.Cannon; +import domain.piece.Chariot; +import domain.piece.Team; +import domain.piece.move.CannonMoveRule; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +class CannonMoveRuleTest { + + final Point start = new Point(0, 0); + final Point middlePoint1 = new Point(1, 0); + final Point middlePoint2 = new Point(2, 0); + final Point middlePoint3 = new Point(3, 0); + final Point middlePoint4 = new Point(4, 0); + final Point middlePoint5 = new Point(5, 0); + final Point middlePoint6 = new Point(6, 0); + final Point middlePoint7 = new Point(7, 0); + final Point middlePoint8 = new Point(8, 0); + final Point end = new Point(9, 0); + + final Intersection intersection1 = Intersection.empty(middlePoint1); + final Intersection intersection2 = Intersection.empty(middlePoint2); + final Intersection intersection3 = Intersection.empty(middlePoint3); + final Intersection intersection4 = Intersection.empty(middlePoint4); + final Intersection intersection5 = Intersection.empty(middlePoint5); + final Intersection intersection6 = Intersection.empty(middlePoint6); + final Intersection intersection7 = Intersection.empty(middlePoint7); + final Intersection intersection8 = Intersection.empty(middlePoint8); + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Team sameTeam = Team.CHO; + + Intersection from = new Intersection(start, new Cannon(sameTeam)); + Intersection onlyObstacleIntersection = new Intersection(middlePoint5, new Cannon(sameTeam)); + Intersection to = new Intersection(end, new Chariot(sameTeam)); + + CannonMoveRule cannonMoveRule = new CannonMoveRule(); + + Assertions.assertThatThrownBy(() -> { + cannonMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + onlyObstacleIntersection, + intersection6, + intersection7, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("포의 이동경로 장애물이 포이면 예외가 발생한다.") + void shouldThrowExceptionWhenObstacleIsCannon() { + Team sameTeam = Team.CHO; + Team anotherTeam = Team.HAN; + + Intersection from = new Intersection(start, new Cannon(sameTeam)); + Intersection cannonObstacle = new Intersection(middlePoint7, new Cannon(anotherTeam)); + Intersection to = Intersection.empty(end); + + CannonMoveRule cannonMoveRule = new CannonMoveRule(); + + Assertions.assertThatThrownBy(() -> { + cannonMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + cannonObstacle, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("포는 포를 넘어갈 수 없습니다."); + } + + @Test + @DisplayName("포는 두개의 장애물을 넘어갈 때 예외가 발생한다.") + void shouldThrowExceptionWhenCannonJumpTwoObstacle() { + Team sameTeam = Team.CHO; + Team anotherTeam = Team.HAN; + + Intersection from = new Intersection(start, new Cannon(sameTeam)); + Intersection obstacle1 = new Intersection(middlePoint5, new Chariot(anotherTeam)); + Intersection obstacle2 = new Intersection(middlePoint6, new Chariot(anotherTeam)); + Intersection to = Intersection.empty(end); + + CannonMoveRule cannonMoveRule = new CannonMoveRule(); + + Assertions.assertThatThrownBy(() -> { + cannonMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + obstacle1, + obstacle2, + intersection7, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("포는 반드시 기물 하나를 넘어야 합니다."); + } + + @Test + @DisplayName("포의 경로에 장애물이 없을 때 예외가 발생한다.") + void shouldThrowExceptionWhenCannonPathDoesntObstacle() { + Team sameTeam = Team.CHO; + + Intersection from = new Intersection(start, new Cannon(sameTeam)); + Intersection to = Intersection.empty(end); + + CannonMoveRule cannonMoveRule = new CannonMoveRule(); + + Assertions.assertThatThrownBy(() -> { + cannonMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + intersection7, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("포는 반드시 기물 하나를 넘어야 합니다."); + } + + @Test + @DisplayName("포가 포를 공격할때 예외가 발생한다.") + void shouldThrowExceptionWhenCannonAttackCannon() { + Team sameTeam = Team.CHO; + Team anotherTeam = Team.HAN; + + Intersection from = new Intersection(start, new Cannon(sameTeam)); + Intersection obstacle = new Intersection(middlePoint6, new Chariot(sameTeam)); + Intersection to = new Intersection(end, new Cannon(anotherTeam)); + + + CannonMoveRule cannonMoveRule = new CannonMoveRule(); + + Assertions.assertThatThrownBy(() -> { + cannonMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + obstacle, + intersection7, + intersection8, + to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("포는 포를 공격할 수 없습니다."); + } + +} From e55c900dd08292a90a988fe246899e7ba34ff078 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 18:57:43 +0900 Subject: [PATCH 25/41] =?UTF-8?q?feat(domain):=20=EC=A1=B8=EB=B3=91=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=EB=A5=BC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/intersection/Intersection.java | 4 + src/main/java/domain/piece/Piece.java | 4 + .../domain/piece/move/SoliderMoveRule.java | 59 ++++++++++++++ .../java/domain/rule/SoliderMoveRuleTest.java | 80 +++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 src/main/java/domain/piece/move/SoliderMoveRule.java create mode 100644 src/test/java/domain/rule/SoliderMoveRuleTest.java diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index f3a9be0595..f9e26b1766 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -34,4 +34,8 @@ public boolean hasPiece() { return piece.hasPiece(); } + public boolean isChoIntersection() { + return piece.isCho(); + } + } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 28972eb43c..a7f535df99 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -23,6 +23,10 @@ public boolean isSameTeam(Piece other) { return this.team == other.team; } + public boolean isCho() { + return this.team == Team.CHO; + } + public boolean hasPiece() { return this.pieceType != PieceType.NONE; } diff --git a/src/main/java/domain/piece/move/SoliderMoveRule.java b/src/main/java/domain/piece/move/SoliderMoveRule.java new file mode 100644 index 0000000000..966a0b099b --- /dev/null +++ b/src/main/java/domain/piece/move/SoliderMoveRule.java @@ -0,0 +1,59 @@ +package domain.piece.move; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.piece.Team; +import domain.point.Point; + +import java.util.List; + +import static domain.piece.move.Vector.*; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; + +public class SoliderMoveRule extends MoveRule { + + public SoliderMoveRule() { + super(PieceType.SOLDIER, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + Directions directions = getDirections(from); + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + return true; + } + + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(DOWN)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT))) + ); + } + + public Directions getDirections(Intersection from){ + if (from.isChoIntersection()) { + return new Directions(List.of( + new Direction(List.of(UP)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT)))); + } + return directions; + } + +} diff --git a/src/test/java/domain/rule/SoliderMoveRuleTest.java b/src/test/java/domain/rule/SoliderMoveRuleTest.java new file mode 100644 index 0000000000..186a55e40a --- /dev/null +++ b/src/test/java/domain/rule/SoliderMoveRuleTest.java @@ -0,0 +1,80 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.Soldier; +import domain.piece.Team; +import domain.piece.move.SoliderMoveRule; +import domain.piece.move.Vector; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class SoliderMoveRuleTest { + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Point start = new Point(0, 0); + Point end = new Point(1, 0); + + Team sameTeam = Team.HAN; + Soldier horse = new Soldier(sameTeam); + Soldier sameTeamPiece = new Soldier(sameTeam); + + Intersection from = new Intersection(start, horse); + Intersection to = new Intersection(end, sameTeamPiece); + + SoliderMoveRule soliderMoveRule = new SoliderMoveRule(); + + Assertions.assertThatThrownBy(() -> { + soliderMoveRule.checkMoveRule(from, List.of(to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("한 진영인 졸의 직진 방향은 내려감이다.") + void straightOfHanSoliderIsDown() { + Point start = new Point(0, 0); + Point end = start.next(Vector.DOWN); + + Team sameTeam = Team.HAN; + Team anotherTeam = Team.CHO; + Soldier horse = new Soldier(sameTeam); + Soldier sameTeamPiece = new Soldier(anotherTeam); + + Intersection from = new Intersection(start, horse); + Intersection to = new Intersection(end, sameTeamPiece); + + SoliderMoveRule soliderMoveRule = new SoliderMoveRule(); + + Assertions.assertThat(soliderMoveRule.checkMoveRule(from, List.of(to))) + .isTrue(); + + } + + @Test + @DisplayName("한 진영인 졸의 직진 방향은 올라감이다.") + void straightOfCHOSoliderIsUp() { + Point start = new Point(1, 0); + Point end = start.next(Vector.UP); + + Team sameTeam = Team.HAN; + Team anotherTeam = Team.CHO; + Soldier horse = new Soldier(sameTeam); + Soldier sameTeamPiece = new Soldier(anotherTeam); + + Intersection from = new Intersection(start, horse); + Intersection to = new Intersection(end, sameTeamPiece); + + SoliderMoveRule soliderMoveRule = new SoliderMoveRule(); + + Assertions.assertThat(soliderMoveRule.checkMoveRule(from, List.of(to))) + .isTrue(); + + } + +} From 004fe1debb618f16cc5b68906798b6bc508d46bb Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 19:06:52 +0900 Subject: [PATCH 26/41] =?UTF-8?q?feat(domain):=20=EC=9E=A5=EA=B5=B0=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=EB=A5=BC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/piece/move/GeneralMoveRule.java | 50 ++++++++++++ .../java/domain/rule/GeneralMoveRuleTest.java | 76 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/main/java/domain/piece/move/GeneralMoveRule.java create mode 100644 src/test/java/domain/rule/GeneralMoveRuleTest.java diff --git a/src/main/java/domain/piece/move/GeneralMoveRule.java b/src/main/java/domain/piece/move/GeneralMoveRule.java new file mode 100644 index 0000000000..3066037be4 --- /dev/null +++ b/src/main/java/domain/piece/move/GeneralMoveRule.java @@ -0,0 +1,50 @@ +package domain.piece.move; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.point.Point; + +import java.util.List; + +import static domain.piece.move.Vector.*; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.UP; + +public class GeneralMoveRule extends MoveRule{ + + public GeneralMoveRule() { + super(PieceType.GENERAL, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + return true; + } + + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP)), + new Direction(List.of(DOWN)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT))) + ); + } + +} diff --git a/src/test/java/domain/rule/GeneralMoveRuleTest.java b/src/test/java/domain/rule/GeneralMoveRuleTest.java new file mode 100644 index 0000000000..c8510ddbde --- /dev/null +++ b/src/test/java/domain/rule/GeneralMoveRuleTest.java @@ -0,0 +1,76 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.General; +import domain.piece.Soldier; +import domain.piece.Team; +import domain.piece.move.GeneralMoveRule; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class GeneralMoveRuleTest { + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Point start = new Point(0, 0); + Point end = new Point(1, 0); + + Team sameTeam = Team.HAN; + General general = new General(sameTeam); + Soldier sameTeamPiece = new Soldier(sameTeam); + + Intersection from = new Intersection(start, general); + Intersection to = new Intersection(end, sameTeamPiece); + + GeneralMoveRule generalMoveRule = new GeneralMoveRule(); + + Assertions.assertThatThrownBy(() -> { + generalMoveRule.checkMoveRule(from, List.of(to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("장군은 도착지에 상대팀이 있으면 이동할 수 있다.") + void canMoveGeneralWhenDestinationIsEmpty() { + Point start = new Point(1, 4); + Point end = new Point(2, 4); + + Team sameTeam = Team.HAN; + General general = new General(sameTeam); + + Intersection from = new Intersection(start, general); + Intersection to = Intersection.empty(end); + + GeneralMoveRule generalMoveRule = new GeneralMoveRule(); + + Assertions.assertThat(generalMoveRule.checkMoveRule(from, List.of(to))) + .isTrue(); + } + + @Test + @DisplayName("장군은 도착지에 상대팀이 있으면 이동할 수 있다.") + void canMoveGeneralWhenDestinationIsOpponent() { + Point start = new Point(1, 4); + Point end = new Point(2, 4); + + Team sameTeam = Team.HAN; + Team anotherTeam = Team.CHO; + General general = new General(sameTeam); + Soldier opponent = new Soldier(anotherTeam); + + Intersection from = new Intersection(start, general); + Intersection to = new Intersection(end, opponent); + + GeneralMoveRule generalMoveRule = new GeneralMoveRule(); + + Assertions.assertThat(generalMoveRule.checkMoveRule(from, List.of(to))) + .isTrue(); + } + +} From 1fe72f60ce13e7a4a4e5fdb7640aec4a5af16282 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 19:07:10 +0900 Subject: [PATCH 27/41] =?UTF-8?q?refactor(domain):=20=EC=A1=B8=EB=B3=91=20?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/rule/SoliderMoveRuleTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/java/domain/rule/SoliderMoveRuleTest.java b/src/test/java/domain/rule/SoliderMoveRuleTest.java index 186a55e40a..36cdf345fa 100644 --- a/src/test/java/domain/rule/SoliderMoveRuleTest.java +++ b/src/test/java/domain/rule/SoliderMoveRuleTest.java @@ -21,10 +21,10 @@ void shouldThrowExceptionWhenDestinationIsSameTeam() { Point end = new Point(1, 0); Team sameTeam = Team.HAN; - Soldier horse = new Soldier(sameTeam); + Soldier soldier = new Soldier(sameTeam); Soldier sameTeamPiece = new Soldier(sameTeam); - Intersection from = new Intersection(start, horse); + Intersection from = new Intersection(start, soldier); Intersection to = new Intersection(end, sameTeamPiece); SoliderMoveRule soliderMoveRule = new SoliderMoveRule(); @@ -43,11 +43,11 @@ void straightOfHanSoliderIsDown() { Team sameTeam = Team.HAN; Team anotherTeam = Team.CHO; - Soldier horse = new Soldier(sameTeam); - Soldier sameTeamPiece = new Soldier(anotherTeam); + Soldier soldier = new Soldier(sameTeam); + Soldier anotherTeamPiece = new Soldier(anotherTeam); - Intersection from = new Intersection(start, horse); - Intersection to = new Intersection(end, sameTeamPiece); + Intersection from = new Intersection(start, soldier); + Intersection to = new Intersection(end, anotherTeamPiece); SoliderMoveRule soliderMoveRule = new SoliderMoveRule(); @@ -64,11 +64,11 @@ void straightOfCHOSoliderIsUp() { Team sameTeam = Team.HAN; Team anotherTeam = Team.CHO; - Soldier horse = new Soldier(sameTeam); - Soldier sameTeamPiece = new Soldier(anotherTeam); + Soldier soldier = new Soldier(sameTeam); + Soldier anotherTeamPiece = new Soldier(anotherTeam); - Intersection from = new Intersection(start, horse); - Intersection to = new Intersection(end, sameTeamPiece); + Intersection from = new Intersection(start, soldier); + Intersection to = new Intersection(end, anotherTeamPiece); SoliderMoveRule soliderMoveRule = new SoliderMoveRule(); From af00787b9155d432bb00cecc5cdec12a1c66c437 Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 19:09:27 +0900 Subject: [PATCH 28/41] =?UTF-8?q?feat(domain):=20=EC=82=AC=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B0=80=EB=8A=A5=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/piece/move/GuardMoveRule.java | 47 +++++++++++ .../java/domain/rule/GuardMoveRuleTest.java | 78 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/main/java/domain/piece/move/GuardMoveRule.java create mode 100644 src/test/java/domain/rule/GuardMoveRuleTest.java diff --git a/src/main/java/domain/piece/move/GuardMoveRule.java b/src/main/java/domain/piece/move/GuardMoveRule.java new file mode 100644 index 0000000000..a84e93c22b --- /dev/null +++ b/src/main/java/domain/piece/move/GuardMoveRule.java @@ -0,0 +1,47 @@ +package domain.piece.move; + +import domain.intersection.Intersection; +import domain.piece.PieceType; +import domain.point.Point; + +import java.util.List; + +import static domain.piece.move.Vector.*; + +public class GuardMoveRule extends MoveRule{ + + public GuardMoveRule() { + super(PieceType.GUARD, initializeDirections()); + } + + public boolean support(PieceType pieceType) { + return this.pieceType == pieceType; + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + return true; + } + + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP)), + new Direction(List.of(DOWN)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT))) + ); + } + +} diff --git a/src/test/java/domain/rule/GuardMoveRuleTest.java b/src/test/java/domain/rule/GuardMoveRuleTest.java new file mode 100644 index 0000000000..b494a35656 --- /dev/null +++ b/src/test/java/domain/rule/GuardMoveRuleTest.java @@ -0,0 +1,78 @@ +package domain.rule; + +import domain.intersection.Intersection; +import domain.piece.General; +import domain.piece.Guard; +import domain.piece.Soldier; +import domain.piece.Team; +import domain.piece.move.GeneralMoveRule; +import domain.piece.move.GuardMoveRule; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class GuardMoveRuleTest { + + @Test + @DisplayName("도착지에 같은 팀이 있는 경우 예외가 발생한다.") + void shouldThrowExceptionWhenDestinationIsSameTeam() { + Point start = new Point(0, 0); + Point end = new Point(1, 0); + + Team sameTeam = Team.HAN; + Guard guard = new Guard(sameTeam); + Soldier sameTeamPiece = new Soldier(sameTeam); + + Intersection from = new Intersection(start, guard); + Intersection to = new Intersection(end, sameTeamPiece); + + GuardMoveRule guardMoveRule = new GuardMoveRule(); + + Assertions.assertThatThrownBy(() -> { + guardMoveRule.checkMoveRule(from, List.of(to)); + }).isInstanceOf(IllegalArgumentException.class) + .hasMessage("같은 팀의 위치로 이동할 수 없습니다."); + } + + @Test + @DisplayName("사는 도착지에 상대팀이 있으면 이동할 수 있다.") + void canMoveGuardWhenDestinationIsEmpty() { + Point start = new Point(1, 4); + Point end = new Point(2, 4); + + Team sameTeam = Team.HAN; + Guard guard = new Guard(sameTeam); + + Intersection from = new Intersection(start, guard); + Intersection to = Intersection.empty(end); + + GuardMoveRule guardMoveRule = new GuardMoveRule(); + + Assertions.assertThat(guardMoveRule.checkMoveRule(from, List.of(to))) + .isTrue(); + } + + @Test + @DisplayName("사는 도착지에 상대팀이 있으면 이동할 수 있다.") + void canMoveGuardWhenDestinationIsOpponent() { + Point start = new Point(1, 4); + Point end = new Point(2, 4); + + Team sameTeam = Team.HAN; + Team anotherTeam = Team.CHO; + Guard guard = new Guard(sameTeam); + Soldier opponent = new Soldier(anotherTeam); + + Intersection from = new Intersection(start, guard); + Intersection to = new Intersection(end, opponent); + + GuardMoveRule guardMoveRule = new GuardMoveRule(); + + Assertions.assertThat(guardMoveRule.checkMoveRule(from, List.of(to))) + .isTrue(); + } + +} From d5732e3d8e7d6a611044f65149b30c328ea9d34c Mon Sep 17 00:00:00 2001 From: koreaioi Date: Fri, 27 Mar 2026 19:38:41 +0900 Subject: [PATCH 29/41] =?UTF-8?q?feat(domain):=20=EC=A0=84=EC=B2=B4=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9D=84=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/JanggiBoard.java | 58 ++++++++++++++++++- .../domain/intersection/Intersection.java | 27 +++++++++ src/main/java/domain/piece/Piece.java | 4 ++ .../domain/piece/move/CannonMoveRule.java | 4 +- .../domain/piece/move/ChariotMoveRule.java | 4 +- .../domain/piece/move/ElephantMoveRule.java | 5 +- .../domain/piece/move/GeneralMoveRule.java | 4 +- .../java/domain/piece/move/GuardMoveRule.java | 4 +- .../java/domain/piece/move/HorseMoveRule.java | 4 +- src/main/java/domain/piece/move/MoveRule.java | 10 ++++ .../domain/piece/move/SoliderMoveRule.java | 4 +- src/test/java/domain/MoveTest.java | 42 ++++++++++++++ 12 files changed, 152 insertions(+), 18 deletions(-) create mode 100644 src/test/java/domain/MoveTest.java diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index 85c1e9c066..d10259c85f 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -1,7 +1,10 @@ package domain.board; import domain.intersection.Intersection; +import domain.piece.move.*; import domain.point.Point; + +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -13,19 +16,50 @@ public class JanggiBoard { private static final int MAX_FILE = 9; private final Map intersections; + private final List moveRules; public JanggiBoard(IntersectionGenerator intersectionGenerator) { this.intersections = fillEmptyIntersections(); + this.moveRules = setMoveRules(); for (Intersection intersection : intersectionGenerator.makeIntersection()) { intersections.put(intersection.getPoint(), intersection); } } - private static Map fillEmptyIntersections() { - return getAllPoints() - .collect(Collectors.toMap(point -> point, Intersection::empty)); + public void tryToMove(Point start, Point end) { + Intersection from = findIntersection(start); + Intersection to = findIntersection(end); + + validateMoveRule(from, to); + move(to, from); + } + + private void move(Intersection to, Intersection from) { + to.arrive(from); + from.leave(); + } + + private void validateMoveRule(Intersection from, Intersection to) { + MoveRule moveRule = findMoveRule(from); + List possiblePoints = moveRule.findPossiblePoints(from, to); + List path = findPath(possiblePoints); + moveRule.checkMoveRule(from, path); + } + + public MoveRule findMoveRule(Intersection from) { + return moveRules.stream() + .filter(moveRule -> moveRule.support(from)) + .findFirst() + .orElse(null); } + private List findPath(List possiblePoints) { + return possiblePoints.stream() + .map(this::findIntersection) + .toList(); + } + + private static Stream getAllPoints() { return range(MAX_ROW).boxed() .flatMap(row -> range(MAX_FILE).mapToObj(f -> new Point(row, f))); @@ -39,4 +73,22 @@ public Intersection findIntersection(Point point) { return intersections.get(point); } + private List setMoveRules() { + return List.of( + new ChariotMoveRule(), + new GeneralMoveRule(), + new GuardMoveRule(), + new ElephantMoveRule(), + new SoliderMoveRule(), + new CannonMoveRule(), + new HorseMoveRule() + ); + } + + private Map fillEmptyIntersections() { + return getAllPoints() + .collect(Collectors.toMap(point -> point, Intersection::empty)); + } + + } diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index f9e26b1766..4690174e21 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -2,8 +2,11 @@ import domain.piece.NonePiece; import domain.piece.Piece; +import domain.piece.PieceType; import domain.point.Point; +import java.util.Objects; + public class Intersection { private final Point point; @@ -18,6 +21,14 @@ public static Intersection empty(Point point) { return new Intersection(point, new NonePiece()); } + public void arrive(Intersection from) { + this.piece = from.piece; + } + + public void leave() { + piece = new NonePiece(); + } + public Point getPoint() { return point; } @@ -26,6 +37,10 @@ public boolean isSamePiece(Intersection intersection) { return this.piece.equals(intersection.piece); } + public boolean isSamePiece(PieceType pieceType) { + return this.piece.isSamePiece(pieceType); + } + public boolean isSameTeam(Intersection to) { return piece.isSameTeam(to.piece); } @@ -38,4 +53,16 @@ public boolean isChoIntersection() { return piece.isCho(); } + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Intersection that = (Intersection) o; + return Objects.equals(point, that.point) && Objects.equals(piece, that.piece); + } + + @Override + public int hashCode() { + return Objects.hash(point, piece); + } + } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index a7f535df99..9b9bf3db4a 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -27,6 +27,10 @@ public boolean isCho() { return this.team == Team.CHO; } + public boolean isSamePiece(PieceType pieceType) { + return this.pieceType == pieceType; + } + public boolean hasPiece() { return this.pieceType != PieceType.NONE; } diff --git a/src/main/java/domain/piece/move/CannonMoveRule.java b/src/main/java/domain/piece/move/CannonMoveRule.java index 5c188dfd13..e62b90dbc6 100644 --- a/src/main/java/domain/piece/move/CannonMoveRule.java +++ b/src/main/java/domain/piece/move/CannonMoveRule.java @@ -16,8 +16,8 @@ public CannonMoveRule() { super(PieceType.CANNON, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } public List findPossiblePoints(Intersection from, Intersection to) { diff --git a/src/main/java/domain/piece/move/ChariotMoveRule.java b/src/main/java/domain/piece/move/ChariotMoveRule.java index 75cfec76b8..c3d2971d61 100644 --- a/src/main/java/domain/piece/move/ChariotMoveRule.java +++ b/src/main/java/domain/piece/move/ChariotMoveRule.java @@ -20,8 +20,8 @@ public ChariotMoveRule() { super(PieceType.CHARIOT, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } public List findPossiblePoints(Intersection from, Intersection to) { diff --git a/src/main/java/domain/piece/move/ElephantMoveRule.java b/src/main/java/domain/piece/move/ElephantMoveRule.java index 8f5479052f..3bbdda2fb2 100644 --- a/src/main/java/domain/piece/move/ElephantMoveRule.java +++ b/src/main/java/domain/piece/move/ElephantMoveRule.java @@ -20,10 +20,9 @@ public ElephantMoveRule() { super(PieceType.ELEPHANT, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } - public List findPossiblePoints(Intersection from, Intersection to) { return directions.findPoints(from.getPoint(), to.getPoint()); } diff --git a/src/main/java/domain/piece/move/GeneralMoveRule.java b/src/main/java/domain/piece/move/GeneralMoveRule.java index 3066037be4..bcbed153aa 100644 --- a/src/main/java/domain/piece/move/GeneralMoveRule.java +++ b/src/main/java/domain/piece/move/GeneralMoveRule.java @@ -17,8 +17,8 @@ public GeneralMoveRule() { super(PieceType.GENERAL, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } public List findPossiblePoints(Intersection from, Intersection to) { diff --git a/src/main/java/domain/piece/move/GuardMoveRule.java b/src/main/java/domain/piece/move/GuardMoveRule.java index a84e93c22b..1b31a9d411 100644 --- a/src/main/java/domain/piece/move/GuardMoveRule.java +++ b/src/main/java/domain/piece/move/GuardMoveRule.java @@ -14,8 +14,8 @@ public GuardMoveRule() { super(PieceType.GUARD, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } public List findPossiblePoints(Intersection from, Intersection to) { diff --git a/src/main/java/domain/piece/move/HorseMoveRule.java b/src/main/java/domain/piece/move/HorseMoveRule.java index 86556bdabd..5404bb77e7 100644 --- a/src/main/java/domain/piece/move/HorseMoveRule.java +++ b/src/main/java/domain/piece/move/HorseMoveRule.java @@ -15,8 +15,8 @@ public HorseMoveRule() { super(PieceType.HORSE, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } public List findPossiblePoints(Intersection from, Intersection to) { diff --git a/src/main/java/domain/piece/move/MoveRule.java b/src/main/java/domain/piece/move/MoveRule.java index fc81cbce2a..958c7c2391 100644 --- a/src/main/java/domain/piece/move/MoveRule.java +++ b/src/main/java/domain/piece/move/MoveRule.java @@ -1,6 +1,10 @@ package domain.piece.move; +import domain.intersection.Intersection; import domain.piece.PieceType; +import domain.point.Point; + +import java.util.List; public abstract class MoveRule { @@ -16,4 +20,10 @@ public MoveRule(PieceType pieceType, Directions directions) { this.directions = directions; } + public abstract boolean support(Intersection from); + + public abstract List findPossiblePoints(Intersection from, Intersection to); + + public abstract boolean checkMoveRule(Intersection from, List path); + } diff --git a/src/main/java/domain/piece/move/SoliderMoveRule.java b/src/main/java/domain/piece/move/SoliderMoveRule.java index 966a0b099b..2c1c458bea 100644 --- a/src/main/java/domain/piece/move/SoliderMoveRule.java +++ b/src/main/java/domain/piece/move/SoliderMoveRule.java @@ -17,8 +17,8 @@ public SoliderMoveRule() { super(PieceType.SOLDIER, initializeDirections()); } - public boolean support(PieceType pieceType) { - return this.pieceType == pieceType; + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); } public List findPossiblePoints(Intersection from, Intersection to) { diff --git a/src/test/java/domain/MoveTest.java b/src/test/java/domain/MoveTest.java new file mode 100644 index 0000000000..b0703a854a --- /dev/null +++ b/src/test/java/domain/MoveTest.java @@ -0,0 +1,42 @@ +package domain; + +import domain.board.JanggiBoard; +import domain.board.JanggiGenerator; +import domain.fixture.TestIntersectionGenerator; +import domain.intersection.Intersection; +import domain.piece.Chariot; +import domain.piece.Soldier; +import domain.piece.Team; +import domain.point.Point; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class MoveTest { + + @Test + @DisplayName("이동이 끝난 뒤 출발지는 비어있고, 도착지는 기물이 존재한다.") + void shouldMovePieceToDestinationAndLeaveSourceEmpty(){ + Point start = new Point(0, 0); + Point end = new Point(3, 0); + + Chariot chariot = new Chariot(Team.CHO); + Soldier soldier = new Soldier(Team.HAN); + + Intersection from = new Intersection(start, chariot); + Intersection to = new Intersection(end, soldier); + + JanggiBoard janggiBoard = new JanggiBoard(new TestIntersectionGenerator(List.of(from, to))); + + janggiBoard.tryToMove(start, end); + + Intersection expectedEmpty = Intersection.empty(start); + Intersection expectedChariot = new Intersection(end, chariot); + + Assertions.assertThat(from).isEqualTo(expectedEmpty); + Assertions.assertThat(to).isEqualTo(expectedChariot); + } + +} From 9c3417baeae20cffe4c7e8ae8126857ec4cf9588 Mon Sep 17 00:00:00 2001 From: poketopa Date: Fri, 27 Mar 2026 23:21:45 +0900 Subject: [PATCH 30/41] =?UTF-8?q?chore:=20=EB=A6=B0=ED=8C=85=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/JanggiBoard.java | 29 ++--- .../java/domain/board/JanggiGenerator.java | 13 ++- .../domain/intersection/Intersection.java | 5 +- .../domain/piece/move/CannonMoveRule.java | 100 +++++++++--------- .../domain/piece/move/ChariotMoveRule.java | 72 ++++++------- .../java/domain/piece/move/Direction.java | 7 +- .../java/domain/piece/move/Directions.java | 7 +- .../domain/piece/move/ElephantMoveRule.java | 27 ++--- .../domain/piece/move/GeneralMoveRule.java | 33 +++--- .../java/domain/piece/move/GuardMoveRule.java | 30 +++--- .../java/domain/piece/move/HorseMoveRule.java | 39 ++++--- src/main/java/domain/piece/move/MoveRule.java | 3 +- .../domain/piece/move/SoliderMoveRule.java | 29 +++-- src/main/java/domain/point/Point.java | 2 +- src/test/java/domain/BoardTest.java | 1 - src/test/java/domain/DirectionTest.java | 7 +- src/test/java/domain/MoveTest.java | 6 +- .../java/domain/rule/CannonMoveRuleTest.java | 4 +- .../java/domain/rule/ChariotMoveRuleTest.java | 20 ++-- .../java/domain/rule/GeneralMoveRuleTest.java | 3 +- .../java/domain/rule/GuardMoveRuleTest.java | 5 +- .../java/domain/rule/HorseMoveRuleTest.java | 3 +- .../java/domain/rule/SoliderMoveRuleTest.java | 3 +- 23 files changed, 222 insertions(+), 226 deletions(-) diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index d10259c85f..ddedefd203 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -1,9 +1,15 @@ package domain.board; import domain.intersection.Intersection; -import domain.piece.move.*; +import domain.piece.move.CannonMoveRule; +import domain.piece.move.ChariotMoveRule; +import domain.piece.move.ElephantMoveRule; +import domain.piece.move.GeneralMoveRule; +import domain.piece.move.GuardMoveRule; +import domain.piece.move.HorseMoveRule; +import domain.piece.move.MoveRule; +import domain.piece.move.SoliderMoveRule; import domain.point.Point; - import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -26,6 +32,15 @@ public JanggiBoard(IntersectionGenerator intersectionGenerator) { } } + private static Stream getAllPoints() { + return range(MAX_ROW).boxed() + .flatMap(row -> range(MAX_FILE).mapToObj(f -> new Point(row, f))); + } + + private static IntStream range(int maxRange) { + return IntStream.range(0, maxRange); + } + public void tryToMove(Point start, Point end) { Intersection from = findIntersection(start); Intersection to = findIntersection(end); @@ -59,16 +74,6 @@ private List findPath(List possiblePoints) { .toList(); } - - private static Stream getAllPoints() { - return range(MAX_ROW).boxed() - .flatMap(row -> range(MAX_FILE).mapToObj(f -> new Point(row, f))); - } - - private static IntStream range(int maxRange) { - return IntStream.range(0, maxRange); - } - public Intersection findIntersection(Point point) { return intersections.get(point); } diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java index 79ef8d936b..e0947391cd 100644 --- a/src/main/java/domain/board/JanggiGenerator.java +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -1,9 +1,16 @@ package domain.board; import domain.intersection.Intersection; -import domain.piece.*; +import domain.piece.Cannon; +import domain.piece.Chariot; +import domain.piece.Elephant; +import domain.piece.General; +import domain.piece.Guard; +import domain.piece.Horse; +import domain.piece.Piece; +import domain.piece.Soldier; +import domain.piece.Team; import domain.point.Point; - import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -20,7 +27,7 @@ public class JanggiGenerator implements IntersectionGenerator { private static final List DEFAULT_SOLDIER_FILES = List.of(0, 2, 4, 6, 8); private static final List DEFAULT_CANNON_FILES = List.of(1, 7); private static final List DEFAULT_GENERAL_FILES = List.of(4); - private static final List DEFAULT_GUARD_FILES = List.of(3,5); + private static final List DEFAULT_GUARD_FILES = List.of(3, 5); private static final List DEFAULT_CHARIOT_FILES = List.of(0, 8); private final Formation hanFormation; diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index 4690174e21..ae23a85184 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -4,7 +4,6 @@ import domain.piece.Piece; import domain.piece.PieceType; import domain.point.Point; - import java.util.Objects; public class Intersection { @@ -55,7 +54,9 @@ public boolean isChoIntersection() { @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; + if (o == null || getClass() != o.getClass()) { + return false; + } Intersection that = (Intersection) o; return Objects.equals(point, that.point) && Objects.equals(piece, that.piece); } diff --git a/src/main/java/domain/piece/move/CannonMoveRule.java b/src/main/java/domain/piece/move/CannonMoveRule.java index e62b90dbc6..88e667f39f 100644 --- a/src/main/java/domain/piece/move/CannonMoveRule.java +++ b/src/main/java/domain/piece/move/CannonMoveRule.java @@ -1,71 +1,27 @@ package domain.piece.move; +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.UP; + import domain.intersection.Intersection; import domain.piece.PieceType; import domain.point.Point; - import java.util.List; -import static domain.piece.move.Vector.*; -import static domain.piece.move.Vector.LEFT; -import static domain.piece.move.Vector.RIGHT; - -public class CannonMoveRule extends MoveRule{ +public class CannonMoveRule extends MoveRule { public CannonMoveRule() { super(PieceType.CANNON, initializeDirections()); } - public boolean support(Intersection from) { - return from.isSamePiece(pieceType); - } - - public List findPossiblePoints(Intersection from, Intersection to) { - return directions.findPoints(from.getPoint(), to.getPoint()); - } - - public boolean checkMoveRule(Intersection from, List path) { - Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 - validateObstacleCondition(from, path); // 장애물 검사 - validateDestinationIsNotCannon(from, to); // 도착지가 포인지 확인한다. - return true; - } - - // 같은 팀 인지 확인 - private void validateIsSameTeam(Intersection from, Intersection to) { - if (from.isSameTeam(to)) { - throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); - } - } - - private void validateObstacleCondition(Intersection from, List path) { - List obstacles = path.subList(0, path.size() - 1).stream() - .filter(Intersection::hasPiece) - .toList(); - - validateObstacleIsOnly(obstacles); - validateObstacleIsNotCannon(from, obstacles); - } - - private void validateObstacleIsOnly(List list) { - if (list.size() != 1) { - throw new IllegalArgumentException("포는 반드시 기물 하나를 넘어야 합니다."); - } - } - private static void validateObstacleIsNotCannon(Intersection from, List list) { if (list.getFirst().isSamePiece(from)) { throw new IllegalArgumentException("포는 포를 넘어갈 수 없습니다."); } } - private void validateDestinationIsNotCannon(Intersection from, Intersection to) { - if (from.isSamePiece(to)) { - throw new IllegalArgumentException("포는 포를 공격할 수 없습니다."); - } - } - public static Directions initializeDirections() { return new Directions(List.of( new Direction(List.of(UP)), @@ -108,4 +64,48 @@ public static Directions initializeDirections() { )); } + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateObstacleCondition(from, path); // 장애물 검사 + validateDestinationIsNotCannon(from, to); // 도착지가 포인지 확인한다. + return true; + } + + // 같은 팀 인지 확인 + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + private void validateObstacleCondition(Intersection from, List path) { + List obstacles = path.subList(0, path.size() - 1).stream() + .filter(Intersection::hasPiece) + .toList(); + + validateObstacleIsOnly(obstacles); + validateObstacleIsNotCannon(from, obstacles); + } + + private void validateObstacleIsOnly(List list) { + if (list.size() != 1) { + throw new IllegalArgumentException("포는 반드시 기물 하나를 넘어야 합니다."); + } + } + + private void validateDestinationIsNotCannon(Intersection from, Intersection to) { + if (from.isSamePiece(to)) { + throw new IllegalArgumentException("포는 포를 공격할 수 없습니다."); + } + } + } diff --git a/src/main/java/domain/piece/move/ChariotMoveRule.java b/src/main/java/domain/piece/move/ChariotMoveRule.java index c3d2971d61..2f99f8d532 100644 --- a/src/main/java/domain/piece/move/ChariotMoveRule.java +++ b/src/main/java/domain/piece/move/ChariotMoveRule.java @@ -2,11 +2,7 @@ import static domain.piece.move.Vector.DOWN; import static domain.piece.move.Vector.LEFT; -import static domain.piece.move.Vector.LEFT_DOWN; -import static domain.piece.move.Vector.LEFT_UP; import static domain.piece.move.Vector.RIGHT; -import static domain.piece.move.Vector.RIGHT_DOWN; -import static domain.piece.move.Vector.RIGHT_UP; import static domain.piece.move.Vector.UP; import domain.intersection.Intersection; @@ -14,45 +10,12 @@ import domain.point.Point; import java.util.List; -public class ChariotMoveRule extends MoveRule{ +public class ChariotMoveRule extends MoveRule { public ChariotMoveRule() { super(PieceType.CHARIOT, initializeDirections()); } - public boolean support(Intersection from) { - return from.isSamePiece(pieceType); - } - - public List findPossiblePoints(Intersection from, Intersection to) { - return directions.findPoints(from.getPoint(), to.getPoint()); - } - - public boolean checkMoveRule(Intersection from, List path) { - Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 - validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 - return true; - } - - // 같은 팀 인지 확인 - private void validateIsSameTeam(Intersection from, Intersection to) { - if (from.isSameTeam(to)) { - throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); - } - } - - private void validateObstacleCondition(List path) { - List routeWithoutTarget = path.subList(0, path.size() - 1); - - boolean hasObstacle = routeWithoutTarget.stream() - .anyMatch(Intersection::hasPiece); - - if (hasObstacle) { - throw new IllegalArgumentException("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); - } - } - public static Directions initializeDirections() { return new Directions(List.of( new Direction(List.of(UP)), @@ -95,4 +58,37 @@ public static Directions initializeDirections() { )); } + public boolean support(Intersection from) { + return from.isSamePiece(pieceType); + } + + public List findPossiblePoints(Intersection from, Intersection to) { + return directions.findPoints(from.getPoint(), to.getPoint()); + } + + public boolean checkMoveRule(Intersection from, List path) { + Intersection to = path.getLast(); + validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + return true; + } + + // 같은 팀 인지 확인 + private void validateIsSameTeam(Intersection from, Intersection to) { + if (from.isSameTeam(to)) { + throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); + } + } + + private void validateObstacleCondition(List path) { + List routeWithoutTarget = path.subList(0, path.size() - 1); + + boolean hasObstacle = routeWithoutTarget.stream() + .anyMatch(Intersection::hasPiece); + + if (hasObstacle) { + throw new IllegalArgumentException("이동 경로에 다른 기물이 있어 통과할 수 없습니다."); + } + } + } diff --git a/src/main/java/domain/piece/move/Direction.java b/src/main/java/domain/piece/move/Direction.java index 8052d84486..ef6142635e 100644 --- a/src/main/java/domain/piece/move/Direction.java +++ b/src/main/java/domain/piece/move/Direction.java @@ -1,7 +1,6 @@ package domain.piece.move; import domain.point.Point; - import java.util.ArrayList; import java.util.List; @@ -17,7 +16,7 @@ public boolean canReach(Point start, Point target) { int dy = vectors.stream().mapToInt(Vector::dy).sum(); int dx = vectors.stream().mapToInt(Vector::dx).sum(); - if(start.canMake(dy, dx)){ + if (start.canMake(dy, dx)) { Point destination = start.movePoint(dy, dx); return destination.equals(target); } @@ -25,9 +24,9 @@ public boolean canReach(Point start, Point target) { return false; } - public List getPoints(Point current){ + public List getPoints(Point current) { List points = new ArrayList<>(); - for(Vector vector : this.vectors){ + for (Vector vector : this.vectors) { current = current.next(vector); points.add(current); } diff --git a/src/main/java/domain/piece/move/Directions.java b/src/main/java/domain/piece/move/Directions.java index 100f64eb30..5d1f44749f 100644 --- a/src/main/java/domain/piece/move/Directions.java +++ b/src/main/java/domain/piece/move/Directions.java @@ -1,7 +1,6 @@ package domain.piece.move; import domain.point.Point; -import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -17,9 +16,9 @@ public List getDirections() { return Collections.unmodifiableList(directions); } - public List findPoints(Point from, Point to){ - for(Direction direction : directions){ - if(direction.canReach(from, to)){ + public List findPoints(Point from, Point to) { + for (Direction direction : directions) { + if (direction.canReach(from, to)) { return direction.getPoints(from); } } diff --git a/src/main/java/domain/piece/move/ElephantMoveRule.java b/src/main/java/domain/piece/move/ElephantMoveRule.java index 3bbdda2fb2..7273c7c5a3 100644 --- a/src/main/java/domain/piece/move/ElephantMoveRule.java +++ b/src/main/java/domain/piece/move/ElephantMoveRule.java @@ -20,9 +20,23 @@ public ElephantMoveRule() { super(PieceType.ELEPHANT, initializeDirections()); } + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP, LEFT_UP, LEFT_UP)), + new Direction(List.of(UP, RIGHT_UP, RIGHT_UP)), + new Direction(List.of(DOWN, LEFT_DOWN, LEFT_DOWN)), + new Direction(List.of(DOWN, RIGHT_DOWN, RIGHT_DOWN)), + new Direction(List.of(LEFT, LEFT_UP, LEFT_UP)), + new Direction(List.of(LEFT, LEFT_DOWN, LEFT_DOWN)), + new Direction(List.of(RIGHT, RIGHT_UP, RIGHT_UP)), + new Direction(List.of(RIGHT, RIGHT_DOWN, RIGHT_DOWN)) + )); + } + public boolean support(Intersection from) { return from.isSamePiece(pieceType); } + public List findPossiblePoints(Intersection from, Intersection to) { return directions.findPoints(from.getPoint(), to.getPoint()); } @@ -52,17 +66,4 @@ private void validateObstacleCondition(List path) { } } - public static Directions initializeDirections() { - return new Directions(List.of( - new Direction(List.of(UP, LEFT_UP, LEFT_UP)), - new Direction(List.of(UP, RIGHT_UP, RIGHT_UP)), - new Direction(List.of(DOWN, LEFT_DOWN, LEFT_DOWN)), - new Direction(List.of(DOWN, RIGHT_DOWN, RIGHT_DOWN)), - new Direction(List.of(LEFT, LEFT_UP, LEFT_UP)), - new Direction(List.of(LEFT, LEFT_DOWN, LEFT_DOWN)), - new Direction(List.of(RIGHT, RIGHT_UP, RIGHT_UP)), - new Direction(List.of(RIGHT, RIGHT_DOWN, RIGHT_DOWN)) - )); - } - } diff --git a/src/main/java/domain/piece/move/GeneralMoveRule.java b/src/main/java/domain/piece/move/GeneralMoveRule.java index bcbed153aa..c43cc28aef 100644 --- a/src/main/java/domain/piece/move/GeneralMoveRule.java +++ b/src/main/java/domain/piece/move/GeneralMoveRule.java @@ -1,22 +1,31 @@ package domain.piece.move; +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.UP; + import domain.intersection.Intersection; import domain.piece.PieceType; import domain.point.Point; - import java.util.List; -import static domain.piece.move.Vector.*; -import static domain.piece.move.Vector.LEFT; -import static domain.piece.move.Vector.RIGHT; -import static domain.piece.move.Vector.UP; - -public class GeneralMoveRule extends MoveRule{ +public class GeneralMoveRule extends MoveRule { public GeneralMoveRule() { super(PieceType.GENERAL, initializeDirections()); } + // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP)), + new Direction(List.of(DOWN)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT))) + ); + } + public boolean support(Intersection from) { return from.isSamePiece(pieceType); } @@ -37,14 +46,4 @@ private void validateIsSameTeam(Intersection from, Intersection to) { } } - // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 - public static Directions initializeDirections() { - return new Directions(List.of( - new Direction(List.of(UP)), - new Direction(List.of(DOWN)), - new Direction(List.of(RIGHT)), - new Direction(List.of(LEFT))) - ); - } - } diff --git a/src/main/java/domain/piece/move/GuardMoveRule.java b/src/main/java/domain/piece/move/GuardMoveRule.java index 1b31a9d411..91b6df18f0 100644 --- a/src/main/java/domain/piece/move/GuardMoveRule.java +++ b/src/main/java/domain/piece/move/GuardMoveRule.java @@ -1,19 +1,31 @@ package domain.piece.move; +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.UP; + import domain.intersection.Intersection; import domain.piece.PieceType; import domain.point.Point; - import java.util.List; -import static domain.piece.move.Vector.*; - -public class GuardMoveRule extends MoveRule{ +public class GuardMoveRule extends MoveRule { public GuardMoveRule() { super(PieceType.GUARD, initializeDirections()); } + // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP)), + new Direction(List.of(DOWN)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT))) + ); + } + public boolean support(Intersection from) { return from.isSamePiece(pieceType); } @@ -34,14 +46,4 @@ private void validateIsSameTeam(Intersection from, Intersection to) { } } - // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 - public static Directions initializeDirections() { - return new Directions(List.of( - new Direction(List.of(UP)), - new Direction(List.of(DOWN)), - new Direction(List.of(RIGHT)), - new Direction(List.of(LEFT))) - ); - } - } diff --git a/src/main/java/domain/piece/move/HorseMoveRule.java b/src/main/java/domain/piece/move/HorseMoveRule.java index 5404bb77e7..53ba4acf0a 100644 --- a/src/main/java/domain/piece/move/HorseMoveRule.java +++ b/src/main/java/domain/piece/move/HorseMoveRule.java @@ -1,13 +1,18 @@ package domain.piece.move; +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.LEFT_DOWN; +import static domain.piece.move.Vector.LEFT_UP; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.RIGHT_DOWN; +import static domain.piece.move.Vector.RIGHT_UP; +import static domain.piece.move.Vector.UP; + import domain.intersection.Intersection; import domain.piece.PieceType; import domain.point.Point; - import java.util.List; -import java.util.stream.IntStream; - -import static domain.piece.move.Vector.*; public class HorseMoveRule extends MoveRule { @@ -15,6 +20,19 @@ public HorseMoveRule() { super(PieceType.HORSE, initializeDirections()); } + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(UP, LEFT_UP)), + new Direction(List.of(UP, RIGHT_UP)), + new Direction(List.of(DOWN, LEFT_DOWN)), + new Direction(List.of(DOWN, RIGHT_DOWN)), + new Direction(List.of(LEFT, LEFT_UP)), + new Direction(List.of(LEFT, LEFT_DOWN)), + new Direction(List.of(RIGHT, RIGHT_UP)), + new Direction(List.of(RIGHT, RIGHT_DOWN)) + )); + } + public boolean support(Intersection from) { return from.isSamePiece(pieceType); } @@ -48,17 +66,4 @@ private void validateObstacleCondition(List path) { } } - public static Directions initializeDirections() { - return new Directions(List.of( - new Direction(List.of(UP, LEFT_UP)), - new Direction(List.of(UP, RIGHT_UP)), - new Direction(List.of(DOWN, LEFT_DOWN)), - new Direction(List.of(DOWN, RIGHT_DOWN)), - new Direction(List.of(LEFT, LEFT_UP)), - new Direction(List.of(LEFT, LEFT_DOWN)), - new Direction(List.of(RIGHT, RIGHT_UP)), - new Direction(List.of(RIGHT, RIGHT_DOWN)) - )); - } - } diff --git a/src/main/java/domain/piece/move/MoveRule.java b/src/main/java/domain/piece/move/MoveRule.java index 958c7c2391..45e1c8dc55 100644 --- a/src/main/java/domain/piece/move/MoveRule.java +++ b/src/main/java/domain/piece/move/MoveRule.java @@ -3,14 +3,13 @@ import domain.intersection.Intersection; import domain.piece.PieceType; import domain.point.Point; - import java.util.List; public abstract class MoveRule { /** * 어떤 피스의 이동 전략인지. - * */ + */ protected final PieceType pieceType; protected final Directions directions; diff --git a/src/main/java/domain/piece/move/SoliderMoveRule.java b/src/main/java/domain/piece/move/SoliderMoveRule.java index 2c1c458bea..ea4361b0d9 100644 --- a/src/main/java/domain/piece/move/SoliderMoveRule.java +++ b/src/main/java/domain/piece/move/SoliderMoveRule.java @@ -1,22 +1,29 @@ package domain.piece.move; +import static domain.piece.move.Vector.DOWN; +import static domain.piece.move.Vector.LEFT; +import static domain.piece.move.Vector.RIGHT; +import static domain.piece.move.Vector.UP; + import domain.intersection.Intersection; import domain.piece.PieceType; -import domain.piece.Team; import domain.point.Point; - import java.util.List; -import static domain.piece.move.Vector.*; -import static domain.piece.move.Vector.LEFT; -import static domain.piece.move.Vector.RIGHT; - public class SoliderMoveRule extends MoveRule { public SoliderMoveRule() { super(PieceType.SOLDIER, initializeDirections()); } + public static Directions initializeDirections() { + return new Directions(List.of( + new Direction(List.of(DOWN)), + new Direction(List.of(RIGHT)), + new Direction(List.of(LEFT))) + ); + } + public boolean support(Intersection from) { return from.isSamePiece(pieceType); } @@ -38,15 +45,7 @@ private void validateIsSameTeam(Intersection from, Intersection to) { } } - public static Directions initializeDirections() { - return new Directions(List.of( - new Direction(List.of(DOWN)), - new Direction(List.of(RIGHT)), - new Direction(List.of(LEFT))) - ); - } - - public Directions getDirections(Intersection from){ + public Directions getDirections(Intersection from) { if (from.isChoIntersection()) { return new Directions(List.of( new Direction(List.of(UP)), diff --git a/src/main/java/domain/point/Point.java b/src/main/java/domain/point/Point.java index d646bb674b..ef367310b4 100644 --- a/src/main/java/domain/point/Point.java +++ b/src/main/java/domain/point/Point.java @@ -13,7 +13,7 @@ public Point(int y, int x) { this.x = x; } - public boolean canMake(int y, int x){ + public boolean canMake(int y, int x) { return checkPointRange(this.y + y, this.x + x); } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 71630b3776..663c39ff02 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -11,7 +11,6 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Stream; - import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/test/java/domain/DirectionTest.java b/src/test/java/domain/DirectionTest.java index accc39884f..b5b001142d 100644 --- a/src/test/java/domain/DirectionTest.java +++ b/src/test/java/domain/DirectionTest.java @@ -4,14 +4,11 @@ import domain.piece.move.Directions; import domain.piece.move.Vector; import domain.point.Point; -import java.awt.dnd.DragGestureEvent; -import java.util.ArrayList; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - public class DirectionTest { @Test @@ -28,7 +25,7 @@ void shouldReachTargetWhenFollowingDirections() { @Test @DisplayName("주어진 경로의 좌표들을 최종적으로 반환하는지 확인한다.") - void returnAllPointsAlongDestination(){ + void returnAllPointsAlongDestination() { Direction direction1 = new Direction(List.of(Vector.UP, Vector.LEFT_UP)); Direction direction2 = new Direction(List.of(Vector.DOWN, Vector.RIGHT_DOWN)); Point from = new Point(0, 0); diff --git a/src/test/java/domain/MoveTest.java b/src/test/java/domain/MoveTest.java index b0703a854a..53bbc25dd7 100644 --- a/src/test/java/domain/MoveTest.java +++ b/src/test/java/domain/MoveTest.java @@ -1,24 +1,22 @@ package domain; import domain.board.JanggiBoard; -import domain.board.JanggiGenerator; import domain.fixture.TestIntersectionGenerator; import domain.intersection.Intersection; import domain.piece.Chariot; import domain.piece.Soldier; import domain.piece.Team; import domain.point.Point; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - public class MoveTest { @Test @DisplayName("이동이 끝난 뒤 출발지는 비어있고, 도착지는 기물이 존재한다.") - void shouldMovePieceToDestinationAndLeaveSourceEmpty(){ + void shouldMovePieceToDestinationAndLeaveSourceEmpty() { Point start = new Point(0, 0); Point end = new Point(3, 0); diff --git a/src/test/java/domain/rule/CannonMoveRuleTest.java b/src/test/java/domain/rule/CannonMoveRuleTest.java index 9bfc4d1161..36d74801db 100644 --- a/src/test/java/domain/rule/CannonMoveRuleTest.java +++ b/src/test/java/domain/rule/CannonMoveRuleTest.java @@ -6,12 +6,11 @@ import domain.piece.Team; import domain.piece.move.CannonMoveRule; import domain.point.Point; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - class CannonMoveRuleTest { final Point start = new Point(0, 0); @@ -146,7 +145,6 @@ void shouldThrowExceptionWhenCannonAttackCannon() { Intersection obstacle = new Intersection(middlePoint6, new Chariot(sameTeam)); Intersection to = new Intersection(end, new Cannon(anotherTeam)); - CannonMoveRule cannonMoveRule = new CannonMoveRule(); Assertions.assertThatThrownBy(() -> { diff --git a/src/test/java/domain/rule/ChariotMoveRuleTest.java b/src/test/java/domain/rule/ChariotMoveRuleTest.java index 70ab25034c..324d92ebe1 100644 --- a/src/test/java/domain/rule/ChariotMoveRuleTest.java +++ b/src/test/java/domain/rule/ChariotMoveRuleTest.java @@ -2,10 +2,8 @@ import domain.intersection.Intersection; import domain.piece.Chariot; -import domain.piece.Elephant; import domain.piece.Team; import domain.piece.move.ChariotMoveRule; -import domain.piece.move.ElephantMoveRule; import domain.point.Point; import java.util.List; import org.assertj.core.api.Assertions; @@ -92,15 +90,15 @@ void chariotCanMove_WhenNoObstacle_AndDestinationIsEmpty() { ChariotMoveRule chariotMoveRule = new ChariotMoveRule(); Assertions.assertThat( - chariotMoveRule.checkMoveRule(from, List.of(intersection1, - intersection2, - intersection3, - intersection4, - intersection5, - intersection6, - intersection7, - intersection8, - to))) + chariotMoveRule.checkMoveRule(from, List.of(intersection1, + intersection2, + intersection3, + intersection4, + intersection5, + intersection6, + intersection7, + intersection8, + to))) .isTrue(); } diff --git a/src/test/java/domain/rule/GeneralMoveRuleTest.java b/src/test/java/domain/rule/GeneralMoveRuleTest.java index c8510ddbde..46c99a83e8 100644 --- a/src/test/java/domain/rule/GeneralMoveRuleTest.java +++ b/src/test/java/domain/rule/GeneralMoveRuleTest.java @@ -6,12 +6,11 @@ import domain.piece.Team; import domain.piece.move.GeneralMoveRule; import domain.point.Point; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - public class GeneralMoveRuleTest { @Test diff --git a/src/test/java/domain/rule/GuardMoveRuleTest.java b/src/test/java/domain/rule/GuardMoveRuleTest.java index b494a35656..7c7931cc75 100644 --- a/src/test/java/domain/rule/GuardMoveRuleTest.java +++ b/src/test/java/domain/rule/GuardMoveRuleTest.java @@ -1,19 +1,16 @@ package domain.rule; import domain.intersection.Intersection; -import domain.piece.General; import domain.piece.Guard; import domain.piece.Soldier; import domain.piece.Team; -import domain.piece.move.GeneralMoveRule; import domain.piece.move.GuardMoveRule; import domain.point.Point; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - public class GuardMoveRuleTest { @Test diff --git a/src/test/java/domain/rule/HorseMoveRuleTest.java b/src/test/java/domain/rule/HorseMoveRuleTest.java index d6c534506a..78479d6585 100644 --- a/src/test/java/domain/rule/HorseMoveRuleTest.java +++ b/src/test/java/domain/rule/HorseMoveRuleTest.java @@ -5,12 +5,11 @@ import domain.piece.Team; import domain.piece.move.HorseMoveRule; import domain.point.Point; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - public class HorseMoveRuleTest { @Test diff --git a/src/test/java/domain/rule/SoliderMoveRuleTest.java b/src/test/java/domain/rule/SoliderMoveRuleTest.java index 36cdf345fa..f063cd082f 100644 --- a/src/test/java/domain/rule/SoliderMoveRuleTest.java +++ b/src/test/java/domain/rule/SoliderMoveRuleTest.java @@ -6,12 +6,11 @@ import domain.piece.move.SoliderMoveRule; import domain.piece.move.Vector; import domain.point.Point; +import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import java.util.List; - public class SoliderMoveRuleTest { @Test From 93447f84914f6488ab304f5f103b00ab2ed6919e Mon Sep 17 00:00:00 2001 From: poketopa Date: Fri, 27 Mar 2026 23:29:30 +0900 Subject: [PATCH 31/41] =?UTF-8?q?docs(README):=20=EB=A6=AC=EB=93=9C?= =?UTF-8?q?=EB=AF=B8=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/README.md b/README.md index 9775dda0ae..4512987c62 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,75 @@ # java-janggi 장기 미션 저장소 + +### 기능 요구사항 체크리스트 + +#### step 1 +- [x] 10x9 장기판 좌표를 `Point(y, x)`로 표현하고, 범위를 벗어난 좌표 생성 시 예외를 발생시킨다. +- [x] 기물 타입(`PieceType`)과 진영(`Team`)을 분리해 도메인 모델링한다. +- [x] 빈 칸을 `NonePiece`로 포장해 `Intersection.empty()`로 관리한다. +- [x] 장기판 초기화 시 전체 좌표를 빈 칸으로 채운 뒤, 생성기(`IntersectionGenerator`)가 전달한 기물을 배치한다. +- [x] 초/한 기본 배치(졸, 포, 장군, 사, 차)를 자동 생성한다. +- [x] 상/마 차림(`Formation`) 4가지를 지원하고, 진영별로 대칭 배치한다. +- [x] `Formation.valueOf(int)`로 입력 숫자를 차림 enum으로 변환한다. +- [x] 보드에서 좌표로 교차점(`Intersection`)을 조회할 수 있다. +- [x] 이동 규칙을 `MoveRule` 전략으로 분리하고, 기물 타입별 규칙 클래스를 연결한다. +- [x] 이동 경로를 `Direction`/`Directions`로 추상화해 “도착 가능 여부 + 경유 좌표”를 계산한다. +- [x] 차(`Chariot`)는 상하좌우 직선 이동만 가능하며, 경로 중간 장애물이 있으면 이동할 수 없다. +- [x] 마(`Horse`)는 2단계 경로(멱) 중 중간 칸이 막히면 이동할 수 없다. +- [x] 상(`Elephant`)은 3단계 경로 중 중간 칸이 막히면 이동할 수 없다. +- [x] 포(`Cannon`)는 정확히 1개의 장애물을 넘어야 하며, 포를 넘거나 포를 공격할 수 없다. +- [x] 장군(`General`)과 사(`Guard`)는 1칸 상하좌우 이동을 지원한다. +- [x] 졸(`Soldier`)은 좌/우 + 전진 이동을 지원하며, 진영에 따라 전진 방향이 다르다. +- [x] 같은 팀 기물이 있는 칸으로는 이동할 수 없다. +- [x] `JanggiBoard.tryToMove()` 수행 시 도착지는 출발 기물로 갱신되고, 출발지는 빈 칸이 된다. + +### 주요 로직 요약 + +#### step 1 +- **보드 생성** + - `JanggiBoard`가 10x9 전체 좌표를 `Intersection.empty()`로 초기화한다. +- **초기 기물 배치** + - `JanggiGenerator`가 진영(`CHO`, `HAN`)별 기본 행/열 규칙으로 기물을 만든다. + - 상/마는 `Formation`에 정의된 열 인덱스 조합으로 배치한다. +- **좌표/교차점 모델링** + - `Point`는 생성 시 범위 검증을 수행하고, `next(Vector)`로 이동 좌표를 계산한다. + - `Intersection`은 기물 도착(`arrive`)과 이탈(`leave`) 책임을 가진다. +- **이동 규칙 선택** + - 보드는 출발 지점의 기물 타입을 기준으로 `MoveRule` 구현체를 선택한다. +- **경로 계산** + - 규칙별 `Directions.findPoints(from, to)`로 목적지까지의 경유 좌표 목록을 만든다. +- **규칙 검증** + - 공통적으로 같은 팀 도착지 여부를 검증한다. + - 차/마/상은 경로 장애물 조건을 검증한다. + - 포는 “장애물 1개 필수”, “포 넘기/포 공격 금지”를 추가 검증한다. +- **실제 이동 반영** + - 검증 통과 시 도착지 `arrive(from)`, 출발지 `leave()` 순서로 상태를 갱신한다. + +### 기물별 이동 규칙 정리 + +- **차(`Chariot`)** + - 상/하/좌/우 직선 다칸 이동 + - 도착지 아군 금지 + - 경로 중간 장애물 금지 +- **포(`Cannon`)** + - 상/하/좌/우 직선 이동 + - 중간 장애물 정확히 1개 필요 + - 장애물/도착지가 포인 경우 금지 + - 도착지 아군 금지 +- **마(`Horse`)** + - 1칸 직선 + 1칸 대각(총 2스텝) + - 중간 경유 칸 장애물 금지 + - 도착지 아군 금지 +- **상(`Elephant`)** + - 1칸 직선 + 2칸 대각(총 3스텝) + - 경유 칸 장애물 금지 + - 도착지 아군 금지 +- **장군/사(`General`/`Guard`)** + - 1칸 상하좌우 이동 + - 도착지 아군 금지 + - (궁성 내부/대각 특수 규칙 미반영) +- **졸(`Soldier`)** + - 좌/우 + 전진 이동 + - CHO는 위쪽(UP), HAN은 아래쪽(DOWN) 전진 + - 도착지 아군 금지 From a78b2948ea1f2855d8a78771ffb80b0ad2b5cba9 Mon Sep 17 00:00:00 2001 From: poketopa Date: Fri, 27 Mar 2026 23:38:00 +0900 Subject: [PATCH 32/41] =?UTF-8?q?refactor(board):=20=EC=82=BC=ED=95=AD=20?= =?UTF-8?q?=EC=97=B0=EC=82=B0=EC=9E=90=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/JanggiGenerator.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java index e0947391cd..be39537f2a 100644 --- a/src/main/java/domain/board/JanggiGenerator.java +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -87,11 +87,17 @@ private List createIntersections(int row, List files, Pie } private Formation getFormationByTeam(Team team) { - return team == Team.HAN ? hanFormation : choFormation; + if (team == Team.HAN) { + return hanFormation; + } + return choFormation; } private int getRow(Team team, int row) { - return team == Team.CHO ? MAX_ROW - row : row; + if (team == Team.CHO) { + return MAX_ROW - row; + } + return row; } } From 991559ddc969472b63ebb8fe36a713e53054b911 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sat, 28 Mar 2026 20:53:26 +0900 Subject: [PATCH 33/41] =?UTF-8?q?refactor(domain):=20=EC=82=BC=ED=95=AD?= =?UTF-8?q?=EC=97=B0=EC=82=B0=EC=9E=90=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/piece/move/Directions.java | 4 ---- src/main/java/domain/piece/move/MoveRule.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/main/java/domain/piece/move/Directions.java b/src/main/java/domain/piece/move/Directions.java index 5d1f44749f..19dcf87d63 100644 --- a/src/main/java/domain/piece/move/Directions.java +++ b/src/main/java/domain/piece/move/Directions.java @@ -12,10 +12,6 @@ public Directions(List directions) { this.directions = directions; } - public List getDirections() { - return Collections.unmodifiableList(directions); - } - public List findPoints(Point from, Point to) { for (Direction direction : directions) { if (direction.canReach(from, to)) { diff --git a/src/main/java/domain/piece/move/MoveRule.java b/src/main/java/domain/piece/move/MoveRule.java index 45e1c8dc55..0bb05c3dac 100644 --- a/src/main/java/domain/piece/move/MoveRule.java +++ b/src/main/java/domain/piece/move/MoveRule.java @@ -7,10 +7,6 @@ public abstract class MoveRule { - /** - * 어떤 피스의 이동 전략인지. - */ - protected final PieceType pieceType; protected final Directions directions; From 45f0dc6502901a0afd3af10accf86bac77b036a6 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sat, 28 Mar 2026 21:21:12 +0900 Subject: [PATCH 34/41] =?UTF-8?q?chore:=20=EC=A3=BC=EC=84=9D=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/piece/Piece.java | 2 -- src/main/java/domain/piece/PieceType.java | 16 ++++++++-------- .../java/domain/piece/move/CannonMoveRule.java | 7 +++---- .../java/domain/piece/move/ChariotMoveRule.java | 5 ++--- .../java/domain/piece/move/ElephantMoveRule.java | 5 ++--- .../java/domain/piece/move/GeneralMoveRule.java | 3 +-- .../java/domain/piece/move/GuardMoveRule.java | 3 +-- .../java/domain/piece/move/HorseMoveRule.java | 5 ++--- .../java/domain/piece/move/SoliderMoveRule.java | 2 +- src/test/java/domain/BoardTest.java | 1 - 10 files changed, 20 insertions(+), 29 deletions(-) diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 9b9bf3db4a..dac666e7cf 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -6,8 +6,6 @@ public abstract class Piece { protected final Team team; protected final PieceType pieceType; - // THINK - // protected final MoveRule moveRule; protected Piece(Team team, PieceType pieceType) { this.team = team; diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 5d23fd92ad..d2fe1ada9c 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -2,14 +2,14 @@ public enum PieceType { - GENERAL, // 궁 - CHARIOT, // 차 - CANNON, // 포 - HORSE, // 마 - ELEPHANT, // 상 - GUARD, // 사 - SOLDIER, // 졸 - NONE, // null 포장 + GENERAL, + CHARIOT, + CANNON, + HORSE, + ELEPHANT, + GUARD, + SOLDIER, + NONE, ; } diff --git a/src/main/java/domain/piece/move/CannonMoveRule.java b/src/main/java/domain/piece/move/CannonMoveRule.java index 88e667f39f..f3b3b1c835 100644 --- a/src/main/java/domain/piece/move/CannonMoveRule.java +++ b/src/main/java/domain/piece/move/CannonMoveRule.java @@ -74,13 +74,12 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 - validateObstacleCondition(from, path); // 장애물 검사 - validateDestinationIsNotCannon(from, to); // 도착지가 포인지 확인한다. + validateIsSameTeam(from, to); + validateObstacleCondition(from, path); + validateDestinationIsNotCannon(from, to); return true; } - // 같은 팀 인지 확인 private void validateIsSameTeam(Intersection from, Intersection to) { if (from.isSameTeam(to)) { throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); diff --git a/src/main/java/domain/piece/move/ChariotMoveRule.java b/src/main/java/domain/piece/move/ChariotMoveRule.java index 2f99f8d532..043a159c81 100644 --- a/src/main/java/domain/piece/move/ChariotMoveRule.java +++ b/src/main/java/domain/piece/move/ChariotMoveRule.java @@ -68,12 +68,11 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 - validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + validateIsSameTeam(from, to); + validateObstacleCondition(path); return true; } - // 같은 팀 인지 확인 private void validateIsSameTeam(Intersection from, Intersection to) { if (from.isSameTeam(to)) { throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); diff --git a/src/main/java/domain/piece/move/ElephantMoveRule.java b/src/main/java/domain/piece/move/ElephantMoveRule.java index 7273c7c5a3..0bd0b90e28 100644 --- a/src/main/java/domain/piece/move/ElephantMoveRule.java +++ b/src/main/java/domain/piece/move/ElephantMoveRule.java @@ -43,12 +43,11 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 - validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + validateIsSameTeam(from, to); + validateObstacleCondition(path); return true; } - // 같은 팀 인지 확인 private void validateIsSameTeam(Intersection from, Intersection to) { if (from.isSameTeam(to)) { throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); diff --git a/src/main/java/domain/piece/move/GeneralMoveRule.java b/src/main/java/domain/piece/move/GeneralMoveRule.java index c43cc28aef..102cf63993 100644 --- a/src/main/java/domain/piece/move/GeneralMoveRule.java +++ b/src/main/java/domain/piece/move/GeneralMoveRule.java @@ -16,7 +16,6 @@ public GeneralMoveRule() { super(PieceType.GENERAL, initializeDirections()); } - // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 public static Directions initializeDirections() { return new Directions(List.of( new Direction(List.of(UP)), @@ -36,7 +35,7 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateIsSameTeam(from, to); return true; } diff --git a/src/main/java/domain/piece/move/GuardMoveRule.java b/src/main/java/domain/piece/move/GuardMoveRule.java index 91b6df18f0..9a5bff42c5 100644 --- a/src/main/java/domain/piece/move/GuardMoveRule.java +++ b/src/main/java/domain/piece/move/GuardMoveRule.java @@ -16,7 +16,6 @@ public GuardMoveRule() { super(PieceType.GUARD, initializeDirections()); } - // NOTE 사이클 1에서는 궁성이 없으므로, 상하좌우만 설정 public static Directions initializeDirections() { return new Directions(List.of( new Direction(List.of(UP)), @@ -36,7 +35,7 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateIsSameTeam(from, to); return true; } diff --git a/src/main/java/domain/piece/move/HorseMoveRule.java b/src/main/java/domain/piece/move/HorseMoveRule.java index 53ba4acf0a..158a26ae16 100644 --- a/src/main/java/domain/piece/move/HorseMoveRule.java +++ b/src/main/java/domain/piece/move/HorseMoveRule.java @@ -43,12 +43,11 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 - validateObstacleCondition(path); // 중간에 장애물이 있는 지 확인 + validateIsSameTeam(from, to); + validateObstacleCondition(path); return true; } - // 같은 팀 인지 확인 private void validateIsSameTeam(Intersection from, Intersection to) { if (from.isSameTeam(to)) { throw new IllegalArgumentException("같은 팀의 위치로 이동할 수 없습니다."); diff --git a/src/main/java/domain/piece/move/SoliderMoveRule.java b/src/main/java/domain/piece/move/SoliderMoveRule.java index ea4361b0d9..978c1811ba 100644 --- a/src/main/java/domain/piece/move/SoliderMoveRule.java +++ b/src/main/java/domain/piece/move/SoliderMoveRule.java @@ -35,7 +35,7 @@ public List findPossiblePoints(Intersection from, Intersection to) { public boolean checkMoveRule(Intersection from, List path) { Intersection to = path.getLast(); - validateIsSameTeam(from, to); // 도착지가 같은 팀인지 확인 + validateIsSameTeam(from, to); return true; } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 663c39ff02..10412cc0d2 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -33,7 +33,6 @@ public class BoardTest { .isTrue(); } - // TODO method 리팩토링 @Test void 차림이_선택되었을_때_상과_마를_정확한_위치에_배치해야_한다() { Formation elephantHorseHorseElephant = Formation.ELEPHANT_HORSE_HORSE_ELEPHANT; From 146434b7049f233e230ebce22cca86ba4aed8119 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:47:49 +0900 Subject: [PATCH 35/41] =?UTF-8?q?feat(domain):=20PieceType=20=ED=95=9C?= =?UTF-8?q?=EC=9E=90=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 4 +++ .../java/controller/JanggiController.java | 4 +++ src/main/java/domain/game/Game.java | 4 +++ src/main/java/domain/piece/PieceType.java | 33 ++++++++++++++----- .../java/domain/{piece => team}/Team.java | 0 src/main/java/dto/BoardStatusDTO.java | 4 +++ src/main/java/dto/InputPointDTO.java | 31 +++++++++++++++++ src/main/java/dto/MoveDTO.java | 4 +++ src/main/java/dto/PointInfoDTO.java | 10 ++++++ src/main/java/view/InputView.java | 4 +++ src/main/java/view/OutputView.java | 4 +++ 11 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/controller/JanggiController.java create mode 100644 src/main/java/domain/game/Game.java rename src/main/java/domain/{piece => team}/Team.java (100%) create mode 100644 src/main/java/dto/BoardStatusDTO.java create mode 100644 src/main/java/dto/InputPointDTO.java create mode 100644 src/main/java/dto/MoveDTO.java create mode 100644 src/main/java/dto/PointInfoDTO.java create mode 100644 src/main/java/view/InputView.java create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 0000000000..0a08323d1b --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,4 @@ +package PACKAGE_NAME; + +public class Application { +} diff --git a/src/main/java/controller/JanggiController.java b/src/main/java/controller/JanggiController.java new file mode 100644 index 0000000000..7f2cf92561 --- /dev/null +++ b/src/main/java/controller/JanggiController.java @@ -0,0 +1,4 @@ +package controller; + +public class JanggiController { +} diff --git a/src/main/java/domain/game/Game.java b/src/main/java/domain/game/Game.java new file mode 100644 index 0000000000..44e7ecb7f7 --- /dev/null +++ b/src/main/java/domain/game/Game.java @@ -0,0 +1,4 @@ +package domain.game; + +public class Game { +} diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index d2fe1ada9c..f7608a6333 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,15 +1,32 @@ package domain.piece; +import domain.team.Team; + public enum PieceType { - GENERAL, - CHARIOT, - CANNON, - HORSE, - ELEPHANT, - GUARD, - SOLDIER, - NONE, + GENERAL("楚", "漢"), + CHARIOT("車", "車"), + CANNON("包", "包"), + HORSE("馬", "馬"), + ELEPHANT("象", "象"), + GUARD("士", "士"), + SOLDIER("卒", "兵"), + NONE("+", "+"), ; + private final String choChineseCharacter; + private final String hanChineseCharacter; + + PieceType(String choChineseCharacter, String hanChineseCharacter) { + this.choChineseCharacter = choChineseCharacter; + this.hanChineseCharacter = hanChineseCharacter; + } + + public String getChineseCharacter(Team team) { + if (team == Team.CHO) { + return choChineseCharacter; + } + return hanChineseCharacter; + } + } diff --git a/src/main/java/domain/piece/Team.java b/src/main/java/domain/team/Team.java similarity index 100% rename from src/main/java/domain/piece/Team.java rename to src/main/java/domain/team/Team.java diff --git a/src/main/java/dto/BoardStatusDTO.java b/src/main/java/dto/BoardStatusDTO.java new file mode 100644 index 0000000000..c36f9cc10b --- /dev/null +++ b/src/main/java/dto/BoardStatusDTO.java @@ -0,0 +1,4 @@ +package dto; + +public class BoardStatusDTO { +} diff --git a/src/main/java/dto/InputPointDTO.java b/src/main/java/dto/InputPointDTO.java new file mode 100644 index 0000000000..6b5ffa183c --- /dev/null +++ b/src/main/java/dto/InputPointDTO.java @@ -0,0 +1,31 @@ +package dto; + +import domain.point.Point; + +public class moveInputDTO { + + private final Point point; + + public moveInputDTO(String y, String x) { + validate(y, x); + this.point = parsePoint(y, x); + } + + private void validate(String y, String x){ + int integerY; + int integerX; + try { + integerY = Integer.parseInt(y); + integerX = Integer.parseInt(x); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("잘못된 입력 형식입니다."); + } + } + + private Point parsePoint(String y, String x){ + int integerY = Integer.parseInt(y); + int integerX = Integer.parseInt(x); + + return new Point(integerY, integerX); + } +} diff --git a/src/main/java/dto/MoveDTO.java b/src/main/java/dto/MoveDTO.java new file mode 100644 index 0000000000..ddbc063183 --- /dev/null +++ b/src/main/java/dto/MoveDTO.java @@ -0,0 +1,4 @@ +package dto; + +public class MoveDTO { +} diff --git a/src/main/java/dto/PointInfoDTO.java b/src/main/java/dto/PointInfoDTO.java new file mode 100644 index 0000000000..15216768e7 --- /dev/null +++ b/src/main/java/dto/PointInfoDTO.java @@ -0,0 +1,10 @@ +package dto; + +public class IntersectionInfoDTO { + + private final String intersection; + + public IntersectionInfoDTO(String intersection) { + this.intersection = intersection; + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000000..ae2791fb07 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,4 @@ +package view; + +public class InputView { +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 0000000000..d8f9743ccf --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,4 @@ +package view; + +public class OutputView { +} From 4800beafc44da89a8d45e6cb8d1c5b4b5e8613a5 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:50:08 +0900 Subject: [PATCH 36/41] =?UTF-8?q?refactor(domain):=20Team=20=ED=8C=A8?= =?UTF-8?q?=ED=82=A4=EC=A7=80=20=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=ED=95=9C?= =?UTF-8?q?=EA=B8=80,=20=ED=95=9C=EC=9E=90=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/piece/Cannon.java | 2 ++ src/main/java/domain/piece/Chariot.java | 2 ++ src/main/java/domain/piece/Elephant.java | 2 ++ src/main/java/domain/piece/General.java | 2 ++ src/main/java/domain/piece/Guard.java | 2 ++ src/main/java/domain/piece/Horse.java | 2 ++ src/main/java/domain/piece/Piece.java | 5 ++++ src/main/java/domain/piece/Soldier.java | 2 ++ src/main/java/domain/team/Team.java | 29 +++++++++++++++++-- src/test/java/domain/PieceTest.java | 2 +- .../java/domain/rule/HorseMoveRuleTest.java | 2 +- .../java/domain/rule/SoliderMoveRuleTest.java | 2 +- 12 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java index 88aa840001..6a0b2507c5 100644 --- a/src/main/java/domain/piece/Cannon.java +++ b/src/main/java/domain/piece/Cannon.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class Cannon extends Piece { public Cannon(Team team) { diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java index 735a5992ea..6272ef1098 100644 --- a/src/main/java/domain/piece/Chariot.java +++ b/src/main/java/domain/piece/Chariot.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class Chariot extends Piece { public Chariot(Team team) { diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java index 48c0b9e75e..b028102488 100644 --- a/src/main/java/domain/piece/Elephant.java +++ b/src/main/java/domain/piece/Elephant.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class Elephant extends Piece { public Elephant(Team team) { diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/General.java index 0eaef4e8af..d6b8f2a167 100644 --- a/src/main/java/domain/piece/General.java +++ b/src/main/java/domain/piece/General.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class General extends Piece { public General(Team team) { diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java index eca1c0e9e1..8af7e6d09e 100644 --- a/src/main/java/domain/piece/Guard.java +++ b/src/main/java/domain/piece/Guard.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class Guard extends Piece { public Guard(Team team) { diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java index b301acdf6c..3f71347530 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/Horse.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class Horse extends Piece { public Horse(Team team) { diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index dac666e7cf..1fe5ca369f 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.team.Team; import java.util.Objects; public abstract class Piece { @@ -33,6 +34,10 @@ public boolean hasPiece() { return this.pieceType != PieceType.NONE; } + public String getChineseCharacter(){ + return pieceType.getChineseCharacter(team); + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java index 86522134e5..47e0c8ea28 100644 --- a/src/main/java/domain/piece/Soldier.java +++ b/src/main/java/domain/piece/Soldier.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.team.Team; + public class Soldier extends Piece { public Soldier(Team team) { diff --git a/src/main/java/domain/team/Team.java b/src/main/java/domain/team/Team.java index 044dc96191..51dfc66722 100644 --- a/src/main/java/domain/team/Team.java +++ b/src/main/java/domain/team/Team.java @@ -1,9 +1,32 @@ -package domain.piece; +package domain.team; public enum Team { - CHO, - HAN, + CHO("초", "楚"), + HAN("한", "漢"), ; + private final String koreanTeamName; + private final String chineseTeamName; + + Team(String koreanTeamName, String chineseTeamName) { + this.koreanTeamName = koreanTeamName; + this.chineseTeamName = chineseTeamName; + } + + public Team nextTurn(){ + if(this == CHO){ + return HAN; + } + return CHO; + } + + public String getKoreanTeamName(){ + return koreanTeamName; + } + + public String getChineseTeamName(){ + return chineseTeamName; + } + } diff --git a/src/test/java/domain/PieceTest.java b/src/test/java/domain/PieceTest.java index 11d6d042b9..ad3e4b0f16 100644 --- a/src/test/java/domain/PieceTest.java +++ b/src/test/java/domain/PieceTest.java @@ -1,7 +1,7 @@ package domain; import domain.piece.Cannon; -import domain.piece.Team; +import domain.team.Team; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/test/java/domain/rule/HorseMoveRuleTest.java b/src/test/java/domain/rule/HorseMoveRuleTest.java index 78479d6585..0f700f1b7d 100644 --- a/src/test/java/domain/rule/HorseMoveRuleTest.java +++ b/src/test/java/domain/rule/HorseMoveRuleTest.java @@ -2,7 +2,7 @@ import domain.intersection.Intersection; import domain.piece.Horse; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.HorseMoveRule; import domain.point.Point; import java.util.List; diff --git a/src/test/java/domain/rule/SoliderMoveRuleTest.java b/src/test/java/domain/rule/SoliderMoveRuleTest.java index f063cd082f..c841d03c36 100644 --- a/src/test/java/domain/rule/SoliderMoveRuleTest.java +++ b/src/test/java/domain/rule/SoliderMoveRuleTest.java @@ -2,7 +2,7 @@ import domain.intersection.Intersection; import domain.piece.Soldier; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.SoliderMoveRule; import domain.piece.move.Vector; import domain.point.Point; From 68ccf14e12909af469a25d2a78687714eef6dfd9 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:50:30 +0900 Subject: [PATCH 37/41] =?UTF-8?q?feat(Application):=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EB=9E=A8=20=EC=8B=9C=EC=9E=91=20=EB=8F=84=EC=9E=85?= =?UTF-8?q?=EB=B6=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/Application.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 0a08323d1b..74e8521883 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,4 +1,18 @@ -package PACKAGE_NAME; +import controller.JanggiController; +import domain.board.JanggiBoard; +import domain.board.JanggiGenerator; +import view.InputView; +import view.OutputView; public class Application { + + public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + + JanggiController janggiController = new JanggiController(inputView, outputView); + janggiController.run(); + + } + } From b8b5f9d2f8efabdfab1be96f8b4aa21a8ee8458f Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:50:43 +0900 Subject: [PATCH 38/41] =?UTF-8?q?feat(controller):=20=EC=9E=A5=EA=B8=B0=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/controller/JanggiController.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/main/java/controller/JanggiController.java b/src/main/java/controller/JanggiController.java index 7f2cf92561..3021ad20dc 100644 --- a/src/main/java/controller/JanggiController.java +++ b/src/main/java/controller/JanggiController.java @@ -1,4 +1,42 @@ package controller; +import domain.board.Formation; +import domain.board.JanggiBoard; +import domain.board.JanggiGenerator; +import domain.game.Game; +import domain.point.Point; +import domain.team.Team; +import dto.MoveDTO; +import view.InputView; +import view.OutputView; + public class JanggiController { + + private final InputView inputView; + private final OutputView outputView; + + public JanggiController(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run(){ + Formation hanFormation = Formation.valueOf(inputView.inputHanWingSetup()); + Formation choFormation = Formation.valueOf(inputView.inputChoWingSetup()); + JanggiGenerator janggiGenerator = new JanggiGenerator(hanFormation, choFormation); + + Game game = new Game(new JanggiBoard(janggiGenerator)); + + while(true){ + try { + outputView.printCurrentBoardStatus(game.boardStatus()); + final Team turn = game.currentTurn(); + outputView.printCurrentTurn(turn); + MoveDTO move = new MoveDTO(inputView.inputMovePiecePoint(), inputView.inputDestinationPoint()); + game.processTurn(move); + } catch (IllegalArgumentException e){ + outputView.printErrorMessage(e.getMessage()); + } + } + } } From 3310d18bd680de1b8118e7bf0c9509261b1d7d6f Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:50:59 +0900 Subject: [PATCH 39/41] =?UTF-8?q?feat(dto):=20=EC=9E=85=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=20DTO=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/dto/BoardStatusDTO.java | 29 ++++++++++++++++++++++++ src/main/java/dto/InputPointDTO.java | 32 ++++++++++++++++----------- src/main/java/dto/MoveDTO.java | 19 ++++++++++++++++ src/main/java/dto/PointInfoDTO.java | 12 ++++++---- 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/src/main/java/dto/BoardStatusDTO.java b/src/main/java/dto/BoardStatusDTO.java index c36f9cc10b..6406bce1d4 100644 --- a/src/main/java/dto/BoardStatusDTO.java +++ b/src/main/java/dto/BoardStatusDTO.java @@ -1,4 +1,33 @@ package dto; +import domain.intersection.Intersection; +import domain.point.Point; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; + public class BoardStatusDTO { + + private final static int MIN_INDEX = 0; + private final static int MAX_ROW = 10; + private final static int MAX_FILE = 9; + + private final List boardStatus; + + public BoardStatusDTO(final Map intersections) { + List pointInfos = IntStream.range(0, MAX_ROW) + .boxed() + .flatMap(row -> IntStream.range(MIN_INDEX, MAX_FILE) + .mapToObj(file -> { + final Point point = new Point(row, file); + final String pointInfo = intersections.get(point).getChineseCharacter(); + return new PointInfoDTO(pointInfo); + })) + .toList(); + this.boardStatus = List.copyOf(pointInfos); + } + + public List boardStatus() { + return List.copyOf(boardStatus); + } } diff --git a/src/main/java/dto/InputPointDTO.java b/src/main/java/dto/InputPointDTO.java index 6b5ffa183c..5105d93e85 100644 --- a/src/main/java/dto/InputPointDTO.java +++ b/src/main/java/dto/InputPointDTO.java @@ -2,30 +2,36 @@ import domain.point.Point; -public class moveInputDTO { +public class InputPointDTO { private final Point point; - public moveInputDTO(String y, String x) { - validate(y, x); - this.point = parsePoint(y, x); + public InputPointDTO(String input) { + validate(input); + this.point = parsePoint(input); } - private void validate(String y, String x){ - int integerY; - int integerX; + private void validate(String input){ try { - integerY = Integer.parseInt(y); - integerX = Integer.parseInt(x); - } catch (IllegalArgumentException e) { + String[] tokens = input.trim().split("\\s+"); + String y = tokens[0]; + String x = tokens[1]; + Integer.parseInt(y); + Integer.parseInt(x); + } catch (RuntimeException e) { throw new IllegalArgumentException("잘못된 입력 형식입니다."); } } - private Point parsePoint(String y, String x){ - int integerY = Integer.parseInt(y); - int integerX = Integer.parseInt(x); + private Point parsePoint(String input){ + String[] tokens = input.trim().split("\\s+"); + int integerY = Integer.parseInt(tokens[0]); + int integerX = Integer.parseInt(tokens[1]); return new Point(integerY, integerX); } + + public Point getPoint(){ + return this.point; + } } diff --git a/src/main/java/dto/MoveDTO.java b/src/main/java/dto/MoveDTO.java index ddbc063183..4beba12076 100644 --- a/src/main/java/dto/MoveDTO.java +++ b/src/main/java/dto/MoveDTO.java @@ -1,4 +1,23 @@ package dto; +import domain.point.Point; + public class MoveDTO { + + private final Point from; + private final Point to; + + public MoveDTO(InputPointDTO from, InputPointDTO to) { + this.from = from.getPoint(); + this.to = to.getPoint(); + } + + public Point getFrom(){ + return from; + } + + public Point getTo(){ + return to; + } + } diff --git a/src/main/java/dto/PointInfoDTO.java b/src/main/java/dto/PointInfoDTO.java index 15216768e7..3e7bb3f164 100644 --- a/src/main/java/dto/PointInfoDTO.java +++ b/src/main/java/dto/PointInfoDTO.java @@ -1,10 +1,14 @@ package dto; -public class IntersectionInfoDTO { +public class PointInfoDTO { - private final String intersection; + private final String pointInfo; - public IntersectionInfoDTO(String intersection) { - this.intersection = intersection; + public PointInfoDTO(String pointInfo) { + this.pointInfo = pointInfo; + } + + public String pointInfo(){ + return pointInfo; } } From d70139ad621fd04040cc251952901d75920f4b17 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:51:29 +0900 Subject: [PATCH 40/41] =?UTF-8?q?feat(view):=20=EC=9E=85=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=20=EB=B7=B0=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/board/Formation.java | 8 ++-- src/main/java/domain/board/JanggiBoard.java | 7 ++- .../java/domain/board/JanggiGenerator.java | 2 +- src/main/java/domain/game/Game.java | 31 +++++++++++++ .../domain/intersection/Intersection.java | 4 ++ src/main/java/view/InputView.java | 38 +++++++++++++++ src/main/java/view/OutputView.java | 46 +++++++++++++++++++ src/test/java/domain/BoardTest.java | 2 +- src/test/java/domain/MoveTest.java | 2 +- .../java/domain/rule/CannonMoveRuleTest.java | 2 +- .../java/domain/rule/ChariotMoveRuleTest.java | 2 +- .../domain/rule/ElephantMoveRuleTest.java | 2 +- .../java/domain/rule/GeneralMoveRuleTest.java | 2 +- .../java/domain/rule/GuardMoveRuleTest.java | 2 +- 14 files changed, 137 insertions(+), 13 deletions(-) diff --git a/src/main/java/domain/board/Formation.java b/src/main/java/domain/board/Formation.java index 2bf020e8bd..dc72101dd3 100644 --- a/src/main/java/domain/board/Formation.java +++ b/src/main/java/domain/board/Formation.java @@ -5,10 +5,10 @@ public enum Formation { - ELEPHANT_HORSE_ELEPHANT_HORSE(1, List.of(1, 6), List.of(2, 7)), - ELEPHANT_HORSE_HORSE_ELEPHANT(2, List.of(1, 7), List.of(2, 6)), - HORSE_ELEPHANT_ELEPHANT_HORSE(3, List.of(2, 6), List.of(1, 7)), - HORSE_ELEPHANT_HORSE_ELEPHANT(4, List.of(2, 7), List.of(1, 6)), + HORSE_ELEPHANT_HORSE_ELEPHANT(1, List.of(2, 7), List.of(1, 6)), + HORSE_ELEPHANT_ELEPHANT_HORSE(2, List.of(2, 6), List.of(1, 7)), + ELEPHANT_HORSE_ELEPHANT_HORSE(3, List.of(1, 6), List.of(2, 7)), + ELEPHANT_HORSE_HORSE_ELEPHANT(4, List.of(1, 7), List.of(2, 6)), ; private final int formatNumber; diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index ddedefd203..026519bbb7 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -10,6 +10,7 @@ import domain.piece.move.MoveRule; import domain.piece.move.SoliderMoveRule; import domain.point.Point; +import dto.BoardStatusDTO; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -65,7 +66,7 @@ public MoveRule findMoveRule(Intersection from) { return moveRules.stream() .filter(moveRule -> moveRule.support(from)) .findFirst() - .orElse(null); + .orElseThrow(() -> new IllegalArgumentException("선택한 좌표에 이동 가능한 기물이 없습니다.")); } private List findPath(List possiblePoints) { @@ -74,6 +75,10 @@ private List findPath(List possiblePoints) { .toList(); } + public BoardStatusDTO boardStatus(){ + return new BoardStatusDTO(intersections); + } + public Intersection findIntersection(Point point) { return intersections.get(point); } diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java index be39537f2a..143d96d4e3 100644 --- a/src/main/java/domain/board/JanggiGenerator.java +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -9,7 +9,7 @@ import domain.piece.Horse; import domain.piece.Piece; import domain.piece.Soldier; -import domain.piece.Team; +import domain.team.Team; import domain.point.Point; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/domain/game/Game.java b/src/main/java/domain/game/Game.java index 44e7ecb7f7..0e6dc473e2 100644 --- a/src/main/java/domain/game/Game.java +++ b/src/main/java/domain/game/Game.java @@ -1,4 +1,35 @@ package domain.game; +import domain.board.JanggiBoard; +import domain.point.Point; +import domain.team.Team; +import dto.BoardStatusDTO; +import dto.MoveDTO; + public class Game { + + private final JanggiBoard janggiBoard; + private Team turn; + + public Game(JanggiBoard janggiBoard) { + this.janggiBoard = janggiBoard; + this.turn = Team.CHO; + } + + public void processTurn(MoveDTO move){ + Point from = move.getFrom(); + Point to = move.getTo(); + janggiBoard.tryToMove(from, to); + + turn = turn.nextTurn(); + } + + public Team currentTurn(){ + return turn; + } + + public BoardStatusDTO boardStatus(){ + return janggiBoard.boardStatus(); + } + } diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index ae23a85184..d4deb87036 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -52,6 +52,10 @@ public boolean isChoIntersection() { return piece.isCho(); } + public String getChineseCharacter(){ + return piece.getChineseCharacter(); + } + @Override public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) { diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index ae2791fb07..f897587ad0 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,4 +1,42 @@ package view; +import dto.InputPointDTO; +import java.util.Scanner; + public class InputView { + + private final String INPUT_MOVE_PIECE_POINT_MESSAGE = "이동할 기물의 좌표를 입력하세요. (입력 형식: y좌표 x좌표)\n"; + private final String INPUT_DESTINATION_POINT_MESSAGE = "기물의 목적지 좌표를 입력하세요. (입력 형식: y좌표 x좌표)\n"; + private final String HAN_WING_SETUP_MESSAGE = "한(漢)의 상차림을 입력하세요." + + "\n1. 마 - 상 - 마 - 상 (馬 - 象 - 馬 - 象)" + + "\n2. 마 - 상 - 상 - 마 (馬 - 象 - 象 - 馬)" + + "\n3. 상 - 마 - 상 - 마 (象 - 馬 - 象 - 馬)" + + "\n4. 상 - 마 - 마 - 상 (象 - 馬 - 馬 - 象)\n"; + private final String CHO_WING_SETUP_MESSAGE = "초(楚)의 상차림을 입력하세요." + + "\n1. 마 - 상 - 마 - 상 (馬 - 象 - 馬 - 象)" + + "\n2. 마 - 상 - 상 - 마 (馬 - 象 - 象 - 馬)" + + "\n3. 상 - 마 - 상 - 마 (象 - 馬 - 象 - 馬)" + + "\n4. 상 - 마 - 마 - 상 (象 - 馬 - 馬 - 象)\n"; + + Scanner scanner = new Scanner(System.in); + + public int inputHanWingSetup(){ + System.out.print(HAN_WING_SETUP_MESSAGE); + return Integer.parseInt(scanner.nextLine().trim()); + } + + public int inputChoWingSetup(){ + System.out.print(CHO_WING_SETUP_MESSAGE); + return Integer.parseInt(scanner.nextLine().trim()); + } + + public InputPointDTO inputMovePiecePoint(){ + System.out.print(INPUT_MOVE_PIECE_POINT_MESSAGE); + return new InputPointDTO(scanner.nextLine()); + } + + public InputPointDTO inputDestinationPoint(){ + System.out.print(INPUT_DESTINATION_POINT_MESSAGE); + return new InputPointDTO(scanner.nextLine()); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index d8f9743ccf..28f7daafaf 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -1,4 +1,50 @@ package view; +import domain.team.Team; +import dto.BoardStatusDTO; +import dto.PointInfoDTO; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + public class OutputView { + + private static final int MIN_INDEX = 0; + private static final int MAX_ROW = 10; + private static final int MAX_FILE = 9; + private static final String FULL_SPACE = " "; + private static final String HALF_SPACE = " "; + + public void printCurrentTurn(Team turn){ + System.out.print(turn.getKoreanTeamName() + "(" + turn.getChineseTeamName() + ")의 차례입니다.\n"); + } + + public void printCurrentBoardStatus(final BoardStatusDTO boardStatus) { + final List pointInfos = boardStatus.boardStatus(); + final String header = IntStream.range(MIN_INDEX, MAX_FILE) + .mapToObj(this::toFullWidthNumber) + .collect(Collectors.joining(HALF_SPACE)); + final String rows = IntStream.range(MIN_INDEX, MAX_ROW) + .mapToObj(row -> { + final String rowCells = IntStream.range(MIN_INDEX, MAX_FILE) + .mapToObj(file -> pointInfos.get(row * MAX_FILE + file).pointInfo()) + .collect(Collectors.joining(HALF_SPACE)); + return toFullWidthNumber(row) + HALF_SPACE + rowCells; + }) + .collect(Collectors.joining(System.lineSeparator())); + System.out.println(FULL_SPACE + HALF_SPACE + header); + System.out.println(rows); + } + + private String toFullWidthNumber(int number) { + return String.valueOf(number) + .chars() + .mapToObj(ch -> String.valueOf((char) ('0' + (ch - '0')))) + .collect(Collectors.joining()); + } + + public void printErrorMessage(String message){ + System.out.println(message); + } + } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 10412cc0d2..8c801bcf5e 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -6,7 +6,7 @@ import domain.fixture.TestIntersectionGenerator; import domain.intersection.Intersection; import domain.piece.General; -import domain.piece.Team; +import domain.team.Team; import domain.point.Point; import java.util.Arrays; import java.util.List; diff --git a/src/test/java/domain/MoveTest.java b/src/test/java/domain/MoveTest.java index 53bbc25dd7..fdb3d458ac 100644 --- a/src/test/java/domain/MoveTest.java +++ b/src/test/java/domain/MoveTest.java @@ -5,7 +5,7 @@ import domain.intersection.Intersection; import domain.piece.Chariot; import domain.piece.Soldier; -import domain.piece.Team; +import domain.team.Team; import domain.point.Point; import java.util.List; import org.assertj.core.api.Assertions; diff --git a/src/test/java/domain/rule/CannonMoveRuleTest.java b/src/test/java/domain/rule/CannonMoveRuleTest.java index 36d74801db..43a14632e6 100644 --- a/src/test/java/domain/rule/CannonMoveRuleTest.java +++ b/src/test/java/domain/rule/CannonMoveRuleTest.java @@ -3,7 +3,7 @@ import domain.intersection.Intersection; import domain.piece.Cannon; import domain.piece.Chariot; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.CannonMoveRule; import domain.point.Point; import java.util.List; diff --git a/src/test/java/domain/rule/ChariotMoveRuleTest.java b/src/test/java/domain/rule/ChariotMoveRuleTest.java index 324d92ebe1..f1b2a6e1de 100644 --- a/src/test/java/domain/rule/ChariotMoveRuleTest.java +++ b/src/test/java/domain/rule/ChariotMoveRuleTest.java @@ -2,7 +2,7 @@ import domain.intersection.Intersection; import domain.piece.Chariot; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.ChariotMoveRule; import domain.point.Point; import java.util.List; diff --git a/src/test/java/domain/rule/ElephantMoveRuleTest.java b/src/test/java/domain/rule/ElephantMoveRuleTest.java index c39d730744..e507ca0811 100644 --- a/src/test/java/domain/rule/ElephantMoveRuleTest.java +++ b/src/test/java/domain/rule/ElephantMoveRuleTest.java @@ -2,7 +2,7 @@ import domain.intersection.Intersection; import domain.piece.Elephant; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.ElephantMoveRule; import domain.point.Point; import java.util.List; diff --git a/src/test/java/domain/rule/GeneralMoveRuleTest.java b/src/test/java/domain/rule/GeneralMoveRuleTest.java index 46c99a83e8..6313752be8 100644 --- a/src/test/java/domain/rule/GeneralMoveRuleTest.java +++ b/src/test/java/domain/rule/GeneralMoveRuleTest.java @@ -3,7 +3,7 @@ import domain.intersection.Intersection; import domain.piece.General; import domain.piece.Soldier; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.GeneralMoveRule; import domain.point.Point; import java.util.List; diff --git a/src/test/java/domain/rule/GuardMoveRuleTest.java b/src/test/java/domain/rule/GuardMoveRuleTest.java index 7c7931cc75..a1aedbbee9 100644 --- a/src/test/java/domain/rule/GuardMoveRuleTest.java +++ b/src/test/java/domain/rule/GuardMoveRuleTest.java @@ -3,7 +3,7 @@ import domain.intersection.Intersection; import domain.piece.Guard; import domain.piece.Soldier; -import domain.piece.Team; +import domain.team.Team; import domain.piece.move.GuardMoveRule; import domain.point.Point; import java.util.List; From c0577baa5cbb1820c92e774f632de3714c330021 Mon Sep 17 00:00:00 2001 From: poketopa Date: Sun, 29 Mar 2026 18:56:33 +0900 Subject: [PATCH 41/41] =?UTF-8?q?chore:=20=EC=A0=84=EC=B2=B4=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EB=A6=B0=ED=8C=85=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/Application.java | 2 -- src/main/java/controller/JanggiController.java | 7 +++---- src/main/java/domain/board/JanggiBoard.java | 2 +- src/main/java/domain/board/JanggiGenerator.java | 2 +- src/main/java/domain/game/Game.java | 8 ++++---- src/main/java/domain/intersection/Intersection.java | 2 +- src/main/java/domain/piece/Piece.java | 2 +- src/main/java/domain/piece/move/Directions.java | 1 - src/main/java/domain/team/Team.java | 8 ++++---- src/main/java/dto/InputPointDTO.java | 6 +++--- src/main/java/dto/MoveDTO.java | 4 ++-- src/main/java/dto/PointInfoDTO.java | 2 +- src/main/java/view/InputView.java | 8 ++++---- src/main/java/view/OutputView.java | 4 ++-- src/test/java/domain/BoardTest.java | 2 +- src/test/java/domain/MoveTest.java | 2 +- src/test/java/domain/rule/CannonMoveRuleTest.java | 2 +- src/test/java/domain/rule/ChariotMoveRuleTest.java | 2 +- src/test/java/domain/rule/ElephantMoveRuleTest.java | 2 +- src/test/java/domain/rule/GeneralMoveRuleTest.java | 2 +- src/test/java/domain/rule/GuardMoveRuleTest.java | 2 +- src/test/java/domain/rule/HorseMoveRuleTest.java | 2 +- src/test/java/domain/rule/SoliderMoveRuleTest.java | 2 +- 23 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 74e8521883..6fd58da8ae 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,6 +1,4 @@ import controller.JanggiController; -import domain.board.JanggiBoard; -import domain.board.JanggiGenerator; import view.InputView; import view.OutputView; diff --git a/src/main/java/controller/JanggiController.java b/src/main/java/controller/JanggiController.java index 3021ad20dc..8e890b77bf 100644 --- a/src/main/java/controller/JanggiController.java +++ b/src/main/java/controller/JanggiController.java @@ -4,7 +4,6 @@ import domain.board.JanggiBoard; import domain.board.JanggiGenerator; import domain.game.Game; -import domain.point.Point; import domain.team.Team; import dto.MoveDTO; import view.InputView; @@ -20,21 +19,21 @@ public JanggiController(InputView inputView, OutputView outputView) { this.outputView = outputView; } - public void run(){ + public void run() { Formation hanFormation = Formation.valueOf(inputView.inputHanWingSetup()); Formation choFormation = Formation.valueOf(inputView.inputChoWingSetup()); JanggiGenerator janggiGenerator = new JanggiGenerator(hanFormation, choFormation); Game game = new Game(new JanggiBoard(janggiGenerator)); - while(true){ + while (true) { try { outputView.printCurrentBoardStatus(game.boardStatus()); final Team turn = game.currentTurn(); outputView.printCurrentTurn(turn); MoveDTO move = new MoveDTO(inputView.inputMovePiecePoint(), inputView.inputDestinationPoint()); game.processTurn(move); - } catch (IllegalArgumentException e){ + } catch (IllegalArgumentException e) { outputView.printErrorMessage(e.getMessage()); } } diff --git a/src/main/java/domain/board/JanggiBoard.java b/src/main/java/domain/board/JanggiBoard.java index 026519bbb7..431c74c35d 100644 --- a/src/main/java/domain/board/JanggiBoard.java +++ b/src/main/java/domain/board/JanggiBoard.java @@ -75,7 +75,7 @@ private List findPath(List possiblePoints) { .toList(); } - public BoardStatusDTO boardStatus(){ + public BoardStatusDTO boardStatus() { return new BoardStatusDTO(intersections); } diff --git a/src/main/java/domain/board/JanggiGenerator.java b/src/main/java/domain/board/JanggiGenerator.java index 143d96d4e3..54a36a1588 100644 --- a/src/main/java/domain/board/JanggiGenerator.java +++ b/src/main/java/domain/board/JanggiGenerator.java @@ -9,8 +9,8 @@ import domain.piece.Horse; import domain.piece.Piece; import domain.piece.Soldier; -import domain.team.Team; import domain.point.Point; +import domain.team.Team; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; diff --git a/src/main/java/domain/game/Game.java b/src/main/java/domain/game/Game.java index 0e6dc473e2..db434ee8a0 100644 --- a/src/main/java/domain/game/Game.java +++ b/src/main/java/domain/game/Game.java @@ -16,19 +16,19 @@ public Game(JanggiBoard janggiBoard) { this.turn = Team.CHO; } - public void processTurn(MoveDTO move){ - Point from = move.getFrom(); + public void processTurn(MoveDTO move) { + Point from = move.getFrom(); Point to = move.getTo(); janggiBoard.tryToMove(from, to); turn = turn.nextTurn(); } - public Team currentTurn(){ + public Team currentTurn() { return turn; } - public BoardStatusDTO boardStatus(){ + public BoardStatusDTO boardStatus() { return janggiBoard.boardStatus(); } diff --git a/src/main/java/domain/intersection/Intersection.java b/src/main/java/domain/intersection/Intersection.java index d4deb87036..c6dc99c062 100644 --- a/src/main/java/domain/intersection/Intersection.java +++ b/src/main/java/domain/intersection/Intersection.java @@ -52,7 +52,7 @@ public boolean isChoIntersection() { return piece.isCho(); } - public String getChineseCharacter(){ + public String getChineseCharacter() { return piece.getChineseCharacter(); } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 1fe5ca369f..d12bafb55d 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -34,7 +34,7 @@ public boolean hasPiece() { return this.pieceType != PieceType.NONE; } - public String getChineseCharacter(){ + public String getChineseCharacter() { return pieceType.getChineseCharacter(team); } diff --git a/src/main/java/domain/piece/move/Directions.java b/src/main/java/domain/piece/move/Directions.java index 19dcf87d63..817bc745cc 100644 --- a/src/main/java/domain/piece/move/Directions.java +++ b/src/main/java/domain/piece/move/Directions.java @@ -1,7 +1,6 @@ package domain.piece.move; import domain.point.Point; -import java.util.Collections; import java.util.List; public class Directions { diff --git a/src/main/java/domain/team/Team.java b/src/main/java/domain/team/Team.java index 51dfc66722..bb768702c4 100644 --- a/src/main/java/domain/team/Team.java +++ b/src/main/java/domain/team/Team.java @@ -14,18 +14,18 @@ public enum Team { this.chineseTeamName = chineseTeamName; } - public Team nextTurn(){ - if(this == CHO){ + public Team nextTurn() { + if (this == CHO) { return HAN; } return CHO; } - public String getKoreanTeamName(){ + public String getKoreanTeamName() { return koreanTeamName; } - public String getChineseTeamName(){ + public String getChineseTeamName() { return chineseTeamName; } diff --git a/src/main/java/dto/InputPointDTO.java b/src/main/java/dto/InputPointDTO.java index 5105d93e85..22a9587512 100644 --- a/src/main/java/dto/InputPointDTO.java +++ b/src/main/java/dto/InputPointDTO.java @@ -11,7 +11,7 @@ public InputPointDTO(String input) { this.point = parsePoint(input); } - private void validate(String input){ + private void validate(String input) { try { String[] tokens = input.trim().split("\\s+"); String y = tokens[0]; @@ -23,7 +23,7 @@ private void validate(String input){ } } - private Point parsePoint(String input){ + private Point parsePoint(String input) { String[] tokens = input.trim().split("\\s+"); int integerY = Integer.parseInt(tokens[0]); int integerX = Integer.parseInt(tokens[1]); @@ -31,7 +31,7 @@ private Point parsePoint(String input){ return new Point(integerY, integerX); } - public Point getPoint(){ + public Point getPoint() { return this.point; } } diff --git a/src/main/java/dto/MoveDTO.java b/src/main/java/dto/MoveDTO.java index 4beba12076..41fb65a74b 100644 --- a/src/main/java/dto/MoveDTO.java +++ b/src/main/java/dto/MoveDTO.java @@ -12,11 +12,11 @@ public MoveDTO(InputPointDTO from, InputPointDTO to) { this.to = to.getPoint(); } - public Point getFrom(){ + public Point getFrom() { return from; } - public Point getTo(){ + public Point getTo() { return to; } diff --git a/src/main/java/dto/PointInfoDTO.java b/src/main/java/dto/PointInfoDTO.java index 3e7bb3f164..559c193863 100644 --- a/src/main/java/dto/PointInfoDTO.java +++ b/src/main/java/dto/PointInfoDTO.java @@ -8,7 +8,7 @@ public PointInfoDTO(String pointInfo) { this.pointInfo = pointInfo; } - public String pointInfo(){ + public String pointInfo() { return pointInfo; } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index f897587ad0..c8c201b6f6 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -20,22 +20,22 @@ public class InputView { Scanner scanner = new Scanner(System.in); - public int inputHanWingSetup(){ + public int inputHanWingSetup() { System.out.print(HAN_WING_SETUP_MESSAGE); return Integer.parseInt(scanner.nextLine().trim()); } - public int inputChoWingSetup(){ + public int inputChoWingSetup() { System.out.print(CHO_WING_SETUP_MESSAGE); return Integer.parseInt(scanner.nextLine().trim()); } - public InputPointDTO inputMovePiecePoint(){ + public InputPointDTO inputMovePiecePoint() { System.out.print(INPUT_MOVE_PIECE_POINT_MESSAGE); return new InputPointDTO(scanner.nextLine()); } - public InputPointDTO inputDestinationPoint(){ + public InputPointDTO inputDestinationPoint() { System.out.print(INPUT_DESTINATION_POINT_MESSAGE); return new InputPointDTO(scanner.nextLine()); } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index 28f7daafaf..4ac322b688 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -15,7 +15,7 @@ public class OutputView { private static final String FULL_SPACE = " "; private static final String HALF_SPACE = " "; - public void printCurrentTurn(Team turn){ + public void printCurrentTurn(Team turn) { System.out.print(turn.getKoreanTeamName() + "(" + turn.getChineseTeamName() + ")의 차례입니다.\n"); } @@ -43,7 +43,7 @@ private String toFullWidthNumber(int number) { .collect(Collectors.joining()); } - public void printErrorMessage(String message){ + public void printErrorMessage(String message) { System.out.println(message); } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 8c801bcf5e..cfabc52dde 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -6,8 +6,8 @@ import domain.fixture.TestIntersectionGenerator; import domain.intersection.Intersection; import domain.piece.General; -import domain.team.Team; import domain.point.Point; +import domain.team.Team; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; diff --git a/src/test/java/domain/MoveTest.java b/src/test/java/domain/MoveTest.java index fdb3d458ac..5bff35fb4f 100644 --- a/src/test/java/domain/MoveTest.java +++ b/src/test/java/domain/MoveTest.java @@ -5,8 +5,8 @@ import domain.intersection.Intersection; import domain.piece.Chariot; import domain.piece.Soldier; -import domain.team.Team; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/CannonMoveRuleTest.java b/src/test/java/domain/rule/CannonMoveRuleTest.java index 43a14632e6..ad1220f455 100644 --- a/src/test/java/domain/rule/CannonMoveRuleTest.java +++ b/src/test/java/domain/rule/CannonMoveRuleTest.java @@ -3,9 +3,9 @@ import domain.intersection.Intersection; import domain.piece.Cannon; import domain.piece.Chariot; -import domain.team.Team; import domain.piece.move.CannonMoveRule; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/ChariotMoveRuleTest.java b/src/test/java/domain/rule/ChariotMoveRuleTest.java index f1b2a6e1de..abe290cb78 100644 --- a/src/test/java/domain/rule/ChariotMoveRuleTest.java +++ b/src/test/java/domain/rule/ChariotMoveRuleTest.java @@ -2,9 +2,9 @@ import domain.intersection.Intersection; import domain.piece.Chariot; -import domain.team.Team; import domain.piece.move.ChariotMoveRule; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/ElephantMoveRuleTest.java b/src/test/java/domain/rule/ElephantMoveRuleTest.java index e507ca0811..07b27170e2 100644 --- a/src/test/java/domain/rule/ElephantMoveRuleTest.java +++ b/src/test/java/domain/rule/ElephantMoveRuleTest.java @@ -2,9 +2,9 @@ import domain.intersection.Intersection; import domain.piece.Elephant; -import domain.team.Team; import domain.piece.move.ElephantMoveRule; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/GeneralMoveRuleTest.java b/src/test/java/domain/rule/GeneralMoveRuleTest.java index 6313752be8..a93b0d2129 100644 --- a/src/test/java/domain/rule/GeneralMoveRuleTest.java +++ b/src/test/java/domain/rule/GeneralMoveRuleTest.java @@ -3,9 +3,9 @@ import domain.intersection.Intersection; import domain.piece.General; import domain.piece.Soldier; -import domain.team.Team; import domain.piece.move.GeneralMoveRule; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/GuardMoveRuleTest.java b/src/test/java/domain/rule/GuardMoveRuleTest.java index a1aedbbee9..235b979690 100644 --- a/src/test/java/domain/rule/GuardMoveRuleTest.java +++ b/src/test/java/domain/rule/GuardMoveRuleTest.java @@ -3,9 +3,9 @@ import domain.intersection.Intersection; import domain.piece.Guard; import domain.piece.Soldier; -import domain.team.Team; import domain.piece.move.GuardMoveRule; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/HorseMoveRuleTest.java b/src/test/java/domain/rule/HorseMoveRuleTest.java index 0f700f1b7d..7a59453606 100644 --- a/src/test/java/domain/rule/HorseMoveRuleTest.java +++ b/src/test/java/domain/rule/HorseMoveRuleTest.java @@ -2,9 +2,9 @@ import domain.intersection.Intersection; import domain.piece.Horse; -import domain.team.Team; import domain.piece.move.HorseMoveRule; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; diff --git a/src/test/java/domain/rule/SoliderMoveRuleTest.java b/src/test/java/domain/rule/SoliderMoveRuleTest.java index c841d03c36..2564117c06 100644 --- a/src/test/java/domain/rule/SoliderMoveRuleTest.java +++ b/src/test/java/domain/rule/SoliderMoveRuleTest.java @@ -2,10 +2,10 @@ import domain.intersection.Intersection; import domain.piece.Soldier; -import domain.team.Team; import domain.piece.move.SoliderMoveRule; import domain.piece.move.Vector; import domain.point.Point; +import domain.team.Team; import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName;