From 9c01c02b4cc0f8f6ffc9c089a98b6d3424506aa0 Mon Sep 17 00:00:00 2001 From: frombunny Date: Tue, 24 Mar 2026 19:59:16 +0900 Subject: [PATCH 01/58] =?UTF-8?q?docs(README):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9775dda0ae..bddc0945a4 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # java-janggi -장기 미션 저장소 +## 1. 보드 초기화 + +- [ ] 보드의 크기는 9행 10열이다. +- [ ] 초기 배치 방법은 4가지가 있다. + - 마상 상마 (원앙마), 상마 상마 (귀마), 마상 마상 (귀마), 상마 마상 (양귀마) + - [ ] 초기구현은 원앙마로만 제한한다. +- [ ] 게임 시작 시, 각 진영마다 졸/병 5개, 포,상,마,차,사 2개, 궁 1개의 기물이 배치된다. From 59fcc57199fd641e745f5f72bcb1827ea1e84206 Mon Sep 17 00:00:00 2001 From: frombunny Date: Tue, 24 Mar 2026 20:43:42 +0900 Subject: [PATCH 02/58] =?UTF-8?q?feat(Position):=20=EC=A2=8C=ED=91=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=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/Application.java | 5 ++++ src/main/java/domain/Position.java | 42 ++++++++++++++++++++++++++++++ src/test/java/PositionTest.java | 26 ++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/domain/Position.java create mode 100644 src/test/java/PositionTest.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 0000000000..bdbffd531f --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,5 @@ +public class Application { + public static void main(String[] args) { + + } +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java new file mode 100644 index 0000000000..691b0b2282 --- /dev/null +++ b/src/main/java/domain/Position.java @@ -0,0 +1,42 @@ +package domain; + +import java.util.Objects; + +public class Position { + private static final int MIN_RANGE = 0; + private static final int MAX_WIDTH_RANGE = 8; + private static final int MIN_HEIGHT_RANGE = 9; + + private final int x; + private final int y; + + public Position(int x, int y) { + validateRange(x, y); + + this.x = x; + this.y = y; + } + + private void validateRange(int x, int y) { + if (x < MIN_RANGE || x > MAX_WIDTH_RANGE) { + throw new IllegalArgumentException("좌표 값이 올바르지 않습니다."); + } + + if (y < MIN_RANGE || y > MIN_HEIGHT_RANGE) { + throw new IllegalArgumentException("좌표 값이 올바르지 않습니다."); + } + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Position position)) { + return false; + } + return x == position.x && y == position.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } +} diff --git a/src/test/java/PositionTest.java b/src/test/java/PositionTest.java new file mode 100644 index 0000000000..8e76b5e859 --- /dev/null +++ b/src/test/java/PositionTest.java @@ -0,0 +1,26 @@ +import static org.assertj.core.api.Assertions.*; + +import domain.Position; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class PositionTest { + @Test + void 장기판의_좌표의_범위는_가로_9칸_세로_10칸이다() { + Position position = new Position(2, 7); + + assertThat(position).isInstanceOf(Position.class); + } + + @Test + void 장기판의_가로_범위를_벗어날_경우_예외를_뱐환한다() { + Assertions.assertThrows(IllegalArgumentException.class, () -> + new Position(9, 7)); + } + + @Test + void 장기판의_세로_범위를_벗어날_경우_예외를_뱐환한다() { + Assertions.assertThrows(IllegalArgumentException.class, () -> + new Position(7, 11)); + } +} From 327b8afc23687b711cdd0a913c6c5d49c4176644 Mon Sep 17 00:00:00 2001 From: frombunny Date: Tue, 24 Mar 2026 21:29:06 +0900 Subject: [PATCH 03/58] =?UTF-8?q?feat(InitBoard):=20=EC=9E=A5=EA=B8=B0?= =?UTF-8?q?=ED=8C=90=20=EC=83=9D=EC=84=B1=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Piece 구현 - PieceType 구현 - Board 생성 구현 --- src/main/java/domain/Board.java | 41 +++++++++++++++++++++++++++++ src/main/java/domain/Piece.java | 4 +++ src/main/java/domain/PieceType.java | 11 ++++++++ src/test/java/BoardTest.java | 33 +++++++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 src/main/java/domain/Board.java create mode 100644 src/main/java/domain/Piece.java create mode 100644 src/main/java/domain/PieceType.java create mode 100644 src/test/java/BoardTest.java diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/Board.java new file mode 100644 index 0000000000..285b9457d0 --- /dev/null +++ b/src/main/java/domain/Board.java @@ -0,0 +1,41 @@ +package domain; + +import java.util.HashMap; +import java.util.Map; + +public class Board { + private Map pieces = new HashMap(); + + public Board() { + pieces.put(new Position(0,6), new Piece(PieceType.PAWN)); + pieces.put(new Position(2,6), new Piece(PieceType.PAWN)); + pieces.put(new Position(4,6), new Piece(PieceType.PAWN)); + pieces.put(new Position(6,6), new Piece(PieceType.PAWN)); + pieces.put(new Position(8,6), new Piece(PieceType.PAWN)); + + pieces.put(new Position(1,7), new Piece(PieceType.HORSE)); + pieces.put(new Position(7,7), new Piece(PieceType.HORSE)); + + + pieces.put(new Position(0,9), new Piece(PieceType.ROOK)); + pieces.put(new Position(8,9), new Piece(PieceType.ROOK)); + + + pieces.put(new Position(1,9), new Piece(PieceType.HORSE)); + pieces.put(new Position(7,9), new Piece(PieceType.HORSE)); + + + pieces.put(new Position(2,9), new Piece(PieceType.ELEPHANT)); + pieces.put(new Position(6,9), new Piece(PieceType.ELEPHANT)); + + pieces.put(new Position(3,9), new Piece(PieceType.ADVISOR)); + pieces.put(new Position(5,9), new Piece(PieceType.ADVISOR)); + + pieces.put(new Position(4,8), new Piece(PieceType.KING)); + } + + public Piece getPiece(Position position) { + return pieces.get(position); + } + +} diff --git a/src/main/java/domain/Piece.java b/src/main/java/domain/Piece.java new file mode 100644 index 0000000000..7aeaa7591c --- /dev/null +++ b/src/main/java/domain/Piece.java @@ -0,0 +1,4 @@ +package domain; + +public record Piece(PieceType pieceType) { +} diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/PieceType.java new file mode 100644 index 0000000000..96a7877468 --- /dev/null +++ b/src/main/java/domain/PieceType.java @@ -0,0 +1,11 @@ +package domain; + +public enum PieceType { + KING, + ROOK, + CANNON, + HORSE, + ELEPHANT, + ADVISOR, + PAWN +} diff --git a/src/test/java/BoardTest.java b/src/test/java/BoardTest.java new file mode 100644 index 0000000000..4e36452c8a --- /dev/null +++ b/src/test/java/BoardTest.java @@ -0,0 +1,33 @@ +import domain.Board; +import domain.Piece; +import domain.PieceType; +import domain.Position; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +public class BoardTest { + @ParameterizedTest + @MethodSource("pawnProvider") + void 졸을_올바른_위치에_초기화한다 (Position position) { + Board board = new Board(); + Piece piece= board.getPiece(position); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.PAWN); + } + + static Stream pawnProvider() { + return Stream.of( + Arguments.of(new Position(0, 6)), + Arguments.of(new Position(2, 6)), + Arguments.of(new Position(4, 6)), + Arguments.of(new Position(6, 6)), + Arguments.of(new Position(8, 6)) + ); + } + + + +} From 1be679455343976ef66d65c3ae366f4ce2b53d02 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Wed, 25 Mar 2026 11:20:56 +0900 Subject: [PATCH 04/58] =?UTF-8?q?feat(InitBoard):=20=EC=9E=A5=EA=B8=B0?= =?UTF-8?q?=ED=8C=90=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EB=B0=A9=EB=B2=95?= =?UTF-8?q?=EB=93=A4=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 초기 포진에 대한 Enum 정의 - Enum을 받아서, 초기화하는 팩토리 추가 - Board는 팩토리에서 생성될 수 있도록 구조 변경 --- src/main/java/domain/Board.java | 41 ------------------ src/main/java/domain/board/Board.java | 17 ++++++++ src/main/java/domain/board/BoardFactory.java | 43 +++++++++++++++++++ .../java/domain/board/InitializeSetting.java | 22 ++++++++++ .../java/domain/{ => board}/Position.java | 2 +- src/test/java/BoardTest.java | 8 ++-- src/test/java/PositionTest.java | 2 +- 7 files changed, 89 insertions(+), 46 deletions(-) delete mode 100644 src/main/java/domain/Board.java create mode 100644 src/main/java/domain/board/Board.java create mode 100644 src/main/java/domain/board/BoardFactory.java create mode 100644 src/main/java/domain/board/InitializeSetting.java rename src/main/java/domain/{ => board}/Position.java (97%) diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/Board.java deleted file mode 100644 index 285b9457d0..0000000000 --- a/src/main/java/domain/Board.java +++ /dev/null @@ -1,41 +0,0 @@ -package domain; - -import java.util.HashMap; -import java.util.Map; - -public class Board { - private Map pieces = new HashMap(); - - public Board() { - pieces.put(new Position(0,6), new Piece(PieceType.PAWN)); - pieces.put(new Position(2,6), new Piece(PieceType.PAWN)); - pieces.put(new Position(4,6), new Piece(PieceType.PAWN)); - pieces.put(new Position(6,6), new Piece(PieceType.PAWN)); - pieces.put(new Position(8,6), new Piece(PieceType.PAWN)); - - pieces.put(new Position(1,7), new Piece(PieceType.HORSE)); - pieces.put(new Position(7,7), new Piece(PieceType.HORSE)); - - - pieces.put(new Position(0,9), new Piece(PieceType.ROOK)); - pieces.put(new Position(8,9), new Piece(PieceType.ROOK)); - - - pieces.put(new Position(1,9), new Piece(PieceType.HORSE)); - pieces.put(new Position(7,9), new Piece(PieceType.HORSE)); - - - pieces.put(new Position(2,9), new Piece(PieceType.ELEPHANT)); - pieces.put(new Position(6,9), new Piece(PieceType.ELEPHANT)); - - pieces.put(new Position(3,9), new Piece(PieceType.ADVISOR)); - pieces.put(new Position(5,9), new Piece(PieceType.ADVISOR)); - - pieces.put(new Position(4,8), new Piece(PieceType.KING)); - } - - public Piece getPiece(Position position) { - return pieces.get(position); - } - -} diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java new file mode 100644 index 0000000000..509e9ef268 --- /dev/null +++ b/src/main/java/domain/board/Board.java @@ -0,0 +1,17 @@ +package domain.board; + +import domain.Piece; + +import java.util.Map; + +public class Board { + private final Map pieces; + + public Board(Map pieces) { + this.pieces = pieces; + } + + public Piece getPiece(Position position) { + return pieces.get(position); + } +} diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java new file mode 100644 index 0000000000..46e61e6979 --- /dev/null +++ b/src/main/java/domain/board/BoardFactory.java @@ -0,0 +1,43 @@ +package domain.board; + +import domain.Piece; +import domain.PieceType; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BoardFactory { + private static final List PAWN_COLUMNS = List.of(0, 2, 4, 6, 8); + private static final List ROOK_COLUMNS = List.of(0, 8); + private static final List ADVISOR_COLUMNS = List.of(3, 5); + + private BoardFactory() { + } + + public static Board createBoard(InitializeSetting initializeSetting) { + Map pieces = new HashMap<>(); + + List initialSetting = initializeSetting.getInitialSetting(); + for (Integer pawnColumn : PAWN_COLUMNS) { + pieces.put(new Position(pawnColumn, 6), new Piece(PieceType.PAWN)); + } + + for (Integer rookColumn : ROOK_COLUMNS) { + pieces.put(new Position(rookColumn, 9), new Piece(PieceType.ROOK)); + } + + for (Integer advisorColumn : ADVISOR_COLUMNS) { + pieces.put(new Position(advisorColumn, 9), new Piece(PieceType.ADVISOR)); + } + + pieces.put(new Position(4, 8), new Piece(PieceType.KING)); + + pieces.put(new Position(1, 9), new Piece(initialSetting.get(0))); + pieces.put(new Position(2, 9), new Piece(initialSetting.get(1))); + pieces.put(new Position(6, 9), new Piece(initialSetting.get(2))); + pieces.put(new Position(7, 9), new Piece(initialSetting.get(3))); + + return new Board(pieces); + } +} diff --git a/src/main/java/domain/board/InitializeSetting.java b/src/main/java/domain/board/InitializeSetting.java new file mode 100644 index 0000000000..dd93ee54cc --- /dev/null +++ b/src/main/java/domain/board/InitializeSetting.java @@ -0,0 +1,22 @@ +package domain.board; + +import domain.PieceType; + +import java.util.List; + +public enum InitializeSetting { + LEFT_ELEPHANT_SETTING(List.of(PieceType.ELEPHANT, PieceType.HORSE, PieceType.ELEPHANT, PieceType.HORSE)), + RIGHT_ELEPHANT_SETTING(List.of(PieceType.HORSE, PieceType.ELEPHANT, PieceType.HORSE, PieceType.ELEPHANT)), + INNER_ELEPHANT_SETTING(List.of(PieceType.HORSE, PieceType.ELEPHANT, PieceType.ELEPHANT, PieceType.HORSE)), + OUTER_ELEPHANT_SETTING(List.of(PieceType.ELEPHANT, PieceType.HORSE, PieceType.HORSE, PieceType.ELEPHANT)); + + private final List initialSetting; + + InitializeSetting(List initialSetting) { + this.initialSetting = initialSetting; + } + + public List getInitialSetting() { + return initialSetting; + } +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/board/Position.java similarity index 97% rename from src/main/java/domain/Position.java rename to src/main/java/domain/board/Position.java index 691b0b2282..a2bf13efda 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/board/Position.java @@ -1,4 +1,4 @@ -package domain; +package domain.board; import java.util.Objects; diff --git a/src/test/java/BoardTest.java b/src/test/java/BoardTest.java index 4e36452c8a..16ba65a5e1 100644 --- a/src/test/java/BoardTest.java +++ b/src/test/java/BoardTest.java @@ -1,7 +1,9 @@ -import domain.Board; +import domain.board.Board; import domain.Piece; import domain.PieceType; -import domain.Position; +import domain.board.BoardFactory; +import domain.board.InitializeSetting; +import domain.board.Position; import org.assertj.core.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -13,7 +15,7 @@ public class BoardTest { @ParameterizedTest @MethodSource("pawnProvider") void 졸을_올바른_위치에_초기화한다 (Position position) { - Board board = new Board(); + Board board = BoardFactory.createBoard(InitializeSetting.RIGHT_ELEPHANT_SETTING); Piece piece= board.getPiece(position); Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.PAWN); } diff --git a/src/test/java/PositionTest.java b/src/test/java/PositionTest.java index 8e76b5e859..9567848a84 100644 --- a/src/test/java/PositionTest.java +++ b/src/test/java/PositionTest.java @@ -1,6 +1,6 @@ import static org.assertj.core.api.Assertions.*; -import domain.Position; +import domain.board.Position; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; From 02d30c2284a1661105c15c23034ac8921ada23e0 Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 25 Mar 2026 13:34:49 +0900 Subject: [PATCH 05/58] =?UTF-8?q?fix(InitBoard):=20=EC=9E=A5=EA=B8=B0?= =?UTF-8?q?=ED=8C=90=20=EC=9B=90=EC=A0=90=20=EC=A2=8C=ED=91=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 원점을 좌하단으로 수정 - 누락된 포 초기화 로직 추가 --- README.md | 3 +- src/main/java/domain/board/BoardFactory.java | 21 +++-- src/test/java/BoardTest.java | 98 +++++++++++++++++--- 3 files changed, 98 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index bddc0945a4..f1987dd04c 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ ## 1. 보드 초기화 -- [ ] 보드의 크기는 9행 10열이다. +- [x] 보드의 크기는 9행 10열이다. - [ ] 초기 배치 방법은 4가지가 있다. - 마상 상마 (원앙마), 상마 상마 (귀마), 마상 마상 (귀마), 상마 마상 (양귀마) - [ ] 초기구현은 원앙마로만 제한한다. - [ ] 게임 시작 시, 각 진영마다 졸/병 5개, 포,상,마,차,사 2개, 궁 1개의 기물이 배치된다. +- [ ] 좌표의 원점은 플레이어의 좌하단을 기준으로 한다. diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java index 46e61e6979..1c6a0873a6 100644 --- a/src/main/java/domain/board/BoardFactory.java +++ b/src/main/java/domain/board/BoardFactory.java @@ -11,6 +11,7 @@ public class BoardFactory { private static final List PAWN_COLUMNS = List.of(0, 2, 4, 6, 8); private static final List ROOK_COLUMNS = List.of(0, 8); private static final List ADVISOR_COLUMNS = List.of(3, 5); + private static final List CANNON_COLUMNS = List.of(1, 7); private BoardFactory() { } @@ -20,23 +21,27 @@ public static Board createBoard(InitializeSetting initializeSetting) { List initialSetting = initializeSetting.getInitialSetting(); for (Integer pawnColumn : PAWN_COLUMNS) { - pieces.put(new Position(pawnColumn, 6), new Piece(PieceType.PAWN)); + pieces.put(new Position(pawnColumn, 3), new Piece(PieceType.PAWN)); } for (Integer rookColumn : ROOK_COLUMNS) { - pieces.put(new Position(rookColumn, 9), new Piece(PieceType.ROOK)); + pieces.put(new Position(rookColumn, 0), new Piece(PieceType.ROOK)); } for (Integer advisorColumn : ADVISOR_COLUMNS) { - pieces.put(new Position(advisorColumn, 9), new Piece(PieceType.ADVISOR)); + pieces.put(new Position(advisorColumn, 0), new Piece(PieceType.ADVISOR)); } - pieces.put(new Position(4, 8), new Piece(PieceType.KING)); + for (Integer cannonColumn : CANNON_COLUMNS) { + pieces.put(new Position(cannonColumn, 2), new Piece(PieceType.CANNON)); + } + + pieces.put(new Position(4, 1), new Piece(PieceType.KING)); - pieces.put(new Position(1, 9), new Piece(initialSetting.get(0))); - pieces.put(new Position(2, 9), new Piece(initialSetting.get(1))); - pieces.put(new Position(6, 9), new Piece(initialSetting.get(2))); - pieces.put(new Position(7, 9), new Piece(initialSetting.get(3))); + pieces.put(new Position(1, 0), new Piece(initialSetting.get(0))); + pieces.put(new Position(2, 0), new Piece(initialSetting.get(1))); + pieces.put(new Position(6, 0), new Piece(initialSetting.get(2))); + pieces.put(new Position(7, 0), new Piece(initialSetting.get(3))); return new Board(pieces); } diff --git a/src/test/java/BoardTest.java b/src/test/java/BoardTest.java index 16ba65a5e1..62111c53c0 100644 --- a/src/test/java/BoardTest.java +++ b/src/test/java/BoardTest.java @@ -5,6 +5,8 @@ import domain.board.InitializeSetting; import domain.board.Position; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -12,24 +14,90 @@ import java.util.stream.Stream; public class BoardTest { - @ParameterizedTest - @MethodSource("pawnProvider") - void 졸을_올바른_위치에_초기화한다 (Position position) { - Board board = BoardFactory.createBoard(InitializeSetting.RIGHT_ELEPHANT_SETTING); - Piece piece= board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.PAWN); - } + private Board board; - static Stream pawnProvider() { - return Stream.of( - Arguments.of(new Position(0, 6)), - Arguments.of(new Position(2, 6)), - Arguments.of(new Position(4, 6)), - Arguments.of(new Position(6, 6)), - Arguments.of(new Position(8, 6)) - ); + @BeforeEach + void setUp() { + board = BoardFactory.createBoard(InitializeSetting.RIGHT_ELEPHANT_SETTING); } + @Nested + class 기물_위치_테스트 { + + @ParameterizedTest + @MethodSource("pawnProvider") + void 졸을_올바른_위치에_초기화한다(Position position) { + Piece piece = board.getPiece(position); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.PAWN); + } + + static Stream pawnProvider() { + return Stream.of( + Arguments.of(new Position(0, 3)), + Arguments.of(new Position(2, 3)), + Arguments.of(new Position(4, 3)), + Arguments.of(new Position(6, 3)), + Arguments.of(new Position(8, 3)) + ); + } + + @ParameterizedTest + @MethodSource("rookProvider") + void 차를_올바른_위치에_초기화한다(Position position) { + Piece piece = board.getPiece(position); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.ROOK); + } + + static Stream rookProvider() { + return Stream.of( + Arguments.of(new Position(0, 0)), + Arguments.of(new Position(8, 0)) + ); + } + + @ParameterizedTest + @MethodSource("advisorProvider") + void 사를_올바른_위치에_초기화한다(Position position) { + Piece piece = board.getPiece(position); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.ADVISOR); + } + + static Stream advisorProvider() { + return Stream.of( + Arguments.of(new Position(3, 0)), + Arguments.of(new Position(5, 0)) + ); + } + + @ParameterizedTest + @MethodSource("kingProvider") + void 궁을_올바른_위치에_초기화한다(Position position) { + Piece piece = board.getPiece(position); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.KING); + } + + static Stream kingProvider() { + return Stream.of( + Arguments.of(new Position(4, 1)) + ); + } + + @ParameterizedTest + @MethodSource("cannonProvider") + void 포를_올바른_위치에_초기화한다(Position position) { + Piece piece = board.getPiece(position); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.CANNON); + } + + static Stream cannonProvider() { + return Stream.of( + Arguments.of(new Position(1, 2)), + Arguments.of(new Position(7, 2)) + ); + } + + + } } From bcff3b20e768a1deb92bfdfb786893eb6c498535 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Wed, 25 Mar 2026 15:31:31 +0900 Subject: [PATCH 06/58] =?UTF-8?q?refactor(InitBoard):=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EB=93=A4=EC=9D=98=20=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - KING -> GENERAL - ROOK -> CHARIOT - ADVISOR -> GUARD - PAWN -> SOLDIER --- src/main/java/domain/PieceType.java | 8 ++--- src/main/java/domain/board/BoardFactory.java | 20 ++++++------ src/test/java/BoardTest.java | 34 +++++++++----------- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/PieceType.java index 96a7877468..68f2a102cd 100644 --- a/src/main/java/domain/PieceType.java +++ b/src/main/java/domain/PieceType.java @@ -1,11 +1,11 @@ package domain; public enum PieceType { - KING, - ROOK, + GENERAL, + CHARIOT, CANNON, HORSE, ELEPHANT, - ADVISOR, - PAWN + GUARD, + SOLDIER } diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java index 1c6a0873a6..c88d5b5e4a 100644 --- a/src/main/java/domain/board/BoardFactory.java +++ b/src/main/java/domain/board/BoardFactory.java @@ -8,9 +8,9 @@ import java.util.Map; public class BoardFactory { - private static final List PAWN_COLUMNS = List.of(0, 2, 4, 6, 8); - private static final List ROOK_COLUMNS = List.of(0, 8); - private static final List ADVISOR_COLUMNS = List.of(3, 5); + private static final List SOLDIER_COLUMNS = List.of(0, 2, 4, 6, 8); + private static final List CHARIOT_COLUMNS = List.of(0, 8); + private static final List GUARD_COLUMNS = List.of(3, 5); private static final List CANNON_COLUMNS = List.of(1, 7); private BoardFactory() { @@ -20,23 +20,23 @@ public static Board createBoard(InitializeSetting initializeSetting) { Map pieces = new HashMap<>(); List initialSetting = initializeSetting.getInitialSetting(); - for (Integer pawnColumn : PAWN_COLUMNS) { - pieces.put(new Position(pawnColumn, 3), new Piece(PieceType.PAWN)); + for (Integer soliderColumns : SOLDIER_COLUMNS) { + pieces.put(new Position(soliderColumns, 3), new Piece(PieceType.SOLDIER)); } - for (Integer rookColumn : ROOK_COLUMNS) { - pieces.put(new Position(rookColumn, 0), new Piece(PieceType.ROOK)); + for (Integer chariotColumn : CHARIOT_COLUMNS) { + pieces.put(new Position(chariotColumn, 0), new Piece(PieceType.CHARIOT)); } - for (Integer advisorColumn : ADVISOR_COLUMNS) { - pieces.put(new Position(advisorColumn, 0), new Piece(PieceType.ADVISOR)); + for (Integer guardColumn : GUARD_COLUMNS) { + pieces.put(new Position(guardColumn, 0), new Piece(PieceType.GUARD)); } for (Integer cannonColumn : CANNON_COLUMNS) { pieces.put(new Position(cannonColumn, 2), new Piece(PieceType.CANNON)); } - pieces.put(new Position(4, 1), new Piece(PieceType.KING)); + pieces.put(new Position(4, 1), new Piece(PieceType.GENERAL)); pieces.put(new Position(1, 0), new Piece(initialSetting.get(0))); pieces.put(new Position(2, 0), new Piece(initialSetting.get(1))); diff --git a/src/test/java/BoardTest.java b/src/test/java/BoardTest.java index 62111c53c0..48d0c49f0f 100644 --- a/src/test/java/BoardTest.java +++ b/src/test/java/BoardTest.java @@ -7,6 +7,7 @@ import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -25,13 +26,13 @@ void setUp() { class 기물_위치_테스트 { @ParameterizedTest - @MethodSource("pawnProvider") + @MethodSource("soldierProvider") void 졸을_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.PAWN); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.SOLDIER); } - static Stream pawnProvider() { + static Stream soldierProvider() { return Stream.of( Arguments.of(new Position(0, 3)), Arguments.of(new Position(2, 3)), @@ -42,13 +43,13 @@ static Stream pawnProvider() { } @ParameterizedTest - @MethodSource("rookProvider") + @MethodSource("chariotProvider") void 차를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.ROOK); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.CHARIOT); } - static Stream rookProvider() { + static Stream chariotProvider() { return Stream.of( Arguments.of(new Position(0, 0)), Arguments.of(new Position(8, 0)) @@ -56,32 +57,27 @@ static Stream rookProvider() { } @ParameterizedTest - @MethodSource("advisorProvider") + @MethodSource("guardProvider") void 사를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.ADVISOR); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.GUARD); } - static Stream advisorProvider() { + static Stream guardProvider() { return Stream.of( Arguments.of(new Position(3, 0)), Arguments.of(new Position(5, 0)) ); } - @ParameterizedTest - @MethodSource("kingProvider") - void 궁을_올바른_위치에_초기화한다(Position position) { - Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.KING); - } - static Stream kingProvider() { - return Stream.of( - Arguments.of(new Position(4, 1)) - ); + @Test + void 궁을_올바른_위치에_초기화한다() { + Piece piece = board.getPiece(new Position(4, 1)); + Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.GENERAL); } + @ParameterizedTest @MethodSource("cannonProvider") void 포를_올바른_위치에_초기화한다(Position position) { From 07bc1ded926497ed9cc8bbabf51333e5430f61d5 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 15:53:51 +0900 Subject: [PATCH 07/58] =?UTF-8?q?refactor(InitBoard):=20Piece=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인터페이스 메서드로 getPathPositions, canMove를 가짐 - 각각의 기물 구현 클래스 추가 - BoardFactory 변경 - 테스트 코드 변경 --- src/main/java/domain/Piece.java | 4 -- src/main/java/domain/board/Board.java | 2 +- src/main/java/domain/board/BoardFactory.java | 39 +++++++++++++------ .../java/domain/board/InitializeSetting.java | 5 ++- src/main/java/domain/piece/Cannon.java | 17 ++++++++ src/main/java/domain/piece/Chariot.java | 17 ++++++++ src/main/java/domain/piece/Elephant.java | 17 ++++++++ src/main/java/domain/piece/General.java | 17 ++++++++ src/main/java/domain/piece/Guard.java | 17 ++++++++ src/main/java/domain/piece/Horse.java | 17 ++++++++ src/main/java/domain/piece/Piece.java | 14 +++++++ .../java/domain/{ => piece}/PieceType.java | 2 +- src/main/java/domain/piece/Soldier.java | 17 ++++++++ src/test/java/BoardTest.java | 27 +++++++------ 14 files changed, 181 insertions(+), 31 deletions(-) delete mode 100644 src/main/java/domain/Piece.java 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/General.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/Piece.java rename src/main/java/domain/{ => piece}/PieceType.java (83%) create mode 100644 src/main/java/domain/piece/Soldier.java diff --git a/src/main/java/domain/Piece.java b/src/main/java/domain/Piece.java deleted file mode 100644 index 7aeaa7591c..0000000000 --- a/src/main/java/domain/Piece.java +++ /dev/null @@ -1,4 +0,0 @@ -package domain; - -public record Piece(PieceType pieceType) { -} diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 509e9ef268..95112636a1 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -1,6 +1,6 @@ package domain.board; -import domain.Piece; +import domain.piece.Piece; import java.util.Map; diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java index c88d5b5e4a..4972ea33b4 100644 --- a/src/main/java/domain/board/BoardFactory.java +++ b/src/main/java/domain/board/BoardFactory.java @@ -1,7 +1,14 @@ package domain.board; -import domain.Piece; -import domain.PieceType; +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.PieceType; +import domain.piece.Soldier; import java.util.HashMap; import java.util.List; @@ -19,30 +26,38 @@ private BoardFactory() { public static Board createBoard(InitializeSetting initializeSetting) { Map pieces = new HashMap<>(); - List initialSetting = initializeSetting.getInitialSetting(); + for (Integer soliderColumns : SOLDIER_COLUMNS) { - pieces.put(new Position(soliderColumns, 3), new Piece(PieceType.SOLDIER)); + pieces.put(new Position(soliderColumns, 3), new Soldier(PieceType.SOLDIER)); } for (Integer chariotColumn : CHARIOT_COLUMNS) { - pieces.put(new Position(chariotColumn, 0), new Piece(PieceType.CHARIOT)); + pieces.put(new Position(chariotColumn, 0), new Chariot(PieceType.CHARIOT)); } for (Integer guardColumn : GUARD_COLUMNS) { - pieces.put(new Position(guardColumn, 0), new Piece(PieceType.GUARD)); + pieces.put(new Position(guardColumn, 0), new Guard(PieceType.GUARD)); } for (Integer cannonColumn : CANNON_COLUMNS) { - pieces.put(new Position(cannonColumn, 2), new Piece(PieceType.CANNON)); + pieces.put(new Position(cannonColumn, 2), new Cannon(PieceType.CANNON)); } - pieces.put(new Position(4, 1), new Piece(PieceType.GENERAL)); + pieces.put(new Position(4, 1), new General(PieceType.GENERAL)); - pieces.put(new Position(1, 0), new Piece(initialSetting.get(0))); - pieces.put(new Position(2, 0), new Piece(initialSetting.get(1))); - pieces.put(new Position(6, 0), new Piece(initialSetting.get(2))); - pieces.put(new Position(7, 0), new Piece(initialSetting.get(3))); + List initialSetting = initializeSetting.getInitialSetting(); + pieces.put(new Position(1, 0), createPiece(initialSetting.get(0))); + pieces.put(new Position(2, 0), createPiece(initialSetting.get(1))); + pieces.put(new Position(6, 0), createPiece(initialSetting.get(2))); + pieces.put(new Position(7, 0), createPiece(initialSetting.get(3))); return new Board(pieces); } + + private static Piece createPiece(PieceType pieceType) { + if (pieceType == PieceType.ELEPHANT) { + return new Elephant(pieceType); + } + return new Horse(pieceType); + } } diff --git a/src/main/java/domain/board/InitializeSetting.java b/src/main/java/domain/board/InitializeSetting.java index dd93ee54cc..6df7c9fc77 100644 --- a/src/main/java/domain/board/InitializeSetting.java +++ b/src/main/java/domain/board/InitializeSetting.java @@ -1,6 +1,6 @@ package domain.board; -import domain.PieceType; +import domain.piece.PieceType; import java.util.List; @@ -19,4 +19,7 @@ public enum InitializeSetting { public List getInitialSetting() { return initialSetting; } + + + } diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java new file mode 100644 index 0000000000..ebcd3a2e68 --- /dev/null +++ b/src/main/java/domain/piece/Cannon.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record Cannon(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java new file mode 100644 index 0000000000..c34382235e --- /dev/null +++ b/src/main/java/domain/piece/Chariot.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record Chariot(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java new file mode 100644 index 0000000000..89e7bc7a29 --- /dev/null +++ b/src/main/java/domain/piece/Elephant.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record Elephant(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/General.java new file mode 100644 index 0000000000..6ab38983d9 --- /dev/null +++ b/src/main/java/domain/piece/General.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record General(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java new file mode 100644 index 0000000000..5a97e43ed9 --- /dev/null +++ b/src/main/java/domain/piece/Guard.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record Guard(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java new file mode 100644 index 0000000000..f13a38503d --- /dev/null +++ b/src/main/java/domain/piece/Horse.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record Horse(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java new file mode 100644 index 0000000000..ad4bd79c90 --- /dev/null +++ b/src/main/java/domain/piece/Piece.java @@ -0,0 +1,14 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public interface Piece { + // piece가 from에서 해당 도착지 to로 도착할 수 있는지 없다면 예외를 던진다 + // from에서 to까지의 경로 Position을 반환 + List getPathPositions(Position from, Position to); + + // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) + void canMove(List pathWithPiece); +} diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/piece/PieceType.java similarity index 83% rename from src/main/java/domain/PieceType.java rename to src/main/java/domain/piece/PieceType.java index 68f2a102cd..1ef8954a54 100644 --- a/src/main/java/domain/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,4 +1,4 @@ -package domain; +package domain.piece; public enum PieceType { GENERAL, diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java new file mode 100644 index 0000000000..5a980e2124 --- /dev/null +++ b/src/main/java/domain/piece/Soldier.java @@ -0,0 +1,17 @@ +package domain.piece; + +import domain.board.Position; + +import java.util.List; + +public record Soldier(PieceType pieceType) implements Piece { + @Override + public List getPathPositions(Position from, Position to) { + return List.of(); + } + + @Override + public void canMove(List pathWithPiece) { + + } +} diff --git a/src/test/java/BoardTest.java b/src/test/java/BoardTest.java index 48d0c49f0f..c4c2101fc1 100644 --- a/src/test/java/BoardTest.java +++ b/src/test/java/BoardTest.java @@ -1,10 +1,15 @@ import domain.board.Board; -import domain.Piece; -import domain.PieceType; +import domain.piece.Cannon; +import domain.piece.Chariot; +import domain.piece.General; +import domain.piece.Guard; +import domain.piece.Piece; + import domain.board.BoardFactory; import domain.board.InitializeSetting; import domain.board.Position; -import org.assertj.core.api.Assertions; +import domain.piece.Soldier; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -14,6 +19,8 @@ import java.util.stream.Stream; +import static org.assertj.core.api.Assertions.assertThat; + public class BoardTest { private Board board; @@ -29,7 +36,7 @@ class 기물_위치_테스트 { @MethodSource("soldierProvider") void 졸을_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.SOLDIER); + assertThat(piece).isInstanceOf(Soldier.class); } static Stream soldierProvider() { @@ -46,7 +53,7 @@ static Stream soldierProvider() { @MethodSource("chariotProvider") void 차를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.CHARIOT); + assertThat(piece).isInstanceOf(Chariot.class); } static Stream chariotProvider() { @@ -60,7 +67,7 @@ static Stream chariotProvider() { @MethodSource("guardProvider") void 사를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.GUARD); + assertThat(piece).isInstanceOf(Guard.class); } static Stream guardProvider() { @@ -74,7 +81,7 @@ static Stream guardProvider() { @Test void 궁을_올바른_위치에_초기화한다() { Piece piece = board.getPiece(new Position(4, 1)); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.GENERAL); + assertThat(piece).isInstanceOf(General.class); } @@ -82,7 +89,7 @@ static Stream guardProvider() { @MethodSource("cannonProvider") void 포를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - Assertions.assertThat(piece.pieceType()).isEqualTo(PieceType.CANNON); + assertThat(piece).isInstanceOf(Cannon.class); } static Stream cannonProvider() { @@ -91,9 +98,5 @@ static Stream cannonProvider() { Arguments.of(new Position(7, 2)) ); } - - } - - } From f37bd6715b9c7a181f8b22a123aef0d53be62d3b Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 17:06:03 +0900 Subject: [PATCH 08/58] =?UTF-8?q?feat(PieceMove):=20=EC=A1=B8,=20=EA=B6=81?= =?UTF-8?q?,=20=EC=82=AC=EC=97=90=20=EB=8C=80=ED=95=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B2=BD=EB=A1=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 방향에 대한 Direction 구현 - 졸 움직임 이동 경로 구현 - 사 움직임 이동 경로 구현 - 궁 움직임 이동 경로 구현 - 테스트 패키지 위치 수정 --- src/main/java/domain/Direction.java | 26 ++++++++ src/main/java/domain/board/Position.java | 10 ++++ src/main/java/domain/piece/General.java | 13 +++- src/main/java/domain/piece/Guard.java | 14 ++++- src/main/java/domain/piece/Soldier.java | 15 ++++- .../java/{ => domain/board}/BoardTest.java | 6 +- .../java/{ => domain/board}/PositionTest.java | 3 +- src/test/java/domain/piece/GeneralTest.java | 59 +++++++++++++++++++ src/test/java/domain/piece/GuardTest.java | 59 +++++++++++++++++++ src/test/java/domain/piece/SoldierTest.java | 51 ++++++++++++++++ 10 files changed, 248 insertions(+), 8 deletions(-) create mode 100644 src/main/java/domain/Direction.java rename src/test/java/{ => domain/board}/BoardTest.java (95%) rename src/test/java/{ => domain/board}/PositionTest.java (96%) create mode 100644 src/test/java/domain/piece/GeneralTest.java create mode 100644 src/test/java/domain/piece/GuardTest.java create mode 100644 src/test/java/domain/piece/SoldierTest.java diff --git a/src/main/java/domain/Direction.java b/src/main/java/domain/Direction.java new file mode 100644 index 0000000000..76a3f8f262 --- /dev/null +++ b/src/main/java/domain/Direction.java @@ -0,0 +1,26 @@ +package domain; + +import domain.board.Position; + +public enum Direction { + UP(0, 1), + DOWN(0, -1), + LEFT(-1, 0), + RIGHT(1, 0); + + private final int dx; + private final int dy; + + Direction(int dx, int dy) { + this.dx = dx; + this.dy = dy; + } + + public int getDx() { + return dx; + } + + public int getDy() { + return dy; + } +} diff --git a/src/main/java/domain/board/Position.java b/src/main/java/domain/board/Position.java index a2bf13efda..2e9f415e0b 100644 --- a/src/main/java/domain/board/Position.java +++ b/src/main/java/domain/board/Position.java @@ -39,4 +39,14 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(x, y); } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + } diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/General.java index 6ab38983d9..15f9e5c062 100644 --- a/src/main/java/domain/piece/General.java +++ b/src/main/java/domain/piece/General.java @@ -7,7 +7,18 @@ public record General(PieceType pieceType) implements Piece { @Override public List getPathPositions(Position from, Position to) { - return List.of(); + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + boolean isMoveUp = dx == 0 && dy == 1; + boolean isMoveLeft = dx == -1 && dy == 0; + boolean isMoveRight = dx == 1 && dy == 0; + boolean isMoveDown = dx == 0 && dy == -1; + + if(!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { + throw new IllegalArgumentException("움직일 수 없는 위치입니다."); + } + return List.of(to); } @Override diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java index 5a97e43ed9..aa49cbc816 100644 --- a/src/main/java/domain/piece/Guard.java +++ b/src/main/java/domain/piece/Guard.java @@ -7,7 +7,19 @@ public record Guard(PieceType pieceType) implements Piece { @Override public List getPathPositions(Position from, Position to) { - return List.of(); + + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + boolean isMoveUp = dx == 0 && dy == 1; + boolean isMoveLeft = dx == -1 && dy == 0; + boolean isMoveRight = dx == 1 && dy == 0; + boolean isMoveDown = dx == 0 && dy == -1; + + if(!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { + throw new IllegalArgumentException("움직일 수 없는 위치입니다."); + } + return List.of(to); } @Override diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java index 5a980e2124..184106a8b4 100644 --- a/src/main/java/domain/piece/Soldier.java +++ b/src/main/java/domain/piece/Soldier.java @@ -1,13 +1,26 @@ package domain.piece; +import domain.Direction; import domain.board.Position; import java.util.List; public record Soldier(PieceType pieceType) implements Piece { + @Override public List getPathPositions(Position from, Position to) { - return List.of(); + + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + boolean isMoveUp = dx == 0 && dy == 1; + boolean isMoveLeft = dx == -1 && dy == 0; + boolean isMoveRight = dx == 1 && dy == 0; + + if(!(isMoveLeft || isMoveRight || isMoveUp)) { + throw new IllegalArgumentException("움직일 수 없는 위치입니다."); + } + return List.of(to); } @Override diff --git a/src/test/java/BoardTest.java b/src/test/java/domain/board/BoardTest.java similarity index 95% rename from src/test/java/BoardTest.java rename to src/test/java/domain/board/BoardTest.java index c4c2101fc1..fbaa36a3f7 100644 --- a/src/test/java/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -1,13 +1,11 @@ -import domain.board.Board; +package domain.board; + import domain.piece.Cannon; import domain.piece.Chariot; import domain.piece.General; import domain.piece.Guard; import domain.piece.Piece; -import domain.board.BoardFactory; -import domain.board.InitializeSetting; -import domain.board.Position; import domain.piece.Soldier; import org.junit.jupiter.api.BeforeEach; diff --git a/src/test/java/PositionTest.java b/src/test/java/domain/board/PositionTest.java similarity index 96% rename from src/test/java/PositionTest.java rename to src/test/java/domain/board/PositionTest.java index 9567848a84..dbc1160b58 100644 --- a/src/test/java/PositionTest.java +++ b/src/test/java/domain/board/PositionTest.java @@ -1,6 +1,7 @@ +package domain.board; + import static org.assertj.core.api.Assertions.*; -import domain.board.Position; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/test/java/domain/piece/GeneralTest.java b/src/test/java/domain/piece/GeneralTest.java new file mode 100644 index 0000000000..5bef5346dd --- /dev/null +++ b/src/test/java/domain/piece/GeneralTest.java @@ -0,0 +1,59 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GeneralTest { + private General general; + + @BeforeEach + void setUp() { + general = new General(PieceType.GENERAL); + } + + @Test + void 궁은_위로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(4, 1); + Position to = new Position(4,2); + + List pathPositions = general.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 2))); + } + + @Test + void 궁은_좌로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(4, 1); + Position to = new Position(3, 1); + + List pathPositions = general.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(3, 1))); + } + + @Test + void 궁은_우로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(4, 1); + Position to = new Position(5, 1); + + List pathPositions = general.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 1))); + } + + + @Test + void 궁은_아래로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(4, 1); + Position to = new Position(4, 0); + + List pathPositions = general.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 0))); + } +} diff --git a/src/test/java/domain/piece/GuardTest.java b/src/test/java/domain/piece/GuardTest.java new file mode 100644 index 0000000000..18409ba0a1 --- /dev/null +++ b/src/test/java/domain/piece/GuardTest.java @@ -0,0 +1,59 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GuardTest { + private Guard guard; + + @BeforeEach + void setUp() { + guard = new Guard(PieceType.GUARD); + } + + @Test + void 사는_위로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(3, 0); + Position to = new Position(3, 1); + + List pathPositions = guard.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(3, 1))); + } + + @Test + void 사는_좌로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 0); + Position to = new Position(4, 0); + + List pathPositions = guard.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 0))); + } + + @Test + void 졸은_우로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(3, 0); + Position to = new Position(4, 0); + + List pathPositions = guard.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 0))); + } + + + @Test + void 사는_아래로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(3, 1); + Position to = new Position(3, 0); + + List pathPositions = guard.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(3, 0))); + } +} diff --git a/src/test/java/domain/piece/SoldierTest.java b/src/test/java/domain/piece/SoldierTest.java new file mode 100644 index 0000000000..1709064792 --- /dev/null +++ b/src/test/java/domain/piece/SoldierTest.java @@ -0,0 +1,51 @@ +package domain.piece; + +import domain.board.Position; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SoldierTest { + + private Soldier soldier; + + @BeforeEach + void setUp() { + soldier = new Soldier(PieceType.SOLDIER); + } + + @Test + void 졸은_위로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(0, 3); + Position to = new Position(0, 4); + + List pathPositions = soldier.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(0, 4))); + } + + @Test + void 졸은_좌로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(2, 3); + Position to = new Position(1, 3); + + List pathPositions = soldier.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + } + + @Test + void 졸은_우로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(0, 3); + Position to = new Position(1, 3); + + List pathPositions = soldier.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + } + +} From 2fdf8a0216df3cd9f3a9248b82d5cf4d76cbf443 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 17:29:12 +0900 Subject: [PATCH 09/58] =?UTF-8?q?feat(PieceMove):=20=EB=A7=88=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=9D=B4=EB=8F=99=20=EA=B2=BD=EB=A1=9C=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 - 마에 대한 이동 경로 구현 --- src/main/java/domain/board/Board.java | 12 +++ src/main/java/domain/board/Position.java | 5 ++ src/main/java/domain/piece/Horse.java | 37 +++++++- src/test/java/domain/piece/HorseTest.java | 105 ++++++++++++++++++++++ 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/test/java/domain/piece/HorseTest.java diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 95112636a1..f1714e5acf 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -2,6 +2,7 @@ import domain.piece.Piece; +import java.util.List; import java.util.Map; public class Board { @@ -14,4 +15,15 @@ public Board(Map pieces) { public Piece getPiece(Position position) { return pieces.get(position); } + + public void move(Position from, Position to){ + // 해당 위치(from)에 기물이 위치하고 있는지 + // (1) piece 가 해당 도착지(to)로 도착하는 경로 반환 : Piece의 getPathPositions 호출 + // (2) 1에서 받은 값으로 getPathWithPiece 호출하여 Piece의 canMove 호출 + } + + // positions(기물이 갈 경로)에 위치한 기물 정보를 반환 + public List getPathWithPiece(List positions){ + return null; + } } diff --git a/src/main/java/domain/board/Position.java b/src/main/java/domain/board/Position.java index 2e9f415e0b..f67792ffb2 100644 --- a/src/main/java/domain/board/Position.java +++ b/src/main/java/domain/board/Position.java @@ -1,5 +1,7 @@ package domain.board; +import domain.Direction; + import java.util.Objects; public class Position { @@ -48,5 +50,8 @@ public int getY() { return y; } + public Position next(Direction direction) { + return new Position(x + direction.getDx(), y + direction.getDy()); + } } diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java index f13a38503d..5235ab4146 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/Horse.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.Direction; import domain.board.Position; import java.util.List; @@ -7,7 +8,41 @@ public record Horse(PieceType pieceType) implements Piece { @Override public List getPathPositions(Position from, Position to) { - return List.of(); + + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + Direction xDirection = decideXDirection(dx); + Direction yDirection = decideYDirection(dy); + + Direction mainDirection; + Direction subDirection; + if (Math.abs(dx) > Math.abs(dy)) { + mainDirection = xDirection; + subDirection = yDirection; + } else { + mainDirection = yDirection; + subDirection = xDirection; + } + + Position step1 = from.next(mainDirection); + Position step2 = step1.next(mainDirection).next(subDirection); + + + return List.of(step1, step2); + } + private Direction decideXDirection(int dx) { + if (dx > 0) { + return Direction.RIGHT; + } + return Direction.LEFT; + } + + private Direction decideYDirection(int dy) { + if (dy > 0) { + return Direction.UP; + } + return Direction.DOWN; } @Override diff --git a/src/test/java/domain/piece/HorseTest.java b/src/test/java/domain/piece/HorseTest.java new file mode 100644 index 0000000000..a3bb242fc3 --- /dev/null +++ b/src/test/java/domain/piece/HorseTest.java @@ -0,0 +1,105 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class HorseTest { + private Horse horse; + + @BeforeEach + void setUp() { + horse = new Horse(PieceType.HORSE); + } + + @Test + void 마는_위로_두칸_왼쪽으로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(4, 7); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(4, 7))); + } + + @Test + void 마는_위로_두칸_오른쪽으로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(6, 7); + + List pathPositions = horse.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(6, 7))); + } + + + @Test + void 마는_위로_한칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(3, 6); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 6))); + } + + + @Test + void 마는_아래로_한칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(3, 4); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 4))); + } + + + @Test + void 마는_아래로_두칸_왼쪽으로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(4, 3); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(4, 3))); + } + + + @Test + void 마는_아래로_두칸_오른쪽으로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(6, 3); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(6, 3))); + } + + + @Test + void 마는_위로_한칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(7, 6); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); + } + + + @Test + void 마는_아래로_한칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(7, 6); + + List pathPositions = horse.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); + } +} From 44b13c5849eaa8cb5a983764461d5d6833c6663f Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 17:36:49 +0900 Subject: [PATCH 10/58] =?UTF-8?q?feat(PieceMove):=20=EC=83=81=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=9D=B4=EB=8F=99=20=EA=B2=BD=EB=A1=9C=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 - 상에 대한 이동 경로 구현 - Horse 공백 추가 --- src/main/java/domain/piece/Elephant.java | 38 ++++++- src/main/java/domain/piece/Horse.java | 1 + src/test/java/domain/piece/ElephantTest.java | 105 +++++++++++++++++++ 3 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/test/java/domain/piece/ElephantTest.java diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java index 89e7bc7a29..0136661f83 100644 --- a/src/main/java/domain/piece/Elephant.java +++ b/src/main/java/domain/piece/Elephant.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.Direction; import domain.board.Position; import java.util.List; @@ -7,7 +8,42 @@ public record Elephant(PieceType pieceType) implements Piece { @Override public List getPathPositions(Position from, Position to) { - return List.of(); + + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + Direction xDirection = decideXDirection(dx); + Direction yDirection = decideYDirection(dy); + + Direction mainDirection; + Direction subDirection; + if (Math.abs(dx) > Math.abs(dy)) { + mainDirection = xDirection; + subDirection = yDirection; + } else { + mainDirection = yDirection; + subDirection = xDirection; + } + + Position step1 = from.next(mainDirection); + Position step2 = step1.next(mainDirection).next(subDirection); + Position step3 = step2.next(mainDirection).next(subDirection); + + return List.of(step1, step2, step3); + } + + private Direction decideXDirection(int dx) { + if (dx > 0) { + return Direction.RIGHT; + } + return Direction.LEFT; + } + + private Direction decideYDirection(int dy) { + if (dy > 0) { + return Direction.UP; + } + return Direction.DOWN; } @Override diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java index 5235ab4146..6dfb2106d6 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/Horse.java @@ -31,6 +31,7 @@ public List getPathPositions(Position from, Position to) { return List.of(step1, step2); } + private Direction decideXDirection(int dx) { if (dx > 0) { return Direction.RIGHT; diff --git a/src/test/java/domain/piece/ElephantTest.java b/src/test/java/domain/piece/ElephantTest.java new file mode 100644 index 0000000000..71bb859ac4 --- /dev/null +++ b/src/test/java/domain/piece/ElephantTest.java @@ -0,0 +1,105 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ElephantTest { + private Elephant elephant; + + @BeforeEach + void setUp() { + elephant = new Elephant(PieceType.ELEPHANT); + } + + @Test + void 상은_위로_세칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(3, 8); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(4, 7), new Position(3, 8))); + } + + @Test + void 상은_위로_세칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(6, 7); + + List pathPositions = elephant.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(6, 7), new Position(7, 8))); + } + + + @Test + void 마는_위로_두칸_왼쪽으로_세칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(2, 7); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 6), new Position(2, 7))); + } + + + @Test + void 마는_아래로_두칸_왼쪽으로_세칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(2, 3); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 4), new Position(2, 3))); + } + + + @Test + void 마는_아래로_세칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(3, 2); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(4, 3), new Position(3, 2))); + } + + + @Test + void 마는_아래로_세칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(7, 2); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(6, 3), new Position(7, 2))); + } + + + @Test + void 상은_위로_두칸_오른쪽으로_세칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(8, 7); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6), new Position(8, 7))); + } + + + @Test + void 상은_아래로_두칸_오른쪽으로_세칸_움직일_수_있는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(8, 7); + + List pathPositions = elephant.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6), new Position(8, 7))); + } +} From f7c7a9ddbe11426cb471f29abde90d45b9f187da Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 17:53:52 +0900 Subject: [PATCH 11/58] =?UTF-8?q?feat(PieceMove):=20=EC=B0=A8=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=9D=B4=EB=8F=99=20=EA=B2=BD=EB=A1=9C=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 - 차에 대한 이동 경로 구현 --- src/main/java/domain/piece/Chariot.java | 44 ++++++++++++- src/test/java/domain/piece/ChariotTest.java | 69 +++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/test/java/domain/piece/ChariotTest.java diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java index c34382235e..721ba4d5b8 100644 --- a/src/main/java/domain/piece/Chariot.java +++ b/src/main/java/domain/piece/Chariot.java @@ -1,15 +1,57 @@ package domain.piece; +import domain.Direction; import domain.board.Position; +import java.util.ArrayList; import java.util.List; public record Chariot(PieceType pieceType) implements Piece { @Override public List getPathPositions(Position from, Position to) { - return List.of(); + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))){ + throw new IllegalArgumentException("차를 해당 위치로 옮길 수 없습니다."); + } + + Direction mainDirection; + int distance; + if (dx == 0) { + mainDirection = decideYDirection(dy); + distance = Math.abs(dy); + } else { + mainDirection = decideXDirection(dx); + distance = Math.abs(dx); + } + + Position step = from; + + List route = new ArrayList<>(); + for (int i = 0; i < distance; i++) { + step = step.next(mainDirection); + route.add(step); + } + + return route; } + private Direction decideXDirection(int dx) { + if (dx > 0) { + return Direction.RIGHT; + } + return Direction.LEFT; + } + + private Direction decideYDirection(int dy) { + if (dy > 0) { + return Direction.UP; + } + return Direction.DOWN; + } + + @Override public void canMove(List pathWithPiece) { diff --git a/src/test/java/domain/piece/ChariotTest.java b/src/test/java/domain/piece/ChariotTest.java new file mode 100644 index 0000000000..7580c028e6 --- /dev/null +++ b/src/test/java/domain/piece/ChariotTest.java @@ -0,0 +1,69 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class ChariotTest { + + private Chariot chariot; + + @BeforeEach + void setUp() { + chariot = new Chariot(PieceType.CHARIOT); + } + + @Test + void 차는_왼쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(2, 5); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5), new Position(2, 5))); + } + + @Test + void 차는_오른쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(8, 5); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5), new Position(8, 5))); + } + + + @Test + void 차는_위쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(5, 7); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(5, 7))); + } + + + @Test + void 차는_아래쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(5, 0); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of( + new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1), new Position(5, 0))); + } + + + +} From e6d3cfbee1a3e8bcefbddad81980fac8ba1b397c Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 17:57:27 +0900 Subject: [PATCH 12/58] =?UTF-8?q?feat(PieceMove):=20=ED=8F=AC=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=EC=9D=B4=EB=8F=99=20=EA=B2=BD=EB=A1=9C=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 - 포에 대한 이동 경로 구현 --- src/main/java/domain/piece/Cannon.java | 44 +++++++++++++- src/test/java/domain/piece/CannonTest.java | 67 ++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 src/test/java/domain/piece/CannonTest.java diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java index ebcd3a2e68..ddad972829 100644 --- a/src/main/java/domain/piece/Cannon.java +++ b/src/main/java/domain/piece/Cannon.java @@ -1,15 +1,57 @@ package domain.piece; +import domain.Direction; import domain.board.Position; +import java.util.ArrayList; import java.util.List; public record Cannon(PieceType pieceType) implements Piece { @Override public List getPathPositions(Position from, Position to) { - return List.of(); + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))){ + throw new IllegalArgumentException("차를 해당 위치로 옮길 수 없습니다."); + } + + Direction mainDirection; + int distance; + if (dx == 0) { + mainDirection = decideYDirection(dy); + distance = Math.abs(dy); + } else { + mainDirection = decideXDirection(dx); + distance = Math.abs(dx); + } + + Position step = from; + + List route = new ArrayList<>(); + for (int i = 0; i < distance; i++) { + step = step.next(mainDirection); + route.add(step); + } + + return route; } + private Direction decideXDirection(int dx) { + if (dx > 0) { + return Direction.RIGHT; + } + return Direction.LEFT; + } + + private Direction decideYDirection(int dy) { + if (dy > 0) { + return Direction.UP; + } + return Direction.DOWN; + } + + @Override public void canMove(List pathWithPiece) { diff --git a/src/test/java/domain/piece/CannonTest.java b/src/test/java/domain/piece/CannonTest.java new file mode 100644 index 0000000000..adf05fbbec --- /dev/null +++ b/src/test/java/domain/piece/CannonTest.java @@ -0,0 +1,67 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class CannonTest { + + private Chariot chariot; + + @BeforeEach + void setUp() { + chariot = new Chariot(PieceType.CHARIOT); + } + + @Test + void 포는_왼쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(2, 5); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5), new Position(2, 5))); + } + + @Test + void 포는_오른쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(8, 5); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5), new Position(8, 5))); + } + + + @Test + void 포는_위쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(5, 7); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(5, 7))); + } + + + @Test + void 포는_아래쪽_직선으로_가는_경로가_있다() { + Position from = new Position(5, 5); + Position to = new Position(5, 0); + + List pathPositions = chariot.getPathPositions(from, to); + + + assertThat(pathPositions).isEqualTo(List.of( + new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1), new Position(5, 0))); + } + +} From 1a309174c3d0a78d64f85629a09681b857d47790 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Thu, 26 Mar 2026 20:01:44 +0900 Subject: [PATCH 13/58] =?UTF-8?q?feat(InitBoard):=20=EC=B4=88/=ED=95=9C=20?= =?UTF-8?q?=EC=A7=84=EC=98=81=EC=97=90=20=EB=8C=80=ED=95=9C=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=A0=95=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 초는 아래에 한은 위에 생성 - 졸/병 움직임을 다른 방향으로 작성 --- src/main/java/domain/board/Board.java | 1 + src/main/java/domain/board/BoardFactory.java | 44 ++++++++++------ 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/Soldier.java | 12 +++-- src/main/java/domain/piece/Team.java | 5 ++ src/test/java/domain/board/BoardTest.java | 2 +- src/test/java/domain/piece/CannonTest.java | 2 +- src/test/java/domain/piece/ChariotTest.java | 2 +- src/test/java/domain/piece/ElephantTest.java | 2 +- src/test/java/domain/piece/GeneralTest.java | 2 +- src/test/java/domain/piece/GuardTest.java | 2 +- src/test/java/domain/piece/HorseTest.java | 2 +- .../{SoldierTest.java => SoldierChoTest.java} | 5 +- .../java/domain/piece/SoldierHanTest.java | 50 +++++++++++++++++++ 19 files changed, 109 insertions(+), 34 deletions(-) create mode 100644 src/main/java/domain/piece/Team.java rename src/test/java/domain/piece/{SoldierTest.java => SoldierChoTest.java} (92%) create mode 100644 src/test/java/domain/piece/SoldierHanTest.java diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index f1714e5acf..156dab81cf 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -19,6 +19,7 @@ public Piece getPiece(Position position) { public void move(Position from, Position to){ // 해당 위치(from)에 기물이 위치하고 있는지 // (1) piece 가 해당 도착지(to)로 도착하는 경로 반환 : Piece의 getPathPositions 호출 + // 상대편 위치, 지금할껀지 or 있다가 할껀지, 초/한 // (2) 1에서 받은 값으로 getPathWithPiece 호출하여 Piece의 canMove 호출 } diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java index 4972ea33b4..4586eaf29a 100644 --- a/src/main/java/domain/board/BoardFactory.java +++ b/src/main/java/domain/board/BoardFactory.java @@ -9,6 +9,7 @@ import domain.piece.Piece; import domain.piece.PieceType; import domain.piece.Soldier; +import domain.piece.Team; import java.util.HashMap; import java.util.List; @@ -23,41 +24,56 @@ public class BoardFactory { private BoardFactory() { } - public static Board createBoard(InitializeSetting initializeSetting) { + public static Board createBoard(InitializeSetting choInitialSetting, InitializeSetting hanInitialSetting) { Map pieces = new HashMap<>(); for (Integer soliderColumns : SOLDIER_COLUMNS) { - pieces.put(new Position(soliderColumns, 3), new Soldier(PieceType.SOLDIER)); + pieces.put(new Position(soliderColumns, 3), new Soldier(PieceType.SOLDIER, Team.CHO)); + pieces.put(new Position(soliderColumns, 6), new Soldier(PieceType.SOLDIER, Team.HAN)); } for (Integer chariotColumn : CHARIOT_COLUMNS) { - pieces.put(new Position(chariotColumn, 0), new Chariot(PieceType.CHARIOT)); + pieces.put(new Position(chariotColumn, 0), new Chariot(PieceType.CHARIOT, Team.CHO)); + pieces.put(new Position(chariotColumn, 9), new Chariot(PieceType.CHARIOT, Team.HAN)); + } for (Integer guardColumn : GUARD_COLUMNS) { - pieces.put(new Position(guardColumn, 0), new Guard(PieceType.GUARD)); + pieces.put(new Position(guardColumn, 0), new Guard(PieceType.GUARD, Team.CHO)); + pieces.put(new Position(guardColumn, 9), new Guard(PieceType.GUARD, Team.HAN)); + } for (Integer cannonColumn : CANNON_COLUMNS) { - pieces.put(new Position(cannonColumn, 2), new Cannon(PieceType.CANNON)); + pieces.put(new Position(cannonColumn, 2), new Cannon(PieceType.CANNON, Team.CHO)); + pieces.put(new Position(cannonColumn, 7), new Cannon(PieceType.CANNON, Team.HAN)); + } - pieces.put(new Position(4, 1), new General(PieceType.GENERAL)); + pieces.put(new Position(4, 1), new General(PieceType.GENERAL, Team.CHO)); + pieces.put(new Position(4, 8), new General(PieceType.GENERAL, Team.HAN)); + + List choSetting = choInitialSetting.getInitialSetting(); + pieces.put(new Position(1, 0), createPiece(choSetting.get(0), Team.CHO)); + pieces.put(new Position(2, 0), createPiece(choSetting.get(1), Team.CHO)); + pieces.put(new Position(6, 0), createPiece(choSetting.get(2), Team.CHO)); + pieces.put(new Position(7, 0), createPiece(choSetting.get(3), Team.CHO)); + + List hanSetting = hanInitialSetting.getInitialSetting(); + pieces.put(new Position(1, 9), createPiece(hanSetting.get(0), Team.HAN)); + pieces.put(new Position(2, 9), createPiece(hanSetting.get(1), Team.HAN)); + pieces.put(new Position(6, 9), createPiece(hanSetting.get(2), Team.HAN)); + pieces.put(new Position(7, 9), createPiece(hanSetting.get(3), Team.HAN)); - List initialSetting = initializeSetting.getInitialSetting(); - pieces.put(new Position(1, 0), createPiece(initialSetting.get(0))); - pieces.put(new Position(2, 0), createPiece(initialSetting.get(1))); - pieces.put(new Position(6, 0), createPiece(initialSetting.get(2))); - pieces.put(new Position(7, 0), createPiece(initialSetting.get(3))); return new Board(pieces); } - private static Piece createPiece(PieceType pieceType) { + private static Piece createPiece(PieceType pieceType, Team team) { if (pieceType == PieceType.ELEPHANT) { - return new Elephant(pieceType); + return new Elephant(pieceType, team); } - return new Horse(pieceType); + return new Horse(pieceType, team); } } diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java index ddad972829..b82cf74d63 100644 --- a/src/main/java/domain/piece/Cannon.java +++ b/src/main/java/domain/piece/Cannon.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.List; -public record Cannon(PieceType pieceType) implements Piece { +public record Cannon(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java index 721ba4d5b8..6de04ff9b0 100644 --- a/src/main/java/domain/piece/Chariot.java +++ b/src/main/java/domain/piece/Chariot.java @@ -6,7 +6,7 @@ import java.util.ArrayList; import java.util.List; -public record Chariot(PieceType pieceType) implements Piece { +public record Chariot(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java index 0136661f83..1ff120fddf 100644 --- a/src/main/java/domain/piece/Elephant.java +++ b/src/main/java/domain/piece/Elephant.java @@ -5,7 +5,7 @@ import java.util.List; -public record Elephant(PieceType pieceType) implements Piece { +public record Elephant(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/General.java index 15f9e5c062..594f0c0ee6 100644 --- a/src/main/java/domain/piece/General.java +++ b/src/main/java/domain/piece/General.java @@ -4,7 +4,7 @@ import java.util.List; -public record General(PieceType pieceType) implements Piece { +public record General(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java index aa49cbc816..30f6ca323a 100644 --- a/src/main/java/domain/piece/Guard.java +++ b/src/main/java/domain/piece/Guard.java @@ -4,7 +4,7 @@ import java.util.List; -public record Guard(PieceType pieceType) implements Piece { +public record Guard(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java index 6dfb2106d6..87178ddf21 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/Horse.java @@ -5,7 +5,7 @@ import java.util.List; -public record Horse(PieceType pieceType) implements Piece { +public record Horse(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java index 184106a8b4..cef1fe285e 100644 --- a/src/main/java/domain/piece/Soldier.java +++ b/src/main/java/domain/piece/Soldier.java @@ -1,11 +1,10 @@ package domain.piece; -import domain.Direction; import domain.board.Position; import java.util.List; -public record Soldier(PieceType pieceType) implements Piece { +public record Soldier(PieceType pieceType, Team team) implements Piece { @Override public List getPathPositions(Position from, Position to) { @@ -13,11 +12,16 @@ public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); int dy = to.getY() - from.getY(); - boolean isMoveUp = dx == 0 && dy == 1; + int straight = 1; + if (team == Team.HAN) { + straight = -1; + } + + boolean isMoveStraight = dx == 0 && dy == straight; boolean isMoveLeft = dx == -1 && dy == 0; boolean isMoveRight = dx == 1 && dy == 0; - if(!(isMoveLeft || isMoveRight || isMoveUp)) { + if (!(isMoveLeft || isMoveRight || isMoveStraight)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } return List.of(to); diff --git a/src/main/java/domain/piece/Team.java b/src/main/java/domain/piece/Team.java new file mode 100644 index 0000000000..463ac64e70 --- /dev/null +++ b/src/main/java/domain/piece/Team.java @@ -0,0 +1,5 @@ +package domain.piece; + +public enum Team { + CHO, HAN; +} diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index fbaa36a3f7..45e91d452f 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -24,7 +24,7 @@ public class BoardTest { @BeforeEach void setUp() { - board = BoardFactory.createBoard(InitializeSetting.RIGHT_ELEPHANT_SETTING); + board = BoardFactory.createBoard(InitializeSetting.RIGHT_ELEPHANT_SETTING, InitializeSetting.RIGHT_ELEPHANT_SETTING); } @Nested diff --git a/src/test/java/domain/piece/CannonTest.java b/src/test/java/domain/piece/CannonTest.java index adf05fbbec..03b8ac75b8 100644 --- a/src/test/java/domain/piece/CannonTest.java +++ b/src/test/java/domain/piece/CannonTest.java @@ -14,7 +14,7 @@ class CannonTest { @BeforeEach void setUp() { - chariot = new Chariot(PieceType.CHARIOT); + chariot = new Chariot(PieceType.CHARIOT, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/ChariotTest.java b/src/test/java/domain/piece/ChariotTest.java index 7580c028e6..7877e6c0b3 100644 --- a/src/test/java/domain/piece/ChariotTest.java +++ b/src/test/java/domain/piece/ChariotTest.java @@ -14,7 +14,7 @@ class ChariotTest { @BeforeEach void setUp() { - chariot = new Chariot(PieceType.CHARIOT); + chariot = new Chariot(PieceType.CHARIOT, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/ElephantTest.java b/src/test/java/domain/piece/ElephantTest.java index 71bb859ac4..a3a7b753a4 100644 --- a/src/test/java/domain/piece/ElephantTest.java +++ b/src/test/java/domain/piece/ElephantTest.java @@ -13,7 +13,7 @@ class ElephantTest { @BeforeEach void setUp() { - elephant = new Elephant(PieceType.ELEPHANT); + elephant = new Elephant(PieceType.ELEPHANT, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/GeneralTest.java b/src/test/java/domain/piece/GeneralTest.java index 5bef5346dd..3b2c8781a6 100644 --- a/src/test/java/domain/piece/GeneralTest.java +++ b/src/test/java/domain/piece/GeneralTest.java @@ -13,7 +13,7 @@ class GeneralTest { @BeforeEach void setUp() { - general = new General(PieceType.GENERAL); + general = new General(PieceType.GENERAL, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/GuardTest.java b/src/test/java/domain/piece/GuardTest.java index 18409ba0a1..44ff3b75b7 100644 --- a/src/test/java/domain/piece/GuardTest.java +++ b/src/test/java/domain/piece/GuardTest.java @@ -13,7 +13,7 @@ class GuardTest { @BeforeEach void setUp() { - guard = new Guard(PieceType.GUARD); + guard = new Guard(PieceType.GUARD, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/HorseTest.java b/src/test/java/domain/piece/HorseTest.java index a3bb242fc3..9448fe0d3f 100644 --- a/src/test/java/domain/piece/HorseTest.java +++ b/src/test/java/domain/piece/HorseTest.java @@ -13,7 +13,7 @@ class HorseTest { @BeforeEach void setUp() { - horse = new Horse(PieceType.HORSE); + horse = new Horse(PieceType.HORSE, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/SoldierTest.java b/src/test/java/domain/piece/SoldierChoTest.java similarity index 92% rename from src/test/java/domain/piece/SoldierTest.java rename to src/test/java/domain/piece/SoldierChoTest.java index 1709064792..ce567ee92b 100644 --- a/src/test/java/domain/piece/SoldierTest.java +++ b/src/test/java/domain/piece/SoldierChoTest.java @@ -1,7 +1,6 @@ package domain.piece; import domain.board.Position; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -9,13 +8,13 @@ import static org.assertj.core.api.Assertions.assertThat; -class SoldierTest { +class SoldierChoTest { private Soldier soldier; @BeforeEach void setUp() { - soldier = new Soldier(PieceType.SOLDIER); + soldier = new Soldier(PieceType.SOLDIER, Team.CHO); } @Test diff --git a/src/test/java/domain/piece/SoldierHanTest.java b/src/test/java/domain/piece/SoldierHanTest.java new file mode 100644 index 0000000000..b73517de3b --- /dev/null +++ b/src/test/java/domain/piece/SoldierHanTest.java @@ -0,0 +1,50 @@ +package domain.piece; + +import domain.board.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class SoldierHanTest { + + private Soldier soldier; + + @BeforeEach + void setUp() { + soldier = new Soldier(PieceType.SOLDIER, Team.HAN); + } + + @Test + void 병은_위로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(0, 4); + Position to = new Position(0, 3); + + List pathPositions = soldier.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(0, 3))); + } + + @Test + void 병은_좌로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(2, 3); + Position to = new Position(1, 3); + + List pathPositions = soldier.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + } + + @Test + void 병은_우로_한칸_움직일_수_있는_경로가_있다() { + Position from = new Position(0, 3); + Position to = new Position(1, 3); + + List pathPositions = soldier.getPathPositions(from, to); + + assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + } + +} From 1c49c85b06f666b0215702bb2aa9475bf409c3c4 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 27 Mar 2026 15:27:52 +0900 Subject: [PATCH 14/58] =?UTF-8?q?feat(PieceMove):=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B2=BD=EB=A1=9C=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Path 클래스 작성 - Board에 getPath() 작성 --- src/main/java/domain/Path.java | 7 +++++++ src/main/java/domain/board/Board.java | 16 ++++++++++++---- src/main/java/domain/piece/Cannon.java | 4 +++- src/main/java/domain/piece/Chariot.java | 11 ++++++++++- src/main/java/domain/piece/Elephant.java | 3 ++- src/main/java/domain/piece/General.java | 3 ++- src/main/java/domain/piece/Guard.java | 3 ++- src/main/java/domain/piece/Horse.java | 3 ++- src/main/java/domain/piece/Piece.java | 3 ++- src/main/java/domain/piece/Soldier.java | 3 ++- src/test/java/domain/board/BoardTest.java | 21 ++++++++++++++------- 11 files changed, 58 insertions(+), 19 deletions(-) create mode 100644 src/main/java/domain/Path.java diff --git a/src/main/java/domain/Path.java b/src/main/java/domain/Path.java new file mode 100644 index 0000000000..d6a996f755 --- /dev/null +++ b/src/main/java/domain/Path.java @@ -0,0 +1,7 @@ +package domain; + +import domain.board.Position; +import domain.piece.Piece; + +public record Path(Position position, Piece piece) { +} diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 156dab81cf..667161d6e8 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -1,7 +1,9 @@ package domain.board; +import domain.Path; import domain.piece.Piece; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -16,15 +18,21 @@ public Piece getPiece(Position position) { return pieces.get(position); } - public void move(Position from, Position to){ + public void move(Position from, Position to) { // 해당 위치(from)에 기물이 위치하고 있는지 // (1) piece 가 해당 도착지(to)로 도착하는 경로 반환 : Piece의 getPathPositions 호출 // 상대편 위치, 지금할껀지 or 있다가 할껀지, 초/한 // (2) 1에서 받은 값으로 getPathWithPiece 호출하여 Piece의 canMove 호출 } - // positions(기물이 갈 경로)에 위치한 기물 정보를 반환 - public List getPathWithPiece(List positions){ - return null; + public List getPath(List positions) { + List paths = new ArrayList<>(); + for (Position position : positions) { + if (pieces.containsKey(position)) { + paths.add(new Path(position, pieces.get(position))); + } + } + + return paths; } } diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/Cannon.java index b82cf74d63..18e68cdb73 100644 --- a/src/main/java/domain/piece/Cannon.java +++ b/src/main/java/domain/piece/Cannon.java @@ -1,6 +1,7 @@ package domain.piece; import domain.Direction; +import domain.Path; import domain.board.Position; import java.util.ArrayList; @@ -53,7 +54,8 @@ private Direction decideYDirection(int dy) { @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { + } } diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/Chariot.java index 6de04ff9b0..40ceeb62af 100644 --- a/src/main/java/domain/piece/Chariot.java +++ b/src/main/java/domain/piece/Chariot.java @@ -1,6 +1,7 @@ package domain.piece; import domain.Direction; +import domain.Path; import domain.board.Position; import java.util.ArrayList; @@ -53,7 +54,15 @@ private Direction decideYDirection(int dy) { @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { + for (Path path : paths) { + if(path.position() != to){ + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } + + if(!paths.isEmpty()){ // 최종 목적지에 기물이 있다 + } } } diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/Elephant.java index 1ff120fddf..0e773d8de9 100644 --- a/src/main/java/domain/piece/Elephant.java +++ b/src/main/java/domain/piece/Elephant.java @@ -1,6 +1,7 @@ package domain.piece; import domain.Direction; +import domain.Path; import domain.board.Position; import java.util.List; @@ -47,7 +48,7 @@ private Direction decideYDirection(int dy) { } @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { } } diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/General.java index 594f0c0ee6..2918eb7cbf 100644 --- a/src/main/java/domain/piece/General.java +++ b/src/main/java/domain/piece/General.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.Path; import domain.board.Position; import java.util.List; @@ -22,7 +23,7 @@ public List getPathPositions(Position from, Position to) { } @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { } } diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/Guard.java index 30f6ca323a..ca2dda9af0 100644 --- a/src/main/java/domain/piece/Guard.java +++ b/src/main/java/domain/piece/Guard.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.Path; import domain.board.Position; import java.util.List; @@ -23,7 +24,7 @@ public List getPathPositions(Position from, Position to) { } @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { } } diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/Horse.java index 87178ddf21..3781db27cc 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/Horse.java @@ -1,6 +1,7 @@ package domain.piece; import domain.Direction; +import domain.Path; import domain.board.Position; import java.util.List; @@ -47,7 +48,7 @@ private Direction decideYDirection(int dy) { } @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { } } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index ad4bd79c90..34f6c9934b 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.Path; import domain.board.Position; import java.util.List; @@ -10,5 +11,5 @@ public interface Piece { List getPathPositions(Position from, Position to); // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) - void canMove(List pathWithPiece); + void canMove(List paths, Position to); } diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/Soldier.java index cef1fe285e..dda014297a 100644 --- a/src/main/java/domain/piece/Soldier.java +++ b/src/main/java/domain/piece/Soldier.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.Path; import domain.board.Position; import java.util.List; @@ -28,7 +29,7 @@ public List getPathPositions(Position from, Position to) { } @Override - public void canMove(List pathWithPiece) { + public void canMove(List paths, Position to) { } } diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index 45e91d452f..91575fbc18 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -1,12 +1,7 @@ package domain.board; -import domain.piece.Cannon; -import domain.piece.Chariot; -import domain.piece.General; -import domain.piece.Guard; -import domain.piece.Piece; - -import domain.piece.Soldier; +import domain.Path; +import domain.piece.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -15,6 +10,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.util.List; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; @@ -97,4 +93,15 @@ static Stream cannonProvider() { ); } } + + + @Test + void 기물이_이동할_경로에_대한_다른_기물의_위치_정보를_반환한다() { + List positions = List.of(new Position(1, 0), new Position(2, 0)); + List path = board.getPath(positions); + + + assertThat(path).isEqualTo(List.of(new Path(new Position(1, 0), new Horse(PieceType.HORSE, Team.CHO)), + new Path(new Position(2, 0), new Elephant(PieceType.ELEPHANT, Team.CHO)))); + } } From 4a8fb06d5879b36ac8e64141453664774018e82a Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 27 Mar 2026 15:57:03 +0900 Subject: [PATCH 15/58] =?UTF-8?q?refactor(Piece):=20Piece=EB=A5=BC=20recor?= =?UTF-8?q?d=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Piece를 인터페이스에서 record로 변경 - Piece에서 MoveStrategy를 주입받도록 변경 --- src/main/java/domain/Direction.java | 2 -- src/main/java/domain/Path.java | 5 +-- src/main/java/domain/board/Board.java | 3 +- src/main/java/domain/board/BoardFactory.java | 35 +++++++------------ .../{Cannon.java => CannonStrategy.java} | 2 +- .../{Chariot.java => ChariotStrategy.java} | 8 ++--- .../{Soldier.java => ChoSoldierStrategy.java} | 6 +--- .../{Elephant.java => ElephantStrategy.java} | 2 +- .../{General.java => GeneralStrategy.java} | 2 +- .../piece/{Guard.java => GuardStrategy.java} | 2 +- .../java/domain/piece/HanSoldierStrategy.java | 31 ++++++++++++++++ .../piece/{Horse.java => HorseStrategy.java} | 2 +- src/main/java/domain/piece/MoveStrategy.java | 15 ++++++++ src/main/java/domain/piece/Piece.java | 13 ++++--- src/main/java/domain/piece/Team.java | 2 +- src/test/java/domain/board/BoardTest.java | 15 ++++---- src/test/java/domain/piece/CannonTest.java | 12 +++---- src/test/java/domain/piece/ChariotTest.java | 4 +-- src/test/java/domain/piece/ElephantTest.java | 4 +-- src/test/java/domain/piece/GeneralTest.java | 4 +-- src/test/java/domain/piece/GuardTest.java | 4 +-- src/test/java/domain/piece/HorseTest.java | 4 +-- .../java/domain/piece/SoldierChoTest.java | 4 +-- .../java/domain/piece/SoldierHanTest.java | 4 +-- 24 files changed, 110 insertions(+), 75 deletions(-) rename src/main/java/domain/piece/{Cannon.java => CannonStrategy.java} (95%) rename src/main/java/domain/piece/{Chariot.java => ChariotStrategy.java} (86%) rename src/main/java/domain/piece/{Soldier.java => ChoSoldierStrategy.java} (83%) rename src/main/java/domain/piece/{Elephant.java => ElephantStrategy.java} (94%) rename src/main/java/domain/piece/{General.java => GeneralStrategy.java} (91%) rename src/main/java/domain/piece/{Guard.java => GuardStrategy.java} (91%) create mode 100644 src/main/java/domain/piece/HanSoldierStrategy.java rename src/main/java/domain/piece/{Horse.java => HorseStrategy.java} (94%) create mode 100644 src/main/java/domain/piece/MoveStrategy.java diff --git a/src/main/java/domain/Direction.java b/src/main/java/domain/Direction.java index 76a3f8f262..cdb76b46c0 100644 --- a/src/main/java/domain/Direction.java +++ b/src/main/java/domain/Direction.java @@ -1,7 +1,5 @@ package domain; -import domain.board.Position; - public enum Direction { UP(0, 1), DOWN(0, -1), diff --git a/src/main/java/domain/Path.java b/src/main/java/domain/Path.java index d6a996f755..cfec416884 100644 --- a/src/main/java/domain/Path.java +++ b/src/main/java/domain/Path.java @@ -1,7 +1,8 @@ package domain; import domain.board.Position; -import domain.piece.Piece; +import domain.piece.PieceType; +import domain.piece.Team; -public record Path(Position position, Piece piece) { +public record Path(Position position, PieceType pieceType, Team team) { } diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 667161d6e8..8aeb763cde 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -29,7 +29,8 @@ public List getPath(List positions) { List paths = new ArrayList<>(); for (Position position : positions) { if (pieces.containsKey(position)) { - paths.add(new Path(position, pieces.get(position))); + Piece piece = pieces.get(position); + paths.add(new Path(position, piece.pieceType(), piece.team())); } } diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java index 4586eaf29a..5892be607e 100644 --- a/src/main/java/domain/board/BoardFactory.java +++ b/src/main/java/domain/board/BoardFactory.java @@ -1,15 +1,6 @@ package domain.board; -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.PieceType; -import domain.piece.Soldier; -import domain.piece.Team; +import domain.piece.*; import java.util.HashMap; import java.util.List; @@ -29,30 +20,30 @@ public static Board createBoard(InitializeSetting choInitialSetting, InitializeS for (Integer soliderColumns : SOLDIER_COLUMNS) { - pieces.put(new Position(soliderColumns, 3), new Soldier(PieceType.SOLDIER, Team.CHO)); - pieces.put(new Position(soliderColumns, 6), new Soldier(PieceType.SOLDIER, Team.HAN)); + pieces.put(new Position(soliderColumns, 3), new Piece(PieceType.SOLDIER, Team.CHO, new ChoSoldierStrategy())); + pieces.put(new Position(soliderColumns, 6), new Piece(PieceType.SOLDIER, Team.HAN, new HanSoldierStrategy())); } for (Integer chariotColumn : CHARIOT_COLUMNS) { - pieces.put(new Position(chariotColumn, 0), new Chariot(PieceType.CHARIOT, Team.CHO)); - pieces.put(new Position(chariotColumn, 9), new Chariot(PieceType.CHARIOT, Team.HAN)); + pieces.put(new Position(chariotColumn, 0), new Piece(PieceType.CHARIOT, Team.CHO, new ChariotStrategy())); + pieces.put(new Position(chariotColumn, 9), new Piece(PieceType.CHARIOT, Team.HAN, new ChariotStrategy())); } for (Integer guardColumn : GUARD_COLUMNS) { - pieces.put(new Position(guardColumn, 0), new Guard(PieceType.GUARD, Team.CHO)); - pieces.put(new Position(guardColumn, 9), new Guard(PieceType.GUARD, Team.HAN)); + pieces.put(new Position(guardColumn, 0), new Piece(PieceType.GUARD, Team.CHO, new GuardStrategy())); + pieces.put(new Position(guardColumn, 9), new Piece(PieceType.GUARD, Team.HAN, new GuardStrategy())); } for (Integer cannonColumn : CANNON_COLUMNS) { - pieces.put(new Position(cannonColumn, 2), new Cannon(PieceType.CANNON, Team.CHO)); - pieces.put(new Position(cannonColumn, 7), new Cannon(PieceType.CANNON, Team.HAN)); + pieces.put(new Position(cannonColumn, 2), new Piece(PieceType.CANNON, Team.CHO, new CannonStrategy())); + pieces.put(new Position(cannonColumn, 7), new Piece(PieceType.CANNON, Team.HAN, new CannonStrategy())); } - pieces.put(new Position(4, 1), new General(PieceType.GENERAL, Team.CHO)); - pieces.put(new Position(4, 8), new General(PieceType.GENERAL, Team.HAN)); + pieces.put(new Position(4, 1), new Piece(PieceType.GENERAL, Team.CHO, new GeneralStrategy())); + pieces.put(new Position(4, 8), new Piece(PieceType.GENERAL, Team.HAN, new GeneralStrategy())); List choSetting = choInitialSetting.getInitialSetting(); pieces.put(new Position(1, 0), createPiece(choSetting.get(0), Team.CHO)); @@ -72,8 +63,8 @@ public static Board createBoard(InitializeSetting choInitialSetting, InitializeS private static Piece createPiece(PieceType pieceType, Team team) { if (pieceType == PieceType.ELEPHANT) { - return new Elephant(pieceType, team); + return new Piece(pieceType, team, new ElephantStrategy()); } - return new Horse(pieceType, team); + return new Piece(pieceType, team, new HorseStrategy()); } } diff --git a/src/main/java/domain/piece/Cannon.java b/src/main/java/domain/piece/CannonStrategy.java similarity index 95% rename from src/main/java/domain/piece/Cannon.java rename to src/main/java/domain/piece/CannonStrategy.java index 18e68cdb73..026fa696da 100644 --- a/src/main/java/domain/piece/Cannon.java +++ b/src/main/java/domain/piece/CannonStrategy.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.List; -public record Cannon(PieceType pieceType, Team team) implements Piece { +public class CannonStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); diff --git a/src/main/java/domain/piece/Chariot.java b/src/main/java/domain/piece/ChariotStrategy.java similarity index 86% rename from src/main/java/domain/piece/Chariot.java rename to src/main/java/domain/piece/ChariotStrategy.java index 40ceeb62af..10081bc4c3 100644 --- a/src/main/java/domain/piece/Chariot.java +++ b/src/main/java/domain/piece/ChariotStrategy.java @@ -7,13 +7,13 @@ import java.util.ArrayList; import java.util.List; -public record Chariot(PieceType pieceType, Team team) implements Piece { +public class ChariotStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); int dy = to.getY() - from.getY(); - if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))){ + if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))) { throw new IllegalArgumentException("차를 해당 위치로 옮길 수 없습니다."); } @@ -56,12 +56,12 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Position to) { for (Path path : paths) { - if(path.position() != to){ + if (path.position() != to) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } - if(!paths.isEmpty()){ // 최종 목적지에 기물이 있다 + if (!paths.isEmpty()) { // 최종 목적지에 기물이 있다 } } diff --git a/src/main/java/domain/piece/Soldier.java b/src/main/java/domain/piece/ChoSoldierStrategy.java similarity index 83% rename from src/main/java/domain/piece/Soldier.java rename to src/main/java/domain/piece/ChoSoldierStrategy.java index dda014297a..4031ac39e9 100644 --- a/src/main/java/domain/piece/Soldier.java +++ b/src/main/java/domain/piece/ChoSoldierStrategy.java @@ -5,18 +5,14 @@ import java.util.List; -public record Soldier(PieceType pieceType, Team team) implements Piece { +public class ChoSoldierStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { - int dx = to.getX() - from.getX(); int dy = to.getY() - from.getY(); int straight = 1; - if (team == Team.HAN) { - straight = -1; - } boolean isMoveStraight = dx == 0 && dy == straight; boolean isMoveLeft = dx == -1 && dy == 0; diff --git a/src/main/java/domain/piece/Elephant.java b/src/main/java/domain/piece/ElephantStrategy.java similarity index 94% rename from src/main/java/domain/piece/Elephant.java rename to src/main/java/domain/piece/ElephantStrategy.java index 0e773d8de9..286d6d3d93 100644 --- a/src/main/java/domain/piece/Elephant.java +++ b/src/main/java/domain/piece/ElephantStrategy.java @@ -6,7 +6,7 @@ import java.util.List; -public record Elephant(PieceType pieceType, Team team) implements Piece { +public class ElephantStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { diff --git a/src/main/java/domain/piece/General.java b/src/main/java/domain/piece/GeneralStrategy.java similarity index 91% rename from src/main/java/domain/piece/General.java rename to src/main/java/domain/piece/GeneralStrategy.java index 2918eb7cbf..23ccef5b70 100644 --- a/src/main/java/domain/piece/General.java +++ b/src/main/java/domain/piece/GeneralStrategy.java @@ -5,7 +5,7 @@ import java.util.List; -public record General(PieceType pieceType, Team team) implements Piece { +public class GeneralStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); diff --git a/src/main/java/domain/piece/Guard.java b/src/main/java/domain/piece/GuardStrategy.java similarity index 91% rename from src/main/java/domain/piece/Guard.java rename to src/main/java/domain/piece/GuardStrategy.java index ca2dda9af0..6f25d7bfa6 100644 --- a/src/main/java/domain/piece/Guard.java +++ b/src/main/java/domain/piece/GuardStrategy.java @@ -5,7 +5,7 @@ import java.util.List; -public record Guard(PieceType pieceType, Team team) implements Piece { +public class GuardStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { diff --git a/src/main/java/domain/piece/HanSoldierStrategy.java b/src/main/java/domain/piece/HanSoldierStrategy.java new file mode 100644 index 0000000000..75ab4db946 --- /dev/null +++ b/src/main/java/domain/piece/HanSoldierStrategy.java @@ -0,0 +1,31 @@ +package domain.piece; + +import domain.Path; +import domain.board.Position; + +import java.util.List; + +public class HanSoldierStrategy implements MoveStrategy { + + @Override + public List getPathPositions(Position from, Position to) { + int dx = to.getX() - from.getX(); + int dy = to.getY() - from.getY(); + + int straight = -1; + + boolean isMoveStraight = dx == 0 && dy == straight; + boolean isMoveLeft = dx == -1 && dy == 0; + boolean isMoveRight = dx == 1 && dy == 0; + + if (!(isMoveLeft || isMoveRight || isMoveStraight)) { + throw new IllegalArgumentException("움직일 수 없는 위치입니다."); + } + return List.of(to); + } + + @Override + public void canMove(List paths, Position to) { + + } +} diff --git a/src/main/java/domain/piece/Horse.java b/src/main/java/domain/piece/HorseStrategy.java similarity index 94% rename from src/main/java/domain/piece/Horse.java rename to src/main/java/domain/piece/HorseStrategy.java index 3781db27cc..8280f7a0a3 100644 --- a/src/main/java/domain/piece/Horse.java +++ b/src/main/java/domain/piece/HorseStrategy.java @@ -6,7 +6,7 @@ import java.util.List; -public record Horse(PieceType pieceType, Team team) implements Piece { +public class HorseStrategy implements MoveStrategy { @Override public List getPathPositions(Position from, Position to) { diff --git a/src/main/java/domain/piece/MoveStrategy.java b/src/main/java/domain/piece/MoveStrategy.java new file mode 100644 index 0000000000..bc5f4087e4 --- /dev/null +++ b/src/main/java/domain/piece/MoveStrategy.java @@ -0,0 +1,15 @@ +package domain.piece; + +import domain.Path; +import domain.board.Position; + +import java.util.List; + +public interface MoveStrategy { + // piece가 from에서 해당 도착지 to로 도착할 수 있는지 없다면 예외를 던진다 + // from에서 to까지의 경로 Position을 반환 + List getPathPositions(Position from, Position to); + + // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) + void canMove(List paths, Position to); +} diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 34f6c9934b..06fe5b7093 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -5,11 +5,14 @@ import java.util.List; -public interface Piece { - // piece가 from에서 해당 도착지 to로 도착할 수 있는지 없다면 예외를 던진다 - // from에서 to까지의 경로 Position을 반환 - List getPathPositions(Position from, Position to); +public record Piece(PieceType pieceType, Team team, MoveStrategy moveStrategy) { + + List getPathPositions(Position from, Position to) { + return moveStrategy.getPathPositions(from, to); + } // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) - void canMove(List paths, Position to); + void canMove(List paths, Position to) { + moveStrategy.canMove(paths, to); + } } diff --git a/src/main/java/domain/piece/Team.java b/src/main/java/domain/piece/Team.java index 463ac64e70..2652d94840 100644 --- a/src/main/java/domain/piece/Team.java +++ b/src/main/java/domain/piece/Team.java @@ -1,5 +1,5 @@ package domain.piece; public enum Team { - CHO, HAN; + CHO, HAN } diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index 91575fbc18..3ab50f72e0 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -30,7 +30,7 @@ class 기물_위치_테스트 { @MethodSource("soldierProvider") void 졸을_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - assertThat(piece).isInstanceOf(Soldier.class); + assertThat(piece.pieceType()).isEqualTo(PieceType.SOLDIER); } static Stream soldierProvider() { @@ -47,7 +47,7 @@ static Stream soldierProvider() { @MethodSource("chariotProvider") void 차를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - assertThat(piece).isInstanceOf(Chariot.class); + assertThat(piece.pieceType()).isEqualTo(PieceType.CHARIOT); } static Stream chariotProvider() { @@ -61,7 +61,7 @@ static Stream chariotProvider() { @MethodSource("guardProvider") void 사를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - assertThat(piece).isInstanceOf(Guard.class); + assertThat(piece.pieceType()).isEqualTo(PieceType.GUARD); } static Stream guardProvider() { @@ -75,7 +75,7 @@ static Stream guardProvider() { @Test void 궁을_올바른_위치에_초기화한다() { Piece piece = board.getPiece(new Position(4, 1)); - assertThat(piece).isInstanceOf(General.class); + assertThat(piece.pieceType()).isEqualTo(PieceType.GENERAL); } @@ -83,7 +83,7 @@ static Stream guardProvider() { @MethodSource("cannonProvider") void 포를_올바른_위치에_초기화한다(Position position) { Piece piece = board.getPiece(position); - assertThat(piece).isInstanceOf(Cannon.class); + assertThat(piece.pieceType()).isEqualTo(PieceType.CANNON); } static Stream cannonProvider() { @@ -100,8 +100,7 @@ static Stream cannonProvider() { List positions = List.of(new Position(1, 0), new Position(2, 0)); List path = board.getPath(positions); - - assertThat(path).isEqualTo(List.of(new Path(new Position(1, 0), new Horse(PieceType.HORSE, Team.CHO)), - new Path(new Position(2, 0), new Elephant(PieceType.ELEPHANT, Team.CHO)))); + assertThat(path).isEqualTo(List.of(new Path(new Position(1, 0), PieceType.HORSE, Team.CHO), + new Path(new Position(2, 0), PieceType.ELEPHANT, Team.CHO))); } } diff --git a/src/test/java/domain/piece/CannonTest.java b/src/test/java/domain/piece/CannonTest.java index 03b8ac75b8..3d201f659b 100644 --- a/src/test/java/domain/piece/CannonTest.java +++ b/src/test/java/domain/piece/CannonTest.java @@ -10,11 +10,11 @@ class CannonTest { - private Chariot chariot; + private Piece cannon; @BeforeEach void setUp() { - chariot = new Chariot(PieceType.CHARIOT, Team.CHO); + cannon = new Piece(PieceType.CANNON, Team.CHO, new CannonStrategy()); } @Test @@ -22,7 +22,7 @@ void setUp() { Position from = new Position(5, 5); Position to = new Position(2, 5); - List pathPositions = chariot.getPathPositions(from, to); + List pathPositions = cannon.getPathPositions(from, to); assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5), new Position(2, 5))); @@ -33,7 +33,7 @@ void setUp() { Position from = new Position(5, 5); Position to = new Position(8, 5); - List pathPositions = chariot.getPathPositions(from, to); + List pathPositions = cannon.getPathPositions(from, to); assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5), new Position(8, 5))); @@ -45,7 +45,7 @@ void setUp() { Position from = new Position(5, 5); Position to = new Position(5, 7); - List pathPositions = chariot.getPathPositions(from, to); + List pathPositions = cannon.getPathPositions(from, to); assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(5, 7))); @@ -57,7 +57,7 @@ void setUp() { Position from = new Position(5, 5); Position to = new Position(5, 0); - List pathPositions = chariot.getPathPositions(from, to); + List pathPositions = cannon.getPathPositions(from, to); assertThat(pathPositions).isEqualTo(List.of( diff --git a/src/test/java/domain/piece/ChariotTest.java b/src/test/java/domain/piece/ChariotTest.java index 7877e6c0b3..e60735ff04 100644 --- a/src/test/java/domain/piece/ChariotTest.java +++ b/src/test/java/domain/piece/ChariotTest.java @@ -10,11 +10,11 @@ class ChariotTest { - private Chariot chariot; + private Piece chariot; @BeforeEach void setUp() { - chariot = new Chariot(PieceType.CHARIOT, Team.CHO); + chariot = new Piece(PieceType.CHARIOT, Team.CHO, new ChariotStrategy()); } @Test diff --git a/src/test/java/domain/piece/ElephantTest.java b/src/test/java/domain/piece/ElephantTest.java index a3a7b753a4..0292d715ab 100644 --- a/src/test/java/domain/piece/ElephantTest.java +++ b/src/test/java/domain/piece/ElephantTest.java @@ -9,11 +9,11 @@ import static org.assertj.core.api.Assertions.assertThat; class ElephantTest { - private Elephant elephant; + private Piece elephant; @BeforeEach void setUp() { - elephant = new Elephant(PieceType.ELEPHANT, Team.CHO); + elephant = new Piece(PieceType.ELEPHANT, Team.CHO, new ElephantStrategy()); } @Test diff --git a/src/test/java/domain/piece/GeneralTest.java b/src/test/java/domain/piece/GeneralTest.java index 3b2c8781a6..72614328c6 100644 --- a/src/test/java/domain/piece/GeneralTest.java +++ b/src/test/java/domain/piece/GeneralTest.java @@ -9,11 +9,11 @@ import static org.assertj.core.api.Assertions.assertThat; class GeneralTest { - private General general; + private Piece general; @BeforeEach void setUp() { - general = new General(PieceType.GENERAL, Team.CHO); + general = new Piece(PieceType.GENERAL, Team.CHO, new GeneralStrategy()); } @Test diff --git a/src/test/java/domain/piece/GuardTest.java b/src/test/java/domain/piece/GuardTest.java index 44ff3b75b7..06aec13828 100644 --- a/src/test/java/domain/piece/GuardTest.java +++ b/src/test/java/domain/piece/GuardTest.java @@ -9,11 +9,11 @@ import static org.assertj.core.api.Assertions.assertThat; class GuardTest { - private Guard guard; + private Piece guard; @BeforeEach void setUp() { - guard = new Guard(PieceType.GUARD, Team.CHO); + guard = new Piece(PieceType.GUARD, Team.CHO, new GuardStrategy()); } @Test diff --git a/src/test/java/domain/piece/HorseTest.java b/src/test/java/domain/piece/HorseTest.java index 9448fe0d3f..39e66d4134 100644 --- a/src/test/java/domain/piece/HorseTest.java +++ b/src/test/java/domain/piece/HorseTest.java @@ -9,11 +9,11 @@ import static org.assertj.core.api.Assertions.assertThat; class HorseTest { - private Horse horse; + private Piece horse; @BeforeEach void setUp() { - horse = new Horse(PieceType.HORSE, Team.CHO); + horse = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); } @Test diff --git a/src/test/java/domain/piece/SoldierChoTest.java b/src/test/java/domain/piece/SoldierChoTest.java index ce567ee92b..a25245ed09 100644 --- a/src/test/java/domain/piece/SoldierChoTest.java +++ b/src/test/java/domain/piece/SoldierChoTest.java @@ -10,11 +10,11 @@ class SoldierChoTest { - private Soldier soldier; + private Piece soldier; @BeforeEach void setUp() { - soldier = new Soldier(PieceType.SOLDIER, Team.CHO); + soldier = new Piece(PieceType.SOLDIER, Team.CHO, new ChoSoldierStrategy()); } @Test diff --git a/src/test/java/domain/piece/SoldierHanTest.java b/src/test/java/domain/piece/SoldierHanTest.java index b73517de3b..bbcbff4cc5 100644 --- a/src/test/java/domain/piece/SoldierHanTest.java +++ b/src/test/java/domain/piece/SoldierHanTest.java @@ -10,11 +10,11 @@ class SoldierHanTest { - private Soldier soldier; + private Piece soldier; @BeforeEach void setUp() { - soldier = new Soldier(PieceType.SOLDIER, Team.HAN); + soldier = new Piece(PieceType.SOLDIER, Team.HAN, new HanSoldierStrategy()); } @Test From 5fbb7ac1f5ef9e94a34a485a425f8038ba02bc97 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 27 Mar 2026 16:04:59 +0900 Subject: [PATCH 16/58] =?UTF-8?q?feat(Piece):=20=EA=B0=99=EC=9D=80=20?= =?UTF-8?q?=ED=8C=80=EC=9D=B8=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/piece/Piece.java | 4 ++++ src/test/java/domain/piece/PieceTest.java | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/test/java/domain/piece/PieceTest.java diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 06fe5b7093..8ef1418c5d 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -15,4 +15,8 @@ List getPathPositions(Position from, Position to) { void canMove(List paths, Position to) { moveStrategy.canMove(paths, to); } + + boolean isSameTeam(Piece another){ + return another.team == team; + } } diff --git a/src/test/java/domain/piece/PieceTest.java b/src/test/java/domain/piece/PieceTest.java new file mode 100644 index 0000000000..abfee85ab7 --- /dev/null +++ b/src/test/java/domain/piece/PieceTest.java @@ -0,0 +1,23 @@ +package domain.piece; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; + + +class PieceTest { + @Test + void 같은_팀의_기물인지_확인한다() { + Piece piece = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); + Piece anotherPiece = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); + + Assertions.assertThat(piece.isSameTeam(anotherPiece)).isTrue(); + } + + @Test + void 다른_팀의_기물인지_확인한다() { + Piece piece = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); + Piece anotherPiece = new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy()); + + Assertions.assertThat(piece.isSameTeam(anotherPiece)).isFalse(); + } +} From ea974180913a7e58784edce1291982cbbfba50f1 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 27 Mar 2026 16:37:21 +0900 Subject: [PATCH 17/58] =?UTF-8?q?feat(PieceMove):=20canMove=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/Path.java | 5 ++--- src/main/java/domain/board/Board.java | 5 +++-- src/main/java/domain/piece/ChariotStrategy.java | 4 ---- src/main/java/domain/piece/ChoSoldierStrategy.java | 6 +++++- src/main/java/domain/piece/ElephantStrategy.java | 6 +++++- src/main/java/domain/piece/GeneralStrategy.java | 6 +++++- src/main/java/domain/piece/GuardStrategy.java | 6 +++++- src/main/java/domain/piece/HanSoldierStrategy.java | 6 +++++- src/main/java/domain/piece/HorseStrategy.java | 6 +++++- src/main/java/domain/piece/Piece.java | 12 ++++++++++++ src/test/java/domain/board/BoardTest.java | 6 ++++-- 11 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/main/java/domain/Path.java b/src/main/java/domain/Path.java index cfec416884..d6a996f755 100644 --- a/src/main/java/domain/Path.java +++ b/src/main/java/domain/Path.java @@ -1,8 +1,7 @@ package domain; import domain.board.Position; -import domain.piece.PieceType; -import domain.piece.Team; +import domain.piece.Piece; -public record Path(Position position, PieceType pieceType, Team team) { +public record Path(Position position, Piece piece) { } diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 8aeb763cde..e1ae816c7c 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -29,11 +29,12 @@ public List getPath(List positions) { List paths = new ArrayList<>(); for (Position position : positions) { if (pieces.containsKey(position)) { - Piece piece = pieces.get(position); - paths.add(new Path(position, piece.pieceType(), piece.team())); + paths.add(new Path(position, pieces.get(position))); } } return paths; } + + // TODO 같은 팀이면 예외 발생, 다른 팀이면 잡는 함수 작성 필요(move 안에) } diff --git a/src/main/java/domain/piece/ChariotStrategy.java b/src/main/java/domain/piece/ChariotStrategy.java index 10081bc4c3..819077401b 100644 --- a/src/main/java/domain/piece/ChariotStrategy.java +++ b/src/main/java/domain/piece/ChariotStrategy.java @@ -60,9 +60,5 @@ public void canMove(List paths, Position to) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } - - if (!paths.isEmpty()) { // 최종 목적지에 기물이 있다 - - } } } diff --git a/src/main/java/domain/piece/ChoSoldierStrategy.java b/src/main/java/domain/piece/ChoSoldierStrategy.java index 4031ac39e9..042b386a84 100644 --- a/src/main/java/domain/piece/ChoSoldierStrategy.java +++ b/src/main/java/domain/piece/ChoSoldierStrategy.java @@ -26,6 +26,10 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Position to) { - + for (Path path : paths) { + if (path.position() != to) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } } } diff --git a/src/main/java/domain/piece/ElephantStrategy.java b/src/main/java/domain/piece/ElephantStrategy.java index 286d6d3d93..f588c327a5 100644 --- a/src/main/java/domain/piece/ElephantStrategy.java +++ b/src/main/java/domain/piece/ElephantStrategy.java @@ -49,6 +49,10 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Position to) { - + for (Path path : paths) { + if (path.position() != to) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } } } diff --git a/src/main/java/domain/piece/GeneralStrategy.java b/src/main/java/domain/piece/GeneralStrategy.java index 23ccef5b70..d1e1ba7ce1 100644 --- a/src/main/java/domain/piece/GeneralStrategy.java +++ b/src/main/java/domain/piece/GeneralStrategy.java @@ -24,6 +24,10 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Position to) { - + for (Path path : paths) { + if (path.position() != to) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } } } diff --git a/src/main/java/domain/piece/GuardStrategy.java b/src/main/java/domain/piece/GuardStrategy.java index 6f25d7bfa6..8dabee5439 100644 --- a/src/main/java/domain/piece/GuardStrategy.java +++ b/src/main/java/domain/piece/GuardStrategy.java @@ -25,6 +25,10 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Position to) { - + for (Path path : paths) { + if (path.position() != to) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } } } diff --git a/src/main/java/domain/piece/HanSoldierStrategy.java b/src/main/java/domain/piece/HanSoldierStrategy.java index 75ab4db946..264c20ea8b 100644 --- a/src/main/java/domain/piece/HanSoldierStrategy.java +++ b/src/main/java/domain/piece/HanSoldierStrategy.java @@ -26,6 +26,10 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Position to) { - + for (Path path : paths) { + if (path.position() != to) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } } } diff --git a/src/main/java/domain/piece/HorseStrategy.java b/src/main/java/domain/piece/HorseStrategy.java index 8280f7a0a3..7b103e424b 100644 --- a/src/main/java/domain/piece/HorseStrategy.java +++ b/src/main/java/domain/piece/HorseStrategy.java @@ -49,6 +49,10 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Position to) { - + for (Path path : paths) { + if (path.position() != to) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); + } + } } } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 8ef1418c5d..3f972c9875 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -4,6 +4,7 @@ import domain.board.Position; import java.util.List; +import java.util.Objects; public record Piece(PieceType pieceType, Team team, MoveStrategy moveStrategy) { @@ -11,6 +12,17 @@ List getPathPositions(Position from, Position to) { return moveStrategy.getPathPositions(from, to); } + @Override + public boolean equals(Object o) { + if (!(o instanceof Piece piece)) return false; + return team == piece.team && pieceType == piece.pieceType; + } + + @Override + public int hashCode() { + return Objects.hash(pieceType, team); + } + // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) void canMove(List paths, Position to) { moveStrategy.canMove(paths, to); diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index 3ab50f72e0..fa58a34b9b 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -100,7 +100,9 @@ static Stream cannonProvider() { List positions = List.of(new Position(1, 0), new Position(2, 0)); List path = board.getPath(positions); - assertThat(path).isEqualTo(List.of(new Path(new Position(1, 0), PieceType.HORSE, Team.CHO), - new Path(new Position(2, 0), PieceType.ELEPHANT, Team.CHO))); + assertThat(path).isEqualTo(List.of(new Path( + new Position(1, 0), new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy())), + new Path(new Position(2, 0), new Piece(PieceType.ELEPHANT, Team.CHO, new ElephantStrategy())) + )); } } From 51094081095254177647743c72ea93005c966c6e Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Fri, 27 Mar 2026 17:16:10 +0900 Subject: [PATCH 18/58] =?UTF-8?q?feat(PieceMove):=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EC=9D=B4=20=EC=9B=80=EC=A7=81=EC=9D=BC=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=EC=A7=80=EC=97=90=20=EB=8C=80=ED=95=9C=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 - canMove에서 움직일 수 없는 경우 예외 발생 - 포에 대한 테스트 추가 - 최종 목적지에 대해 같은 진영인지 다른 진영인지는 보드가 판단 --- src/main/java/domain/board/Board.java | 19 ++++- .../java/domain/piece/CannonStrategy.java | 17 ++++- .../java/domain/piece/ChariotStrategy.java | 10 +-- .../java/domain/piece/ChoSoldierStrategy.java | 10 +-- .../java/domain/piece/ElephantStrategy.java | 11 +-- .../java/domain/piece/GeneralStrategy.java | 10 +-- src/main/java/domain/piece/GuardStrategy.java | 10 +-- .../java/domain/piece/HanSoldierStrategy.java | 10 +-- src/main/java/domain/piece/HorseStrategy.java | 11 +-- src/main/java/domain/piece/MoveStrategy.java | 2 +- src/main/java/domain/piece/Piece.java | 13 ++-- .../java/domain/piece/CannonStrategyTest.java | 76 +++++++++++++++++++ src/test/java/domain/piece/CannonTest.java | 8 +- src/test/java/domain/piece/ChariotTest.java | 8 +- src/test/java/domain/piece/ElephantTest.java | 16 ++-- src/test/java/domain/piece/GeneralTest.java | 8 +- src/test/java/domain/piece/GuardTest.java | 8 +- src/test/java/domain/piece/HorseTest.java | 16 ++-- .../java/domain/piece/SoldierChoTest.java | 6 +- .../java/domain/piece/SoldierHanTest.java | 6 +- 20 files changed, 181 insertions(+), 94 deletions(-) create mode 100644 src/test/java/domain/piece/CannonStrategyTest.java diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index e1ae816c7c..062a48a9d3 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -19,10 +19,26 @@ public Piece getPiece(Position position) { } public void move(Position from, Position to) { - // 해당 위치(from)에 기물이 위치하고 있는지 + // (1) piece 가 해당 도착지(to)로 도착하는 경로 반환 : Piece의 getPathPositions 호출 + + Piece fromPiece = pieces.get(from); // 실제 움직일 애 + Piece toPiece = pieces.get(to); + List pathPositions = fromPiece.getPathPositions(from, to); // 좌표(경유지) 목록을 반환 + List path = getPath(pathPositions); // 해당 좌표(경유지)에 대해서 반환함. + fromPiece.canMove(path, toPiece); + + + if (fromPiece.isSameTeam(toPiece)) { + throw new IllegalStateException("같은 팀의 기물을 잡을 수 없습니다."); + } + + // 잡는 행위 + // 실제로 옮겨진 // 상대편 위치, 지금할껀지 or 있다가 할껀지, 초/한 + // (2) 1에서 받은 값으로 getPathWithPiece 호출하여 Piece의 canMove 호출 + // 해당 위치(from)에 기물이 위치하고 있는지 } public List getPath(List positions) { @@ -32,7 +48,6 @@ public List getPath(List positions) { paths.add(new Path(position, pieces.get(position))); } } - return paths; } diff --git a/src/main/java/domain/piece/CannonStrategy.java b/src/main/java/domain/piece/CannonStrategy.java index 026fa696da..dcdf467fa4 100644 --- a/src/main/java/domain/piece/CannonStrategy.java +++ b/src/main/java/domain/piece/CannonStrategy.java @@ -18,6 +18,7 @@ public List getPathPositions(Position from, Position to) { } Direction mainDirection; + int distance; if (dx == 0) { mainDirection = decideYDirection(dy); @@ -30,7 +31,7 @@ public List getPathPositions(Position from, Position to) { Position step = from; List route = new ArrayList<>(); - for (int i = 0; i < distance; i++) { + for (int i = 0; i < distance - 1; i++) { step = step.next(mainDirection); route.add(step); } @@ -54,8 +55,20 @@ private Direction decideYDirection(int dy) { @Override - public void canMove(List paths, Position to) { + public void canMove(List paths, Piece to) { + if(paths.size() != 1) { + throw new IllegalStateException("포는 한 기물만 뛰어 넘을 수 있습니다."); + } + + Piece piece = paths.getFirst().piece(); + if(piece.pieceType() == PieceType.CANNON) { + throw new IllegalStateException("포는 포를 뛰어 넘을 수 있습니다."); + } + + if(to.pieceType() == PieceType.CANNON) { + throw new IllegalStateException("포를 잡을 수 없습니다"); + } } } diff --git a/src/main/java/domain/piece/ChariotStrategy.java b/src/main/java/domain/piece/ChariotStrategy.java index 819077401b..018dd1b885 100644 --- a/src/main/java/domain/piece/ChariotStrategy.java +++ b/src/main/java/domain/piece/ChariotStrategy.java @@ -30,7 +30,7 @@ public List getPathPositions(Position from, Position to) { Position step = from; List route = new ArrayList<>(); - for (int i = 0; i < distance; i++) { + for (int i = 0; i < distance - 1; i++) { step = step.next(mainDirection); route.add(step); } @@ -54,11 +54,9 @@ private Direction decideYDirection(int dy) { @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece to) { + if (!paths.isEmpty() ) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/ChoSoldierStrategy.java b/src/main/java/domain/piece/ChoSoldierStrategy.java index 042b386a84..3f1ee60ad1 100644 --- a/src/main/java/domain/piece/ChoSoldierStrategy.java +++ b/src/main/java/domain/piece/ChoSoldierStrategy.java @@ -21,15 +21,13 @@ public List getPathPositions(Position from, Position to) { if (!(isMoveLeft || isMoveRight || isMoveStraight)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } - return List.of(to); + return List.of(); } @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece to) { + if (!paths.isEmpty() ) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/ElephantStrategy.java b/src/main/java/domain/piece/ElephantStrategy.java index f588c327a5..2a641a67f0 100644 --- a/src/main/java/domain/piece/ElephantStrategy.java +++ b/src/main/java/domain/piece/ElephantStrategy.java @@ -28,9 +28,8 @@ public List getPathPositions(Position from, Position to) { Position step1 = from.next(mainDirection); Position step2 = step1.next(mainDirection).next(subDirection); - Position step3 = step2.next(mainDirection).next(subDirection); - return List.of(step1, step2, step3); + return List.of(step1, step2); } private Direction decideXDirection(int dx) { @@ -48,11 +47,9 @@ private Direction decideYDirection(int dy) { } @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece to) { + if (!paths.isEmpty() ) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/GeneralStrategy.java b/src/main/java/domain/piece/GeneralStrategy.java index d1e1ba7ce1..734ef411ad 100644 --- a/src/main/java/domain/piece/GeneralStrategy.java +++ b/src/main/java/domain/piece/GeneralStrategy.java @@ -19,15 +19,13 @@ public List getPathPositions(Position from, Position to) { if(!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } - return List.of(to); + return List.of(); } @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece toa) { + if (!paths.isEmpty() ) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/GuardStrategy.java b/src/main/java/domain/piece/GuardStrategy.java index 8dabee5439..172ac88ef8 100644 --- a/src/main/java/domain/piece/GuardStrategy.java +++ b/src/main/java/domain/piece/GuardStrategy.java @@ -20,15 +20,13 @@ public List getPathPositions(Position from, Position to) { if(!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } - return List.of(to); + return List.of(); } @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece to) { + if (!paths.isEmpty()) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/HanSoldierStrategy.java b/src/main/java/domain/piece/HanSoldierStrategy.java index 264c20ea8b..9514be9d10 100644 --- a/src/main/java/domain/piece/HanSoldierStrategy.java +++ b/src/main/java/domain/piece/HanSoldierStrategy.java @@ -21,15 +21,13 @@ public List getPathPositions(Position from, Position to) { if (!(isMoveLeft || isMoveRight || isMoveStraight)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } - return List.of(to); + return List.of(); } @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece to) { + if (!paths.isEmpty() ) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/HorseStrategy.java b/src/main/java/domain/piece/HorseStrategy.java index 7b103e424b..0d379ad587 100644 --- a/src/main/java/domain/piece/HorseStrategy.java +++ b/src/main/java/domain/piece/HorseStrategy.java @@ -27,10 +27,9 @@ public List getPathPositions(Position from, Position to) { } Position step1 = from.next(mainDirection); - Position step2 = step1.next(mainDirection).next(subDirection); - return List.of(step1, step2); + return List.of(step1); } private Direction decideXDirection(int dx) { @@ -48,11 +47,9 @@ private Direction decideYDirection(int dy) { } @Override - public void canMove(List paths, Position to) { - for (Path path : paths) { - if (path.position() != to) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } + public void canMove(List paths, Piece to) { + if (!paths.isEmpty() ) { + throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/MoveStrategy.java b/src/main/java/domain/piece/MoveStrategy.java index bc5f4087e4..5d85e016a8 100644 --- a/src/main/java/domain/piece/MoveStrategy.java +++ b/src/main/java/domain/piece/MoveStrategy.java @@ -11,5 +11,5 @@ public interface MoveStrategy { List getPathPositions(Position from, Position to); // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) - void canMove(List paths, Position to); + void canMove(List paths, Piece to); } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 3f972c9875..7ea70bdc83 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -8,10 +8,14 @@ public record Piece(PieceType pieceType, Team team, MoveStrategy moveStrategy) { - List getPathPositions(Position from, Position to) { + public List getPathPositions(Position from, Position to) { return moveStrategy.getPathPositions(from, to); } + public void canMove(List paths, Piece to) { + moveStrategy.canMove(paths, to); + } + @Override public boolean equals(Object o) { if (!(o instanceof Piece piece)) return false; @@ -23,12 +27,7 @@ public int hashCode() { return Objects.hash(pieceType, team); } - // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) - void canMove(List paths, Position to) { - moveStrategy.canMove(paths, to); - } - - boolean isSameTeam(Piece another){ + public boolean isSameTeam(Piece another){ return another.team == team; } } diff --git a/src/test/java/domain/piece/CannonStrategyTest.java b/src/test/java/domain/piece/CannonStrategyTest.java new file mode 100644 index 0000000000..b9ca552153 --- /dev/null +++ b/src/test/java/domain/piece/CannonStrategyTest.java @@ -0,0 +1,76 @@ +package domain.piece; + +import domain.Path; +import domain.board.Position; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + + +class CannonStrategyTest { + + Piece piece; + + @BeforeEach + void setUp() { + piece = new Piece(PieceType.CANNON, Team.CHO, new CannonStrategy()); + } + + @Test + void 포는_기물이_사이에_하나의_기물이_있으면_정상적으로_움직일_수_있다() { + List paths = List.of(new Path(new Position(3, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy()))); + + assertDoesNotThrow(() -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy()))); + } + + + @Test + void 포는_기물이_사이에_하나라도_존재하지_않으면_예외를_반환한다() { + List paths = List.of(); + + assertThrows(IllegalStateException.class, + () -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) + ); + } + + @Test + void 포는_기물이_사이에_두개_이상_존재하면_예외를_반환한다() { + List paths = List.of( + new Path(new Position(3, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())), + new Path(new Position(6, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) + ); + + + assertThrows(IllegalStateException.class, + () -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) + ); + } + + @Test + void 포는_기물이_사이에_포가_존재하면_예외를_반환한다() { + List paths = List.of( + new Path(new Position(3, 0), new Piece(PieceType.CANNON, Team.HAN, new CannonStrategy())) + ); + + assertThrows(IllegalStateException.class, + () -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) + ); + } + + @Test + void 포는_목적지에_포가_존재하면_예외를_반환한다() { + List paths = List.of( + new Path(new Position(3, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) + ); + + assertThrows(IllegalStateException.class, + () -> piece.canMove(paths, new Piece(PieceType.CANNON, Team.HAN, new CannonStrategy())) + ); + } + +} diff --git a/src/test/java/domain/piece/CannonTest.java b/src/test/java/domain/piece/CannonTest.java index 3d201f659b..c4269ad7b9 100644 --- a/src/test/java/domain/piece/CannonTest.java +++ b/src/test/java/domain/piece/CannonTest.java @@ -25,7 +25,7 @@ void setUp() { List pathPositions = cannon.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5), new Position(2, 5))); + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5))); } @Test @@ -36,7 +36,7 @@ void setUp() { List pathPositions = cannon.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5), new Position(8, 5))); + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5))); } @@ -48,7 +48,7 @@ void setUp() { List pathPositions = cannon.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(5, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); } @@ -61,7 +61,7 @@ void setUp() { assertThat(pathPositions).isEqualTo(List.of( - new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1), new Position(5, 0))); + new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1))); } } diff --git a/src/test/java/domain/piece/ChariotTest.java b/src/test/java/domain/piece/ChariotTest.java index e60735ff04..3935c0388e 100644 --- a/src/test/java/domain/piece/ChariotTest.java +++ b/src/test/java/domain/piece/ChariotTest.java @@ -25,7 +25,7 @@ void setUp() { List pathPositions = chariot.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5), new Position(2, 5))); + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5))); } @Test @@ -36,7 +36,7 @@ void setUp() { List pathPositions = chariot.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5), new Position(8, 5))); + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5))); } @@ -48,7 +48,7 @@ void setUp() { List pathPositions = chariot.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(5, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); } @@ -61,7 +61,7 @@ void setUp() { assertThat(pathPositions).isEqualTo(List.of( - new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1), new Position(5, 0))); + new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1))); } diff --git a/src/test/java/domain/piece/ElephantTest.java b/src/test/java/domain/piece/ElephantTest.java index 0292d715ab..564f07f680 100644 --- a/src/test/java/domain/piece/ElephantTest.java +++ b/src/test/java/domain/piece/ElephantTest.java @@ -23,7 +23,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(4, 7), new Position(3, 8))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(4, 7))); } @Test @@ -34,7 +34,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(6, 7), new Position(7, 8))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(6, 7))); } @@ -45,7 +45,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 6), new Position(2, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 6))); } @@ -56,7 +56,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 4), new Position(2, 3))); + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 4))); } @@ -67,7 +67,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(4, 3), new Position(3, 2))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(4, 3))); } @@ -78,7 +78,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(6, 3), new Position(7, 2))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(6, 3))); } @@ -89,7 +89,7 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6), new Position(8, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); } @@ -100,6 +100,6 @@ void setUp() { List pathPositions = elephant.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6), new Position(8, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); } } diff --git a/src/test/java/domain/piece/GeneralTest.java b/src/test/java/domain/piece/GeneralTest.java index 72614328c6..031da4729a 100644 --- a/src/test/java/domain/piece/GeneralTest.java +++ b/src/test/java/domain/piece/GeneralTest.java @@ -23,7 +23,7 @@ void setUp() { List pathPositions = general.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 2))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -33,7 +33,7 @@ void setUp() { List pathPositions = general.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(3, 1))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -43,7 +43,7 @@ void setUp() { List pathPositions = general.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 1))); + assertThat(pathPositions).isEqualTo(List.of()); } @@ -54,6 +54,6 @@ void setUp() { List pathPositions = general.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 0))); + assertThat(pathPositions).isEqualTo(List.of()); } } diff --git a/src/test/java/domain/piece/GuardTest.java b/src/test/java/domain/piece/GuardTest.java index 06aec13828..18a59ee82d 100644 --- a/src/test/java/domain/piece/GuardTest.java +++ b/src/test/java/domain/piece/GuardTest.java @@ -23,7 +23,7 @@ void setUp() { List pathPositions = guard.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(3, 1))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -33,7 +33,7 @@ void setUp() { List pathPositions = guard.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 0))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -43,7 +43,7 @@ void setUp() { List pathPositions = guard.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 0))); + assertThat(pathPositions).isEqualTo(List.of()); } @@ -54,6 +54,6 @@ void setUp() { List pathPositions = guard.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(3, 0))); + assertThat(pathPositions).isEqualTo(List.of()); } } diff --git a/src/test/java/domain/piece/HorseTest.java b/src/test/java/domain/piece/HorseTest.java index 39e66d4134..2f7c18a61e 100644 --- a/src/test/java/domain/piece/HorseTest.java +++ b/src/test/java/domain/piece/HorseTest.java @@ -23,7 +23,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(4, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); } @Test @@ -34,7 +34,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(6, 7))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); } @@ -45,7 +45,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 6))); + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5))); } @@ -56,7 +56,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 4))); + assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5))); } @@ -67,7 +67,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(4, 3))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4))); } @@ -78,7 +78,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(6, 3))); + assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4))); } @@ -89,7 +89,7 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5))); } @@ -100,6 +100,6 @@ void setUp() { List pathPositions = horse.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); + assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5))); } } diff --git a/src/test/java/domain/piece/SoldierChoTest.java b/src/test/java/domain/piece/SoldierChoTest.java index a25245ed09..9034d3a7f3 100644 --- a/src/test/java/domain/piece/SoldierChoTest.java +++ b/src/test/java/domain/piece/SoldierChoTest.java @@ -24,7 +24,7 @@ void setUp() { List pathPositions = soldier.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(0, 4))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -34,7 +34,7 @@ void setUp() { List pathPositions = soldier.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -44,7 +44,7 @@ void setUp() { List pathPositions = soldier.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + assertThat(pathPositions).isEqualTo(List.of()); } } diff --git a/src/test/java/domain/piece/SoldierHanTest.java b/src/test/java/domain/piece/SoldierHanTest.java index bbcbff4cc5..88174a3804 100644 --- a/src/test/java/domain/piece/SoldierHanTest.java +++ b/src/test/java/domain/piece/SoldierHanTest.java @@ -24,7 +24,7 @@ void setUp() { List pathPositions = soldier.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(0, 3))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -34,7 +34,7 @@ void setUp() { List pathPositions = soldier.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + assertThat(pathPositions).isEqualTo(List.of()); } @Test @@ -44,7 +44,7 @@ void setUp() { List pathPositions = soldier.getPathPositions(from, to); - assertThat(pathPositions).isEqualTo(List.of(new Position(1, 3))); + assertThat(pathPositions).isEqualTo(List.of()); } } From 5fcb7570a3f44a5a7fa7b72ef55c3167bcd8d418 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sat, 28 Mar 2026 10:27:02 +0900 Subject: [PATCH 19/58] =?UTF-8?q?docs(README):=20=EA=B8=B0=EB=AC=BC?= =?UTF-8?q?=EC=9D=98=20=EC=9D=B4=EB=8F=99=20=EA=B8=B0=EB=8A=A5=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f1987dd04c..e7a5b5845c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,69 @@ # java-janggi -## 1. 보드 초기화 +## 1.1 보드 초기화 - [x] 보드의 크기는 9행 10열이다. -- [ ] 초기 배치 방법은 4가지가 있다. - - 마상 상마 (원앙마), 상마 상마 (귀마), 마상 마상 (귀마), 상마 마상 (양귀마) - - [ ] 초기구현은 원앙마로만 제한한다. -- [ ] 게임 시작 시, 각 진영마다 졸/병 5개, 포,상,마,차,사 2개, 궁 1개의 기물이 배치된다. -- [ ] 좌표의 원점은 플레이어의 좌하단을 기준으로 한다. +- [x] 초기 상차림은 4가지가 있다. + - [x] 마상 상마 (원앙마), 상마 상마 (귀마), 마상 마상 (귀마), 상마 마상 (양귀마) + - [x] 모든 상차림에 대해 구현한다. +- [x] 게임 시작 시, 각 진영마다 졸/병 5개, 포,상,마,차,사 2개, 궁 1개의 기물이 배치된다. +- [x] 좌표의 원점은 보드의 좌하단을 기준으로 한다. +- [x] 초는 밑에 한은 위에 기물이 존재한다. + +## 1.2 기물 이동 + +- [x] 각 기물의 이동 규칙을 구현한다. 궁성 영역은 구현하지 않는다. + +### 공통 +- [x] 이동하고자 하는 기물의 최종 목적지에 자신의 기물이 있을 때는 이동할 수 없다. +### 졸/병 + +- [x] 기물이 좌우로 한칸씩 움직일 수 있다. +- [x] 초는 위로, 한은 아래로 한칸씩 움직일 수 있다. + +### 궁 + +- [x] 기물이 상하좌우로 한칸씩 움직일 수 있다. +- [x] 궁성 영역은 고려하지 않는다. + +### 사 + +- [x] 기물이 상하좌우로 한칸씩 움직일 수 있다. +- [x] 궁성 영역은 고려하지 않는다. + +### 마 + +- [x] 직선으로 한칸, 그리고 앞서 움직였던 방향을 포함한 대각선 방향으로 한칸 움직일 수 있다. + - [x] 위로 한번, 좌상단 대각선 방향으로 한번 움직인다. + - [x] 위로 한번, 우상단 대각선 방향으로 한번 움직인다. + - [x] 아래로 한번, 좌하단 대각선 방향으로 한번 움직인다. + - [x] 아래로 한번, 우하단 대각선 방향으로 한번 움직인다. + - [x] 좌로 한번, 좌상단 대각선 방향으로 한번 움직인다. + - [x] 좌로 한번, 좌하단 대각선 방향으로 한번 움직인다. + - [x] 우로 한번, 우상단 대각선 방향으로 한번 움직인다. + - [x] 우로 한번, 우하단 대각선 방향으로 한번 움직인다. +- [x] 이동하는 도중, 어떠한 기물이라도 있다면, 이동할 수 없다. + +### 상 + +- [x] 직선으로 한칸, 그리고 앞서 움직였던 방향을 포함한 대각선 방향으로 두칸 움직일 수 있다. + - [x] 위로 한번, 좌상단 대각선 방향으로 두번 움직인다. + - [x] 위로 한번, 우상단 대각선 방향으로 두번 움직인다. + - [x] 아래로 한번, 좌하단 대각선 방향으로 두번 움직인다. + - [x] 아래로 한번, 우하단 대각선 방향으로 두번 움직인다. + - [x] 좌로 한번, 좌상단 대각선 방향으로 두번 움직인다. + - [x] 좌로 한번, 좌하단 대각선 방향으로 두번 움직인다. + - [x] 우로 한번, 우상단 대각선 방향으로 두번 움직인다. + - [x] 우로 한번, 우하단 대각선 방향으로 두번 움직인다. +- [x] 이동하는 도중, 어떠한 기물이라도 있다면, 이동할 수 없다. + + +### 차 +- [x] 직선방향으로만 움직일 수 있다. +- [x] 이동하는 도중, 어떠한 기물이라도 있다면, 이동할 수 없다. + +### 포 +- [x] 직선방향으로만 움직일 수 있다. +- [x] 이동하고자 하는 위치 사이에 기물이 하나 존재해야한다. +- [x] 사이에 있는 기물이 포여서는 안된다. +- [x] 포는 포를 잡을 수 없다. 즉 최종 목적지에 포여서도 안된다. From 4723ed7c6365e99692098fb2f784b789ebd20172 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sat, 28 Mar 2026 10:30:37 +0900 Subject: [PATCH 20/58] =?UTF-8?q?style:=20=EC=BD=94=EB=93=9C=20=ED=8F=AC?= =?UTF-8?q?=EB=A7=B7=20=EC=88=98=EC=A0=95,=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EC=A3=BC=EC=84=9D=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/Board.java | 21 ++++--------------- .../java/domain/board/InitializeSetting.java | 3 --- src/main/java/domain/board/Position.java | 1 - .../java/domain/piece/CannonStrategy.java | 8 +++---- .../java/domain/piece/ChariotStrategy.java | 2 +- .../java/domain/piece/ChoSoldierStrategy.java | 2 +- .../java/domain/piece/ElephantStrategy.java | 2 +- .../java/domain/piece/GeneralStrategy.java | 4 ++-- src/main/java/domain/piece/GuardStrategy.java | 2 +- .../java/domain/piece/HanSoldierStrategy.java | 2 +- src/main/java/domain/piece/HorseStrategy.java | 2 +- src/main/java/domain/piece/Piece.java | 2 +- src/test/java/domain/board/BoardTest.java | 2 +- src/test/java/domain/piece/CannonTest.java | 2 +- src/test/java/domain/piece/ChariotTest.java | 3 +-- src/test/java/domain/piece/GeneralTest.java | 2 +- 16 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 062a48a9d3..faa9dfe559 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -19,26 +19,15 @@ public Piece getPiece(Position position) { } public void move(Position from, Position to) { - - // (1) piece 가 해당 도착지(to)로 도착하는 경로 반환 : Piece의 getPathPositions 호출 - - Piece fromPiece = pieces.get(from); // 실제 움직일 애 + Piece fromPiece = pieces.get(from); Piece toPiece = pieces.get(to); - List pathPositions = fromPiece.getPathPositions(from, to); // 좌표(경유지) 목록을 반환 - List path = getPath(pathPositions); // 해당 좌표(경유지)에 대해서 반환함. + List pathPositions = fromPiece.getPathPositions(from, to); + List path = getPath(pathPositions); fromPiece.canMove(path, toPiece); - - + if (fromPiece.isSameTeam(toPiece)) { throw new IllegalStateException("같은 팀의 기물을 잡을 수 없습니다."); } - - // 잡는 행위 - // 실제로 옮겨진 - // 상대편 위치, 지금할껀지 or 있다가 할껀지, 초/한 - - // (2) 1에서 받은 값으로 getPathWithPiece 호출하여 Piece의 canMove 호출 - // 해당 위치(from)에 기물이 위치하고 있는지 } public List getPath(List positions) { @@ -50,6 +39,4 @@ public List getPath(List positions) { } return paths; } - - // TODO 같은 팀이면 예외 발생, 다른 팀이면 잡는 함수 작성 필요(move 안에) } diff --git a/src/main/java/domain/board/InitializeSetting.java b/src/main/java/domain/board/InitializeSetting.java index 6df7c9fc77..812216f4aa 100644 --- a/src/main/java/domain/board/InitializeSetting.java +++ b/src/main/java/domain/board/InitializeSetting.java @@ -19,7 +19,4 @@ public enum InitializeSetting { public List getInitialSetting() { return initialSetting; } - - - } diff --git a/src/main/java/domain/board/Position.java b/src/main/java/domain/board/Position.java index f67792ffb2..0dd7699b51 100644 --- a/src/main/java/domain/board/Position.java +++ b/src/main/java/domain/board/Position.java @@ -53,5 +53,4 @@ public int getY() { public Position next(Direction direction) { return new Position(x + direction.getDx(), y + direction.getDy()); } - } diff --git a/src/main/java/domain/piece/CannonStrategy.java b/src/main/java/domain/piece/CannonStrategy.java index dcdf467fa4..1ad8727ddf 100644 --- a/src/main/java/domain/piece/CannonStrategy.java +++ b/src/main/java/domain/piece/CannonStrategy.java @@ -13,7 +13,7 @@ public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); int dy = to.getY() - from.getY(); - if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))){ + if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))) { throw new IllegalArgumentException("차를 해당 위치로 옮길 수 없습니다."); } @@ -56,18 +56,18 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Piece to) { - if(paths.size() != 1) { + if (paths.size() != 1) { throw new IllegalStateException("포는 한 기물만 뛰어 넘을 수 있습니다."); } Piece piece = paths.getFirst().piece(); - if(piece.pieceType() == PieceType.CANNON) { + if (piece.pieceType() == PieceType.CANNON) { throw new IllegalStateException("포는 포를 뛰어 넘을 수 있습니다."); } - if(to.pieceType() == PieceType.CANNON) { + if (to.pieceType() == PieceType.CANNON) { throw new IllegalStateException("포를 잡을 수 없습니다"); } } diff --git a/src/main/java/domain/piece/ChariotStrategy.java b/src/main/java/domain/piece/ChariotStrategy.java index 018dd1b885..237c422a87 100644 --- a/src/main/java/domain/piece/ChariotStrategy.java +++ b/src/main/java/domain/piece/ChariotStrategy.java @@ -55,7 +55,7 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Piece to) { - if (!paths.isEmpty() ) { + if (!paths.isEmpty()) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } diff --git a/src/main/java/domain/piece/ChoSoldierStrategy.java b/src/main/java/domain/piece/ChoSoldierStrategy.java index 3f1ee60ad1..9074fd1652 100644 --- a/src/main/java/domain/piece/ChoSoldierStrategy.java +++ b/src/main/java/domain/piece/ChoSoldierStrategy.java @@ -26,7 +26,7 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Piece to) { - if (!paths.isEmpty() ) { + if (!paths.isEmpty()) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } diff --git a/src/main/java/domain/piece/ElephantStrategy.java b/src/main/java/domain/piece/ElephantStrategy.java index 2a641a67f0..7d7b0b8bc2 100644 --- a/src/main/java/domain/piece/ElephantStrategy.java +++ b/src/main/java/domain/piece/ElephantStrategy.java @@ -48,7 +48,7 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Piece to) { - if (!paths.isEmpty() ) { + if (!paths.isEmpty()) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } diff --git a/src/main/java/domain/piece/GeneralStrategy.java b/src/main/java/domain/piece/GeneralStrategy.java index 734ef411ad..df6a3425f4 100644 --- a/src/main/java/domain/piece/GeneralStrategy.java +++ b/src/main/java/domain/piece/GeneralStrategy.java @@ -16,7 +16,7 @@ public List getPathPositions(Position from, Position to) { boolean isMoveRight = dx == 1 && dy == 0; boolean isMoveDown = dx == 0 && dy == -1; - if(!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { + if (!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } return List.of(); @@ -24,7 +24,7 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Piece toa) { - if (!paths.isEmpty() ) { + if (!paths.isEmpty()) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } diff --git a/src/main/java/domain/piece/GuardStrategy.java b/src/main/java/domain/piece/GuardStrategy.java index 172ac88ef8..063df8517f 100644 --- a/src/main/java/domain/piece/GuardStrategy.java +++ b/src/main/java/domain/piece/GuardStrategy.java @@ -17,7 +17,7 @@ public List getPathPositions(Position from, Position to) { boolean isMoveRight = dx == 1 && dy == 0; boolean isMoveDown = dx == 0 && dy == -1; - if(!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { + if (!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { throw new IllegalArgumentException("움직일 수 없는 위치입니다."); } return List.of(); diff --git a/src/main/java/domain/piece/HanSoldierStrategy.java b/src/main/java/domain/piece/HanSoldierStrategy.java index 9514be9d10..070200d505 100644 --- a/src/main/java/domain/piece/HanSoldierStrategy.java +++ b/src/main/java/domain/piece/HanSoldierStrategy.java @@ -26,7 +26,7 @@ public List getPathPositions(Position from, Position to) { @Override public void canMove(List paths, Piece to) { - if (!paths.isEmpty() ) { + if (!paths.isEmpty()) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } diff --git a/src/main/java/domain/piece/HorseStrategy.java b/src/main/java/domain/piece/HorseStrategy.java index 0d379ad587..37fcc7ac84 100644 --- a/src/main/java/domain/piece/HorseStrategy.java +++ b/src/main/java/domain/piece/HorseStrategy.java @@ -48,7 +48,7 @@ private Direction decideYDirection(int dy) { @Override public void canMove(List paths, Piece to) { - if (!paths.isEmpty() ) { + if (!paths.isEmpty()) { throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); } } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 7ea70bdc83..2484d01abc 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -27,7 +27,7 @@ public int hashCode() { return Objects.hash(pieceType, team); } - public boolean isSameTeam(Piece another){ + public boolean isSameTeam(Piece another) { return another.team == team; } } diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index fa58a34b9b..ef45dbc644 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -101,7 +101,7 @@ static Stream cannonProvider() { List path = board.getPath(positions); assertThat(path).isEqualTo(List.of(new Path( - new Position(1, 0), new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy())), + new Position(1, 0), new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy())), new Path(new Position(2, 0), new Piece(PieceType.ELEPHANT, Team.CHO, new ElephantStrategy())) )); } diff --git a/src/test/java/domain/piece/CannonTest.java b/src/test/java/domain/piece/CannonTest.java index c4269ad7b9..a0faf6f559 100644 --- a/src/test/java/domain/piece/CannonTest.java +++ b/src/test/java/domain/piece/CannonTest.java @@ -61,7 +61,7 @@ void setUp() { assertThat(pathPositions).isEqualTo(List.of( - new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1))); + new Position(5, 4), new Position(5, 3), new Position(5, 2), new Position(5, 1))); } } diff --git a/src/test/java/domain/piece/ChariotTest.java b/src/test/java/domain/piece/ChariotTest.java index 3935c0388e..194d3c161c 100644 --- a/src/test/java/domain/piece/ChariotTest.java +++ b/src/test/java/domain/piece/ChariotTest.java @@ -61,9 +61,8 @@ void setUp() { assertThat(pathPositions).isEqualTo(List.of( - new Position(5, 4), new Position(5, 3), new Position(5, 2),new Position(5, 1))); + new Position(5, 4), new Position(5, 3), new Position(5, 2), new Position(5, 1))); } - } diff --git a/src/test/java/domain/piece/GeneralTest.java b/src/test/java/domain/piece/GeneralTest.java index 031da4729a..5f2095a581 100644 --- a/src/test/java/domain/piece/GeneralTest.java +++ b/src/test/java/domain/piece/GeneralTest.java @@ -19,7 +19,7 @@ void setUp() { @Test void 궁은_위로_한칸_움직일_수_있는_경로가_있다() { Position from = new Position(4, 1); - Position to = new Position(4,2); + Position to = new Position(4, 2); List pathPositions = general.getPathPositions(from, to); From e595d08679f371a9d1e2fe468610ad920c61def7 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sat, 28 Mar 2026 10:55:18 +0900 Subject: [PATCH 21/58] =?UTF-8?q?fix(PieceMove):=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=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/Board.java | 7 +++++-- src/main/java/domain/piece/CannonStrategy.java | 4 ++-- src/main/java/domain/piece/ElephantStrategy.java | 4 ++++ src/main/java/domain/piece/HorseStrategy.java | 4 ++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index faa9dfe559..d318c1d177 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -24,10 +24,13 @@ public void move(Position from, Position to) { List pathPositions = fromPiece.getPathPositions(from, to); List path = getPath(pathPositions); fromPiece.canMove(path, toPiece); - - if (fromPiece.isSameTeam(toPiece)) { + + if (toPiece != null && fromPiece.isSameTeam(toPiece)) { throw new IllegalStateException("같은 팀의 기물을 잡을 수 없습니다."); } + + Piece remove = pieces.remove(from); + pieces.put(to, remove); } public List getPath(List positions) { diff --git a/src/main/java/domain/piece/CannonStrategy.java b/src/main/java/domain/piece/CannonStrategy.java index 1ad8727ddf..af8a3842ad 100644 --- a/src/main/java/domain/piece/CannonStrategy.java +++ b/src/main/java/domain/piece/CannonStrategy.java @@ -14,7 +14,7 @@ public List getPathPositions(Position from, Position to) { int dy = to.getY() - from.getY(); if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))) { - throw new IllegalArgumentException("차를 해당 위치로 옮길 수 없습니다."); + throw new IllegalArgumentException("포를 해당 위치로 옮길 수 없습니다."); } Direction mainDirection; @@ -67,7 +67,7 @@ public void canMove(List paths, Piece to) { throw new IllegalStateException("포는 포를 뛰어 넘을 수 있습니다."); } - if (to.pieceType() == PieceType.CANNON) { + if (to != null && to.pieceType() == PieceType.CANNON) { throw new IllegalStateException("포를 잡을 수 없습니다"); } } diff --git a/src/main/java/domain/piece/ElephantStrategy.java b/src/main/java/domain/piece/ElephantStrategy.java index 7d7b0b8bc2..114a84e40c 100644 --- a/src/main/java/domain/piece/ElephantStrategy.java +++ b/src/main/java/domain/piece/ElephantStrategy.java @@ -13,6 +13,10 @@ public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); int dy = to.getY() - from.getY(); + if (!((Math.abs(dx) == 3 && Math.abs(dy) == 2) || (Math.abs(dx) == 2 && Math.abs(dy) == 3))) { + throw new IllegalArgumentException("상이 이동할 수 없습니다."); + } + Direction xDirection = decideXDirection(dx); Direction yDirection = decideYDirection(dy); diff --git a/src/main/java/domain/piece/HorseStrategy.java b/src/main/java/domain/piece/HorseStrategy.java index 37fcc7ac84..8aadfa559b 100644 --- a/src/main/java/domain/piece/HorseStrategy.java +++ b/src/main/java/domain/piece/HorseStrategy.java @@ -13,6 +13,10 @@ public List getPathPositions(Position from, Position to) { int dx = to.getX() - from.getX(); int dy = to.getY() - from.getY(); + if (!((Math.abs(dx) == 2 && Math.abs(dy) == 1) || (Math.abs(dx) == 1 && Math.abs(dy) == 2))) { + throw new IllegalArgumentException("마가 이동할 수 없습니다."); + } + Direction xDirection = decideXDirection(dx); Direction yDirection = decideYDirection(dy); From 1d2e22ca4e0c5629fe86359ad3e128e5c6c20df4 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sat, 28 Mar 2026 10:57:08 +0900 Subject: [PATCH 22/58] =?UTF-8?q?feat(view):=20=EC=9E=A5=EA=B8=B0=EC=97=90?= =?UTF-8?q?=20=EB=8C=80=ED=95=B4=20=ED=99=95=EC=9D=B8=ED=95=A0=20=EC=88=98?= =?UTF-8?q?=20=EC=9E=88=EB=8A=94=20=EB=B7=B0,=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 간단한 형태로, 움직임만 확인할 수 있도록 뷰 및 컨트롤러 구현 - 현재 좌표, 이동 좌표로 확인만 할 수 있도록 확인 --- src/main/java/Application.java | 8 ++++ src/main/java/controller/Controller.java | 47 +++++++++++++++++++++++ src/main/java/view/InputView.java | 48 ++++++++++++++++++++++++ src/main/java/view/OutputView.java | 46 +++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 src/main/java/controller/Controller.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 index bdbffd531f..7b8239347b 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,5 +1,13 @@ +import controller.Controller; +import view.InputView; +import view.OutputView; + public class Application { public static void main(String[] args) { + InputView inputView = new InputView(); + OutputView outputView = new OutputView(); + Controller controller = new Controller(inputView, outputView); + controller.run(); } } diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java new file mode 100644 index 0000000000..0659c51d2f --- /dev/null +++ b/src/main/java/controller/Controller.java @@ -0,0 +1,47 @@ +package controller; + +import domain.board.Board; +import domain.board.BoardFactory; +import domain.board.InitializeSetting; +import domain.board.Position; +import view.InputView; +import view.OutputView; + +public class Controller { + private final InputView inputView; + private final OutputView outputView; + + public Controller(InputView inputView, OutputView outputView) { + this.inputView = inputView; + this.outputView = outputView; + } + + public void run() { + try { + InitializeSetting choSetting = inputView.readInitialSetting("초(CHO)"); + InitializeSetting hanSetting = inputView.readInitialSetting("한(HAN)"); + + Board board = BoardFactory.createBoard(choSetting, hanSetting); + + play(board); + } catch (Exception e) { + outputView.printError(e); + } + } + + private void play(Board board) { + while (true) { + try { + outputView.printBoard(board); + Position[] positions = inputView.readMoveCommand(); + + Position from = positions[0]; + Position to = positions[1]; + + board.move(from, to); + } catch (Exception e) { + outputView.printError(e); + } + } + } +} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000000..2e6e488a40 --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,48 @@ +package view; + +import domain.board.InitializeSetting; +import domain.board.Position; + +import java.util.Scanner; + +public class InputView { + private final Scanner scanner = new Scanner(System.in); + + public InitializeSetting readInitialSetting(String teamName) { + System.out.println("===" + teamName + " 진영 상차림을 선택하세요 ==="); + System.out.println("1. 왼상차림 (상마상마)"); + System.out.println("2. 오른상차림 (마상마상)"); + System.out.println("3. 안상차림 (마상상마)"); + System.out.println("4. 바깥상차림 (상마마상)"); + System.out.print("선택: "); + + int choice = Integer.parseInt(scanner.nextLine().trim()); + return switch (choice) { + case 1 -> InitializeSetting.LEFT_ELEPHANT_SETTING; + case 2 -> InitializeSetting.RIGHT_ELEPHANT_SETTING; + case 3 -> InitializeSetting.INNER_ELEPHANT_SETTING; + case 4 -> InitializeSetting.OUTER_ELEPHANT_SETTING; + default -> throw new IllegalArgumentException("잘못된 선택입니다."); + }; + } + + public Position[] readMoveCommand() { + System.out.println("\n이동할 기물의 시작 좌표와 도착 좌표를 입력하세요. (예: 0,0 1,0)"); + System.out.print("입력: "); + String input = scanner.nextLine().trim(); + String[] parts = input.split(" "); + + if (parts.length != 2) { + throw new IllegalArgumentException("올바른 형식이 아닙니다. (예: 0,0 1,0)"); + } + + return new Position[]{parsePosition(parts[0]), parsePosition(parts[1])}; + } + + private Position parsePosition(String positionStr) { + String[] coords = positionStr.split(","); + int x = Integer.parseInt(coords[0].trim()); + int y = Integer.parseInt(coords[1].trim()); + return new Position(x, y); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 0000000000..c6c232fbf8 --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,46 @@ +package view; + +import domain.board.Board; +import domain.board.Position; +import domain.piece.Piece; +import domain.piece.Team; + +public class OutputView { + + public void printBoard(Board board) { + System.out.println("\n 0 1 2 3 4 5 6 7 8 (X)"); + for (int y = 9; y >= 0; y--) { + System.out.print(y + " "); + for (int x = 0; x <= 8; x++) { + Position currentPosition = new Position(x, y); + Piece piece = board.getPiece(currentPosition); + System.out.print(getPieceSymbol(piece) + " "); + } + System.out.println(); + } + System.out.println("(Y)\n"); + } + + public void printError(Exception e) { + System.out.println("[ERROR] " + e.getMessage()); + } + + private String getPieceSymbol(Piece piece) { + if (piece == null) { + return " . "; + } + + String teamPrefix = piece.team() == Team.CHO ? "초" : "한"; + String typeName = switch (piece.pieceType()) { + case GENERAL -> "장"; + case CHARIOT -> "차"; + case CANNON -> "포"; + case HORSE -> "마"; + case ELEPHANT -> "상"; + case GUARD -> "사"; + case SOLDIER -> piece.team() == Team.CHO ? "졸" : "병"; + }; + + return teamPrefix + typeName; + } +} From 83f9817baa8d6e19da67f4c7c3e6844352abc1f8 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sat, 28 Mar 2026 11:17:41 +0900 Subject: [PATCH 23/58] =?UTF-8?q?docs(README):=20=ED=86=A0=EB=A1=A0?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9E=91=EC=84=B1=ED=95=9C=20=EA=B7=9C?= =?UTF-8?q?=EC=B9=99,=20=EB=AF=B8=EC=85=98=20=EC=A4=91=20=EA=B8=B0?= =?UTF-8?q?=EB=A1=9D=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/README.md b/README.md index e7a5b5845c..74ff5430db 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # java-janggi +# 구현 할 기능 목록 ## 1.1 보드 초기화 - [x] 보드의 크기는 9행 10열이다. @@ -67,3 +68,125 @@ - [x] 이동하고자 하는 위치 사이에 기물이 하나 존재해야한다. - [x] 사이에 있는 기물이 포여서는 안된다. - [x] 포는 포를 잡을 수 없다. 즉 최종 목적지에 포여서도 안된다. + +

+ +# 규칙 +## **1. 테스트 단위 기준** + +- 테스트는 **public 메서드 단위**로 작성한다. + - 이 때 메서드는 **한 가지 역할만 담당**하도록 만든다. + - private 메서드는 직접 테스트하지 않고 **public 메서드를 통해 간접 검증**한다. +- 테스트 코드 내부에 **조건문을 넣지 않는다.** + - 분기가 있는 경우 **경계값과 분기별 케이스를 나누어 테스트**한다. + +## **2. 테스트 제외 기준** + +- **입출력(UI)은 테스트하지 않는다. (ex. Scanner, print)** + - 다만 **입력값 검증은 테스트한다.** +- getter, 단순 객체 생성 자체는 테스트하지 않는다. +- enum은 무조건 테스트하지 않고, **의미 있는 로직이나 메서드가 있을 때만 테스트한다.** + + +## **3. 테스트가 어려울 때 대응** + +- 테스트가 어렵다면 **설계를 먼저 의심한다.** + - 메서드와 객체가 **단일 책임을 가지고 있는지 다시 점검한다.** + - 테스트가 어려웠던 이유를 기록하고, 이후 리팩터링의 근거로 삼는다. +- 랜덤 값, 시간 등 제어할 수 없는 요소는 외부에서 주입해주는 방식으로 변경한다. + - **인터페이스 추상화나 전략 분리**를 적극 사용한다. + +## **4. 책임 분리 기준** + +- 객체는 자신의 내부 상태를 외부에 공개하지 않고, **스스로 행동해야 한다.** + - 값을 꺼내 외부에서 판단하기보다, **해당 정보를 가장 잘 아는 객체에게 책임을 맡긴다.** +- “**(객체)는 (역할)로서 (행위)를 한다**”라는 문장에 대입해보고, 역할과 행위가 어색하게 섞여 있으면 책임 분리를 고려한다. +- 도메인 객체는 **도메인 규칙과 상태 관리에 집중**해야 한다. + - UI, 입출력, 프레임워크 의존성을 가지지 않도록 한다. + +## **5. 변경 범위 제한 규칙** + +- **같은 이유로 변경되는 코드는 함께 두고, 다른 이유로 변경되는 코드는 분리한다.** +- 변경 범위를 줄이기 위해 **추상화, 다형성, 캡슐화**를 고려한다. + - 검증 규칙이나 의미를 가진 값은 **Value Object**로 감싼다. + - 컬렉션에 의미와 규칙이 있다면 **일급 컬렉션**으로 다룬다. + + +## **6. 테스트와 설계의 관계** + +- **비즈니스 규칙이 변경되어 테스트가 깨지는 것은 건강한 실패**다. + - 이 경우 테스트도 함께 수정한다. +- 내부 구조만 리팩터링했는데 테스트가 깨진다면, 테스트가 **구현 세부사항에 과하게 의존하고 있는지 점검한다.** +- 테스트는 **구현이 아니라 행위**를 검증해야 한다. +- 테스트를 위해 설계를 망치지 않는다. + - 불필요한 getter, 생성자, 메서드 추가 및 테스트만을 위한 public 메서드 노출 +- TDD를 시작하기 전, 클래스 구조의 큰 틀과 시나리오 흐름 정도는 먼저 생각해본다. +- 작은 기능들을 테스트해 쌓아나가면서 하나의 큰 기능을 테스트하는 방향으로 간다. + +## 7. 상태 위치 규칙 (Single Source of Truth) + +- 하나의 상태는 **오직 한 객체만 소유한다.** 다른 객체들은 해당 상태를 **참조하거나 전달받아 사용한다.** +- 상태의 위치는 **객체 자체가 아니라 객체 간 협력 관계와 책임**을 기준으로 결정한다. + +## 8. 불변 객체 기준 + +- **가능한 모든 클래스를 불변 객체로 설계한다.** +- 내부 필드를 변경해야 할 경우 + → 기존 객체를 수정하지 않고 **새로운 불변 객체를 생성해 반환한다.** +- **변하지 않거나 변하면 안 되는 값은 반드시 불변으로 만든다.** + +## 9. 캡슐화 기준 + +- 객체 간 협력에 필요한 **메서드만 외부에 공개한다.** +- 그 외 모든 것은 객체 내부에 숨긴다. + - 객체의 **속성(필드)** + - 내부 구현 방식 + +## 10. `null` 사용 기준 + +- `null` 사용은 **최대한 지양한다.** +- 필요할 경우에는 `Optional`을 사용해 **명시적으로 감싸서 표현한다.** + +## 11. 조건문 대체 기준 (다형성 사용 시점) + +다음 상황에서는 조건문 대신 **다형성**을 고려한다. + +- 인터페이스가 존재하지만 **구체 클래스에 의존하는 조건 분기**가 있을 때 + +## 12. 역할 / 인터페이스 설계 기준 + +- **공통된 책임을 하나의 역할(인터페이스)로 묶는다.** +- **같은 질문에 다른 답을 하는 경우** → 다형성 후보로 판단한다. + + +## 13. 새 타입 추가 시 변경 범위 제한 규칙 + +- 새로운 타입이 추가될 때 **관련된 객체만 수정 가능**하도록 설계한다. + - 예: 새로운 용 타입 추가 → **행마법 관련 객체만 변경** +- 객체 자체를 수정하기보다**인터페이스 조합과 구현체 주입을 통해 확장**한다. +- 즉, + - 객체 구조는 유지하고 + - **새 구현체를 추가하는 방식으로 확장한다.** + +

+ +# 미션 중 기록 +- 상태 위치를 결정할 때 고민한 순간 1회 + - 기물의 위치는 기물이 제일 잘 알지 않을까라고 판단을해서, 원래는 기물이 스스로 판단하면 된다고 생각했습니다;. + - 하지만 움직임을 파악할 때 다른 기물의 위치도 전부 파악해야하므로, 보드가 위치를 파악하는 것이 맞다고 판단해서 수정하였습니다. +- 불변/캡슐화를 적용한 코드 1곳 + - 위치 정보는 불변이라고 생각이 들어, 이를 불변객체로 적용하였습니다. + - 또한 기물의 정보도, 실행 중에는 실행규칙이 절대 변경되지 않으므로 불변객체로 적용하였습니다. +- 규칙 적용으로 변경한 설계 1곳 + - 12번 규칙 역할/인터페이스 설계기준으로 인해, 조건문으로 판별했었던 코드를 전략패턴으로 수정해서 진행했습니다. +- 조건문을 다형성으로 대체한 코드 1곳 + - 기물들에 대해서 모두 다르게 움직이기 때문에, 기물의 종류를 파악하기 위해 조건문으로 판별하자고 생각했습니다. + - 이를 이후, MoveStrategy로 대체를 하여 진행하였습니다. +- 인터페이스/추상 클래스를 도입한 이유 + - 각각의 기물에 대해 서로 다른 규칙이 적용되는데, 모든 기물의 위치 정보는 보드가 기록하고 있었습니다. + - 보드가 기물의 규칙을 모두 알아야하는 문제점이 있었으며, 규칙이 변경될 때 마다 고쳐야하는 범위가 여기저기 흩어져 있었습니다. + - 각각의 기물에 움직임 규칙을 구현하고, 보드는 이를 몰라도 움직일 수 있는지, 없는지만 판별 할 수 있도록 인터페이스를 고려하였습니다. +- 새 기물 추가 시 변경 범위 테스트 (가상으로) + - 그 기물에 대한 전략 클래스를 구현합니다. + - 보드 초기화 때 새 기물의 위치를 추가합니다. + - 보드 자체에서는 변경되는 사항은 없습니다. From ec818804f238c090b781213fce99c0452e7f7843 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sat, 28 Mar 2026 11:27:33 +0900 Subject: [PATCH 24/58] =?UTF-8?q?style:=20=EC=99=80=EC=9D=BC=EB=93=9C=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=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/BoardFactory.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java index 5892be607e..5f256aa1af 100644 --- a/src/main/java/domain/board/BoardFactory.java +++ b/src/main/java/domain/board/BoardFactory.java @@ -1,6 +1,17 @@ package domain.board; -import domain.piece.*; + +import domain.piece.CannonStrategy; +import domain.piece.ChariotStrategy; +import domain.piece.ChoSoldierStrategy; +import domain.piece.ElephantStrategy; +import domain.piece.GeneralStrategy; +import domain.piece.GuardStrategy; +import domain.piece.HanSoldierStrategy; +import domain.piece.HorseStrategy; +import domain.piece.Piece; +import domain.piece.PieceType; +import domain.piece.Team; import java.util.HashMap; import java.util.List; From 9e98fcc2b087ab1a036a6f89f4a0f040c3edc0c6 Mon Sep 17 00:00:00 2001 From: JunHyung1206 Date: Sun, 29 Mar 2026 12:56:46 +0900 Subject: [PATCH 25/58] =?UTF-8?q?test(PieceMove):=20=EC=83=81=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/piece/ElephantTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/domain/piece/ElephantTest.java b/src/test/java/domain/piece/ElephantTest.java index 564f07f680..b6679e95db 100644 --- a/src/test/java/domain/piece/ElephantTest.java +++ b/src/test/java/domain/piece/ElephantTest.java @@ -29,7 +29,7 @@ void setUp() { @Test void 상은_위로_세칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { Position from = new Position(5, 5); - Position to = new Position(6, 7); + Position to = new Position(7, 8); List pathPositions = elephant.getPathPositions(from, to); From 5a2beb6044932e502d31b42bfb905c214e83407a Mon Sep 17 00:00:00 2001 From: frombunny Date: Mon, 30 Mar 2026 19:03:39 +0900 Subject: [PATCH 26/58] =?UTF-8?q?feat(Position):=20=EC=A2=8C=ED=91=9C=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 200 ++---------------- src/main/java/Application.java | 13 -- src/main/java/controller/Controller.java | 47 ---- src/main/java/domain/Direction.java | 24 --- src/main/java/domain/Path.java | 7 - src/main/java/domain/Position.java | 32 +++ src/main/java/domain/board/Board.java | 45 ---- src/main/java/domain/board/BoardFactory.java | 81 ------- .../java/domain/board/InitializeSetting.java | 22 -- src/main/java/domain/board/Position.java | 56 ----- .../java/domain/piece/CannonStrategy.java | 74 ------- .../java/domain/piece/ChariotStrategy.java | 62 ------ .../java/domain/piece/ChoSoldierStrategy.java | 33 --- .../java/domain/piece/ElephantStrategy.java | 59 ------ .../java/domain/piece/GeneralStrategy.java | 31 --- src/main/java/domain/piece/GuardStrategy.java | 32 --- .../java/domain/piece/HanSoldierStrategy.java | 33 --- src/main/java/domain/piece/HorseStrategy.java | 59 ------ src/main/java/domain/piece/MoveStrategy.java | 15 -- src/main/java/domain/piece/Piece.java | 33 --- src/main/java/domain/piece/PieceType.java | 11 - src/main/java/domain/piece/Team.java | 5 - src/main/java/view/InputView.java | 48 ----- src/main/java/view/OutputView.java | 46 ---- src/test/java/domain/PositionTest.java | 37 ++++ src/test/java/domain/board/BoardTest.java | 108 ---------- src/test/java/domain/board/PositionTest.java | 27 --- .../java/domain/piece/CannonStrategyTest.java | 76 ------- src/test/java/domain/piece/CannonTest.java | 67 ------ src/test/java/domain/piece/ChariotTest.java | 68 ------ src/test/java/domain/piece/ElephantTest.java | 105 --------- src/test/java/domain/piece/GeneralTest.java | 59 ------ src/test/java/domain/piece/GuardTest.java | 59 ------ src/test/java/domain/piece/HorseTest.java | 105 --------- src/test/java/domain/piece/PieceTest.java | 23 -- .../java/domain/piece/SoldierChoTest.java | 50 ----- .../java/domain/piece/SoldierHanTest.java | 50 ----- 37 files changed, 81 insertions(+), 1821 deletions(-) delete mode 100644 src/main/java/Application.java delete mode 100644 src/main/java/controller/Controller.java delete mode 100644 src/main/java/domain/Direction.java delete mode 100644 src/main/java/domain/Path.java create mode 100644 src/main/java/domain/Position.java delete mode 100644 src/main/java/domain/board/Board.java delete mode 100644 src/main/java/domain/board/BoardFactory.java delete mode 100644 src/main/java/domain/board/InitializeSetting.java delete mode 100644 src/main/java/domain/board/Position.java delete mode 100644 src/main/java/domain/piece/CannonStrategy.java delete mode 100644 src/main/java/domain/piece/ChariotStrategy.java delete mode 100644 src/main/java/domain/piece/ChoSoldierStrategy.java delete mode 100644 src/main/java/domain/piece/ElephantStrategy.java delete mode 100644 src/main/java/domain/piece/GeneralStrategy.java delete mode 100644 src/main/java/domain/piece/GuardStrategy.java delete mode 100644 src/main/java/domain/piece/HanSoldierStrategy.java delete mode 100644 src/main/java/domain/piece/HorseStrategy.java delete mode 100644 src/main/java/domain/piece/MoveStrategy.java delete mode 100644 src/main/java/domain/piece/Piece.java delete mode 100644 src/main/java/domain/piece/PieceType.java delete mode 100644 src/main/java/domain/piece/Team.java delete mode 100644 src/main/java/view/InputView.java delete mode 100644 src/main/java/view/OutputView.java create mode 100644 src/test/java/domain/PositionTest.java delete mode 100644 src/test/java/domain/board/BoardTest.java delete mode 100644 src/test/java/domain/board/PositionTest.java delete mode 100644 src/test/java/domain/piece/CannonStrategyTest.java delete mode 100644 src/test/java/domain/piece/CannonTest.java delete mode 100644 src/test/java/domain/piece/ChariotTest.java delete mode 100644 src/test/java/domain/piece/ElephantTest.java delete mode 100644 src/test/java/domain/piece/GeneralTest.java delete mode 100644 src/test/java/domain/piece/GuardTest.java delete mode 100644 src/test/java/domain/piece/HorseTest.java delete mode 100644 src/test/java/domain/piece/PieceTest.java delete mode 100644 src/test/java/domain/piece/SoldierChoTest.java delete mode 100644 src/test/java/domain/piece/SoldierHanTest.java diff --git a/README.md b/README.md index 74ff5430db..1cdb5275ad 100644 --- a/README.md +++ b/README.md @@ -1,192 +1,16 @@ # java-janggi -# 구현 할 기능 목록 ## 1.1 보드 초기화 -- [x] 보드의 크기는 9행 10열이다. -- [x] 초기 상차림은 4가지가 있다. - - [x] 마상 상마 (원앙마), 상마 상마 (귀마), 마상 마상 (귀마), 상마 마상 (양귀마) - - [x] 모든 상차림에 대해 구현한다. -- [x] 게임 시작 시, 각 진영마다 졸/병 5개, 포,상,마,차,사 2개, 궁 1개의 기물이 배치된다. -- [x] 좌표의 원점은 보드의 좌하단을 기준으로 한다. -- [x] 초는 밑에 한은 위에 기물이 존재한다. - -## 1.2 기물 이동 - -- [x] 각 기물의 이동 규칙을 구현한다. 궁성 영역은 구현하지 않는다. - -### 공통 -- [x] 이동하고자 하는 기물의 최종 목적지에 자신의 기물이 있을 때는 이동할 수 없다. -### 졸/병 - -- [x] 기물이 좌우로 한칸씩 움직일 수 있다. -- [x] 초는 위로, 한은 아래로 한칸씩 움직일 수 있다. - -### 궁 - -- [x] 기물이 상하좌우로 한칸씩 움직일 수 있다. -- [x] 궁성 영역은 고려하지 않는다. - -### 사 - -- [x] 기물이 상하좌우로 한칸씩 움직일 수 있다. -- [x] 궁성 영역은 고려하지 않는다. - -### 마 - -- [x] 직선으로 한칸, 그리고 앞서 움직였던 방향을 포함한 대각선 방향으로 한칸 움직일 수 있다. - - [x] 위로 한번, 좌상단 대각선 방향으로 한번 움직인다. - - [x] 위로 한번, 우상단 대각선 방향으로 한번 움직인다. - - [x] 아래로 한번, 좌하단 대각선 방향으로 한번 움직인다. - - [x] 아래로 한번, 우하단 대각선 방향으로 한번 움직인다. - - [x] 좌로 한번, 좌상단 대각선 방향으로 한번 움직인다. - - [x] 좌로 한번, 좌하단 대각선 방향으로 한번 움직인다. - - [x] 우로 한번, 우상단 대각선 방향으로 한번 움직인다. - - [x] 우로 한번, 우하단 대각선 방향으로 한번 움직인다. -- [x] 이동하는 도중, 어떠한 기물이라도 있다면, 이동할 수 없다. - -### 상 - -- [x] 직선으로 한칸, 그리고 앞서 움직였던 방향을 포함한 대각선 방향으로 두칸 움직일 수 있다. - - [x] 위로 한번, 좌상단 대각선 방향으로 두번 움직인다. - - [x] 위로 한번, 우상단 대각선 방향으로 두번 움직인다. - - [x] 아래로 한번, 좌하단 대각선 방향으로 두번 움직인다. - - [x] 아래로 한번, 우하단 대각선 방향으로 두번 움직인다. - - [x] 좌로 한번, 좌상단 대각선 방향으로 두번 움직인다. - - [x] 좌로 한번, 좌하단 대각선 방향으로 두번 움직인다. - - [x] 우로 한번, 우상단 대각선 방향으로 두번 움직인다. - - [x] 우로 한번, 우하단 대각선 방향으로 두번 움직인다. -- [x] 이동하는 도중, 어떠한 기물이라도 있다면, 이동할 수 없다. - - -### 차 -- [x] 직선방향으로만 움직일 수 있다. -- [x] 이동하는 도중, 어떠한 기물이라도 있다면, 이동할 수 없다. - -### 포 -- [x] 직선방향으로만 움직일 수 있다. -- [x] 이동하고자 하는 위치 사이에 기물이 하나 존재해야한다. -- [x] 사이에 있는 기물이 포여서는 안된다. -- [x] 포는 포를 잡을 수 없다. 즉 최종 목적지에 포여서도 안된다. - -

- -# 규칙 -## **1. 테스트 단위 기준** - -- 테스트는 **public 메서드 단위**로 작성한다. - - 이 때 메서드는 **한 가지 역할만 담당**하도록 만든다. - - private 메서드는 직접 테스트하지 않고 **public 메서드를 통해 간접 검증**한다. -- 테스트 코드 내부에 **조건문을 넣지 않는다.** - - 분기가 있는 경우 **경계값과 분기별 케이스를 나누어 테스트**한다. - -## **2. 테스트 제외 기준** - -- **입출력(UI)은 테스트하지 않는다. (ex. Scanner, print)** - - 다만 **입력값 검증은 테스트한다.** -- getter, 단순 객체 생성 자체는 테스트하지 않는다. -- enum은 무조건 테스트하지 않고, **의미 있는 로직이나 메서드가 있을 때만 테스트한다.** - - -## **3. 테스트가 어려울 때 대응** - -- 테스트가 어렵다면 **설계를 먼저 의심한다.** - - 메서드와 객체가 **단일 책임을 가지고 있는지 다시 점검한다.** - - 테스트가 어려웠던 이유를 기록하고, 이후 리팩터링의 근거로 삼는다. -- 랜덤 값, 시간 등 제어할 수 없는 요소는 외부에서 주입해주는 방식으로 변경한다. - - **인터페이스 추상화나 전략 분리**를 적극 사용한다. - -## **4. 책임 분리 기준** - -- 객체는 자신의 내부 상태를 외부에 공개하지 않고, **스스로 행동해야 한다.** - - 값을 꺼내 외부에서 판단하기보다, **해당 정보를 가장 잘 아는 객체에게 책임을 맡긴다.** -- “**(객체)는 (역할)로서 (행위)를 한다**”라는 문장에 대입해보고, 역할과 행위가 어색하게 섞여 있으면 책임 분리를 고려한다. -- 도메인 객체는 **도메인 규칙과 상태 관리에 집중**해야 한다. - - UI, 입출력, 프레임워크 의존성을 가지지 않도록 한다. - -## **5. 변경 범위 제한 규칙** - -- **같은 이유로 변경되는 코드는 함께 두고, 다른 이유로 변경되는 코드는 분리한다.** -- 변경 범위를 줄이기 위해 **추상화, 다형성, 캡슐화**를 고려한다. - - 검증 규칙이나 의미를 가진 값은 **Value Object**로 감싼다. - - 컬렉션에 의미와 규칙이 있다면 **일급 컬렉션**으로 다룬다. - - -## **6. 테스트와 설계의 관계** - -- **비즈니스 규칙이 변경되어 테스트가 깨지는 것은 건강한 실패**다. - - 이 경우 테스트도 함께 수정한다. -- 내부 구조만 리팩터링했는데 테스트가 깨진다면, 테스트가 **구현 세부사항에 과하게 의존하고 있는지 점검한다.** -- 테스트는 **구현이 아니라 행위**를 검증해야 한다. -- 테스트를 위해 설계를 망치지 않는다. - - 불필요한 getter, 생성자, 메서드 추가 및 테스트만을 위한 public 메서드 노출 -- TDD를 시작하기 전, 클래스 구조의 큰 틀과 시나리오 흐름 정도는 먼저 생각해본다. -- 작은 기능들을 테스트해 쌓아나가면서 하나의 큰 기능을 테스트하는 방향으로 간다. - -## 7. 상태 위치 규칙 (Single Source of Truth) - -- 하나의 상태는 **오직 한 객체만 소유한다.** 다른 객체들은 해당 상태를 **참조하거나 전달받아 사용한다.** -- 상태의 위치는 **객체 자체가 아니라 객체 간 협력 관계와 책임**을 기준으로 결정한다. - -## 8. 불변 객체 기준 - -- **가능한 모든 클래스를 불변 객체로 설계한다.** -- 내부 필드를 변경해야 할 경우 - → 기존 객체를 수정하지 않고 **새로운 불변 객체를 생성해 반환한다.** -- **변하지 않거나 변하면 안 되는 값은 반드시 불변으로 만든다.** - -## 9. 캡슐화 기준 - -- 객체 간 협력에 필요한 **메서드만 외부에 공개한다.** -- 그 외 모든 것은 객체 내부에 숨긴다. - - 객체의 **속성(필드)** - - 내부 구현 방식 - -## 10. `null` 사용 기준 - -- `null` 사용은 **최대한 지양한다.** -- 필요할 경우에는 `Optional`을 사용해 **명시적으로 감싸서 표현한다.** - -## 11. 조건문 대체 기준 (다형성 사용 시점) - -다음 상황에서는 조건문 대신 **다형성**을 고려한다. - -- 인터페이스가 존재하지만 **구체 클래스에 의존하는 조건 분기**가 있을 때 - -## 12. 역할 / 인터페이스 설계 기준 - -- **공통된 책임을 하나의 역할(인터페이스)로 묶는다.** -- **같은 질문에 다른 답을 하는 경우** → 다형성 후보로 판단한다. - - -## 13. 새 타입 추가 시 변경 범위 제한 규칙 - -- 새로운 타입이 추가될 때 **관련된 객체만 수정 가능**하도록 설계한다. - - 예: 새로운 용 타입 추가 → **행마법 관련 객체만 변경** -- 객체 자체를 수정하기보다**인터페이스 조합과 구현체 주입을 통해 확장**한다. -- 즉, - - 객체 구조는 유지하고 - - **새 구현체를 추가하는 방식으로 확장한다.** - -

- -# 미션 중 기록 -- 상태 위치를 결정할 때 고민한 순간 1회 - - 기물의 위치는 기물이 제일 잘 알지 않을까라고 판단을해서, 원래는 기물이 스스로 판단하면 된다고 생각했습니다;. - - 하지만 움직임을 파악할 때 다른 기물의 위치도 전부 파악해야하므로, 보드가 위치를 파악하는 것이 맞다고 판단해서 수정하였습니다. -- 불변/캡슐화를 적용한 코드 1곳 - - 위치 정보는 불변이라고 생각이 들어, 이를 불변객체로 적용하였습니다. - - 또한 기물의 정보도, 실행 중에는 실행규칙이 절대 변경되지 않으므로 불변객체로 적용하였습니다. -- 규칙 적용으로 변경한 설계 1곳 - - 12번 규칙 역할/인터페이스 설계기준으로 인해, 조건문으로 판별했었던 코드를 전략패턴으로 수정해서 진행했습니다. -- 조건문을 다형성으로 대체한 코드 1곳 - - 기물들에 대해서 모두 다르게 움직이기 때문에, 기물의 종류를 파악하기 위해 조건문으로 판별하자고 생각했습니다. - - 이를 이후, MoveStrategy로 대체를 하여 진행하였습니다. -- 인터페이스/추상 클래스를 도입한 이유 - - 각각의 기물에 대해 서로 다른 규칙이 적용되는데, 모든 기물의 위치 정보는 보드가 기록하고 있었습니다. - - 보드가 기물의 규칙을 모두 알아야하는 문제점이 있었으며, 규칙이 변경될 때 마다 고쳐야하는 범위가 여기저기 흩어져 있었습니다. - - 각각의 기물에 움직임 규칙을 구현하고, 보드는 이를 몰라도 움직일 수 있는지, 없는지만 판별 할 수 있도록 인터페이스를 고려하였습니다. -- 새 기물 추가 시 변경 범위 테스트 (가상으로) - - 그 기물에 대한 전략 클래스를 구현합니다. - - 보드 초기화 때 새 기물의 위치를 추가합니다. - - 보드 자체에서는 변경되는 사항은 없습니다. +- [x] 보드는 9행 * 10열 크기이다. (x축은 가로, y축은 세로이다.) + - [x] x좌표는 0 이상 8 이하의 범위를 가진다. (총 9칸) + - [x] y좌표는 0 이상 9 이하의 범위를 가진다. (총 10칸) + - [x] 보드의 범위를 벗어난 좌표에 접근할 경우, IllegalArgumentException을 발생시킨다. +- [x] 보드의 좌측 하단을 (0, 0)으로 정의한다. + +-[ ] 보드를 초기화한다. + - [ ] 상차림에 맞도록 기물을 배치한다. + - [ ] 왼상차림 : 상마상마 + - [ ] 오른상차림 : 마상마상 + - [ ] 바깥상차림 : 마상상마 + - [ ] 안상차림 : 상마마상 diff --git a/src/main/java/Application.java b/src/main/java/Application.java deleted file mode 100644 index 7b8239347b..0000000000 --- a/src/main/java/Application.java +++ /dev/null @@ -1,13 +0,0 @@ -import controller.Controller; -import view.InputView; -import view.OutputView; - -public class Application { - public static void main(String[] args) { - InputView inputView = new InputView(); - OutputView outputView = new OutputView(); - - Controller controller = new Controller(inputView, outputView); - controller.run(); - } -} diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java deleted file mode 100644 index 0659c51d2f..0000000000 --- a/src/main/java/controller/Controller.java +++ /dev/null @@ -1,47 +0,0 @@ -package controller; - -import domain.board.Board; -import domain.board.BoardFactory; -import domain.board.InitializeSetting; -import domain.board.Position; -import view.InputView; -import view.OutputView; - -public class Controller { - private final InputView inputView; - private final OutputView outputView; - - public Controller(InputView inputView, OutputView outputView) { - this.inputView = inputView; - this.outputView = outputView; - } - - public void run() { - try { - InitializeSetting choSetting = inputView.readInitialSetting("초(CHO)"); - InitializeSetting hanSetting = inputView.readInitialSetting("한(HAN)"); - - Board board = BoardFactory.createBoard(choSetting, hanSetting); - - play(board); - } catch (Exception e) { - outputView.printError(e); - } - } - - private void play(Board board) { - while (true) { - try { - outputView.printBoard(board); - Position[] positions = inputView.readMoveCommand(); - - Position from = positions[0]; - Position to = positions[1]; - - board.move(from, to); - } catch (Exception e) { - outputView.printError(e); - } - } - } -} diff --git a/src/main/java/domain/Direction.java b/src/main/java/domain/Direction.java deleted file mode 100644 index cdb76b46c0..0000000000 --- a/src/main/java/domain/Direction.java +++ /dev/null @@ -1,24 +0,0 @@ -package domain; - -public enum Direction { - UP(0, 1), - DOWN(0, -1), - LEFT(-1, 0), - RIGHT(1, 0); - - private final int dx; - private final int dy; - - Direction(int dx, int dy) { - this.dx = dx; - this.dy = dy; - } - - public int getDx() { - return dx; - } - - public int getDy() { - return dy; - } -} diff --git a/src/main/java/domain/Path.java b/src/main/java/domain/Path.java deleted file mode 100644 index d6a996f755..0000000000 --- a/src/main/java/domain/Path.java +++ /dev/null @@ -1,7 +0,0 @@ -package domain; - -import domain.board.Position; -import domain.piece.Piece; - -public record Path(Position position, Piece piece) { -} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java new file mode 100644 index 0000000000..e8fc82c394 --- /dev/null +++ b/src/main/java/domain/Position.java @@ -0,0 +1,32 @@ +package domain; + +public class Position { + private static final int MIN_POSITION = 0; + private static final int MAX_COLUMN = 8; + private static final int MAX_ROW = 9; + + private final int column; + private final int row; + + public Position(int column, int row) { + validateColumn(column); + validateRow(row); + + this.column = column; + this.row = row; + } + + private void validateColumn(int column) { + if (column < 0 || column > MAX_COLUMN) { + throw new IllegalArgumentException( + String.format("[ERROR] x좌표는 %d에서 %d 사이입니다.", MIN_POSITION, MAX_COLUMN)); + } + } + + private void validateRow(int row) { + if (row < 0 || row > MAX_ROW) { + throw new IllegalArgumentException( + String.format("[ERROR] y좌표는 %d에서 %d 사이입니다.", MIN_POSITION, MAX_ROW)); + } + } +} diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java deleted file mode 100644 index d318c1d177..0000000000 --- a/src/main/java/domain/board/Board.java +++ /dev/null @@ -1,45 +0,0 @@ -package domain.board; - -import domain.Path; -import domain.piece.Piece; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class Board { - private final Map pieces; - - public Board(Map pieces) { - this.pieces = pieces; - } - - public Piece getPiece(Position position) { - return pieces.get(position); - } - - public void move(Position from, Position to) { - Piece fromPiece = pieces.get(from); - Piece toPiece = pieces.get(to); - List pathPositions = fromPiece.getPathPositions(from, to); - List path = getPath(pathPositions); - fromPiece.canMove(path, toPiece); - - if (toPiece != null && fromPiece.isSameTeam(toPiece)) { - throw new IllegalStateException("같은 팀의 기물을 잡을 수 없습니다."); - } - - Piece remove = pieces.remove(from); - pieces.put(to, remove); - } - - public List getPath(List positions) { - List paths = new ArrayList<>(); - for (Position position : positions) { - if (pieces.containsKey(position)) { - paths.add(new Path(position, pieces.get(position))); - } - } - return paths; - } -} diff --git a/src/main/java/domain/board/BoardFactory.java b/src/main/java/domain/board/BoardFactory.java deleted file mode 100644 index 5f256aa1af..0000000000 --- a/src/main/java/domain/board/BoardFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -package domain.board; - - -import domain.piece.CannonStrategy; -import domain.piece.ChariotStrategy; -import domain.piece.ChoSoldierStrategy; -import domain.piece.ElephantStrategy; -import domain.piece.GeneralStrategy; -import domain.piece.GuardStrategy; -import domain.piece.HanSoldierStrategy; -import domain.piece.HorseStrategy; -import domain.piece.Piece; -import domain.piece.PieceType; -import domain.piece.Team; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class BoardFactory { - private static final List SOLDIER_COLUMNS = List.of(0, 2, 4, 6, 8); - private static final List CHARIOT_COLUMNS = List.of(0, 8); - private static final List GUARD_COLUMNS = List.of(3, 5); - private static final List CANNON_COLUMNS = List.of(1, 7); - - private BoardFactory() { - } - - public static Board createBoard(InitializeSetting choInitialSetting, InitializeSetting hanInitialSetting) { - Map pieces = new HashMap<>(); - - - for (Integer soliderColumns : SOLDIER_COLUMNS) { - pieces.put(new Position(soliderColumns, 3), new Piece(PieceType.SOLDIER, Team.CHO, new ChoSoldierStrategy())); - pieces.put(new Position(soliderColumns, 6), new Piece(PieceType.SOLDIER, Team.HAN, new HanSoldierStrategy())); - } - - for (Integer chariotColumn : CHARIOT_COLUMNS) { - pieces.put(new Position(chariotColumn, 0), new Piece(PieceType.CHARIOT, Team.CHO, new ChariotStrategy())); - pieces.put(new Position(chariotColumn, 9), new Piece(PieceType.CHARIOT, Team.HAN, new ChariotStrategy())); - - } - - for (Integer guardColumn : GUARD_COLUMNS) { - pieces.put(new Position(guardColumn, 0), new Piece(PieceType.GUARD, Team.CHO, new GuardStrategy())); - pieces.put(new Position(guardColumn, 9), new Piece(PieceType.GUARD, Team.HAN, new GuardStrategy())); - - } - - for (Integer cannonColumn : CANNON_COLUMNS) { - pieces.put(new Position(cannonColumn, 2), new Piece(PieceType.CANNON, Team.CHO, new CannonStrategy())); - pieces.put(new Position(cannonColumn, 7), new Piece(PieceType.CANNON, Team.HAN, new CannonStrategy())); - - } - - pieces.put(new Position(4, 1), new Piece(PieceType.GENERAL, Team.CHO, new GeneralStrategy())); - pieces.put(new Position(4, 8), new Piece(PieceType.GENERAL, Team.HAN, new GeneralStrategy())); - - List choSetting = choInitialSetting.getInitialSetting(); - pieces.put(new Position(1, 0), createPiece(choSetting.get(0), Team.CHO)); - pieces.put(new Position(2, 0), createPiece(choSetting.get(1), Team.CHO)); - pieces.put(new Position(6, 0), createPiece(choSetting.get(2), Team.CHO)); - pieces.put(new Position(7, 0), createPiece(choSetting.get(3), Team.CHO)); - - List hanSetting = hanInitialSetting.getInitialSetting(); - pieces.put(new Position(1, 9), createPiece(hanSetting.get(0), Team.HAN)); - pieces.put(new Position(2, 9), createPiece(hanSetting.get(1), Team.HAN)); - pieces.put(new Position(6, 9), createPiece(hanSetting.get(2), Team.HAN)); - pieces.put(new Position(7, 9), createPiece(hanSetting.get(3), Team.HAN)); - - - return new Board(pieces); - } - - private static Piece createPiece(PieceType pieceType, Team team) { - if (pieceType == PieceType.ELEPHANT) { - return new Piece(pieceType, team, new ElephantStrategy()); - } - return new Piece(pieceType, team, new HorseStrategy()); - } -} diff --git a/src/main/java/domain/board/InitializeSetting.java b/src/main/java/domain/board/InitializeSetting.java deleted file mode 100644 index 812216f4aa..0000000000 --- a/src/main/java/domain/board/InitializeSetting.java +++ /dev/null @@ -1,22 +0,0 @@ -package domain.board; - -import domain.piece.PieceType; - -import java.util.List; - -public enum InitializeSetting { - LEFT_ELEPHANT_SETTING(List.of(PieceType.ELEPHANT, PieceType.HORSE, PieceType.ELEPHANT, PieceType.HORSE)), - RIGHT_ELEPHANT_SETTING(List.of(PieceType.HORSE, PieceType.ELEPHANT, PieceType.HORSE, PieceType.ELEPHANT)), - INNER_ELEPHANT_SETTING(List.of(PieceType.HORSE, PieceType.ELEPHANT, PieceType.ELEPHANT, PieceType.HORSE)), - OUTER_ELEPHANT_SETTING(List.of(PieceType.ELEPHANT, PieceType.HORSE, PieceType.HORSE, PieceType.ELEPHANT)); - - private final List initialSetting; - - InitializeSetting(List initialSetting) { - this.initialSetting = initialSetting; - } - - public List getInitialSetting() { - return initialSetting; - } -} diff --git a/src/main/java/domain/board/Position.java b/src/main/java/domain/board/Position.java deleted file mode 100644 index 0dd7699b51..0000000000 --- a/src/main/java/domain/board/Position.java +++ /dev/null @@ -1,56 +0,0 @@ -package domain.board; - -import domain.Direction; - -import java.util.Objects; - -public class Position { - private static final int MIN_RANGE = 0; - private static final int MAX_WIDTH_RANGE = 8; - private static final int MIN_HEIGHT_RANGE = 9; - - private final int x; - private final int y; - - public Position(int x, int y) { - validateRange(x, y); - - this.x = x; - this.y = y; - } - - private void validateRange(int x, int y) { - if (x < MIN_RANGE || x > MAX_WIDTH_RANGE) { - throw new IllegalArgumentException("좌표 값이 올바르지 않습니다."); - } - - if (y < MIN_RANGE || y > MIN_HEIGHT_RANGE) { - throw new IllegalArgumentException("좌표 값이 올바르지 않습니다."); - } - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof Position position)) { - return false; - } - return x == position.x && y == position.y; - } - - @Override - public int hashCode() { - return Objects.hash(x, y); - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public Position next(Direction direction) { - return new Position(x + direction.getDx(), y + direction.getDy()); - } -} diff --git a/src/main/java/domain/piece/CannonStrategy.java b/src/main/java/domain/piece/CannonStrategy.java deleted file mode 100644 index af8a3842ad..0000000000 --- a/src/main/java/domain/piece/CannonStrategy.java +++ /dev/null @@ -1,74 +0,0 @@ -package domain.piece; - -import domain.Direction; -import domain.Path; -import domain.board.Position; - -import java.util.ArrayList; -import java.util.List; - -public class CannonStrategy implements MoveStrategy { - @Override - public List getPathPositions(Position from, Position to) { - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))) { - throw new IllegalArgumentException("포를 해당 위치로 옮길 수 없습니다."); - } - - Direction mainDirection; - - int distance; - if (dx == 0) { - mainDirection = decideYDirection(dy); - distance = Math.abs(dy); - } else { - mainDirection = decideXDirection(dx); - distance = Math.abs(dx); - } - - Position step = from; - - List route = new ArrayList<>(); - for (int i = 0; i < distance - 1; i++) { - step = step.next(mainDirection); - route.add(step); - } - - return route; - } - - private Direction decideXDirection(int dx) { - if (dx > 0) { - return Direction.RIGHT; - } - return Direction.LEFT; - } - - private Direction decideYDirection(int dy) { - if (dy > 0) { - return Direction.UP; - } - return Direction.DOWN; - } - - - @Override - public void canMove(List paths, Piece to) { - if (paths.size() != 1) { - throw new IllegalStateException("포는 한 기물만 뛰어 넘을 수 있습니다."); - } - - Piece piece = paths.getFirst().piece(); - - - if (piece.pieceType() == PieceType.CANNON) { - throw new IllegalStateException("포는 포를 뛰어 넘을 수 있습니다."); - } - - if (to != null && to.pieceType() == PieceType.CANNON) { - throw new IllegalStateException("포를 잡을 수 없습니다"); - } - } -} diff --git a/src/main/java/domain/piece/ChariotStrategy.java b/src/main/java/domain/piece/ChariotStrategy.java deleted file mode 100644 index 237c422a87..0000000000 --- a/src/main/java/domain/piece/ChariotStrategy.java +++ /dev/null @@ -1,62 +0,0 @@ -package domain.piece; - -import domain.Direction; -import domain.Path; -import domain.board.Position; - -import java.util.ArrayList; -import java.util.List; - -public class ChariotStrategy implements MoveStrategy { - @Override - public List getPathPositions(Position from, Position to) { - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - if (!((dx == 0 && dy != 0) || (dx != 0 && dy == 0))) { - throw new IllegalArgumentException("차를 해당 위치로 옮길 수 없습니다."); - } - - Direction mainDirection; - int distance; - if (dx == 0) { - mainDirection = decideYDirection(dy); - distance = Math.abs(dy); - } else { - mainDirection = decideXDirection(dx); - distance = Math.abs(dx); - } - - Position step = from; - - List route = new ArrayList<>(); - for (int i = 0; i < distance - 1; i++) { - step = step.next(mainDirection); - route.add(step); - } - - return route; - } - - private Direction decideXDirection(int dx) { - if (dx > 0) { - return Direction.RIGHT; - } - return Direction.LEFT; - } - - private Direction decideYDirection(int dy) { - if (dy > 0) { - return Direction.UP; - } - return Direction.DOWN; - } - - - @Override - public void canMove(List paths, Piece to) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/ChoSoldierStrategy.java b/src/main/java/domain/piece/ChoSoldierStrategy.java deleted file mode 100644 index 9074fd1652..0000000000 --- a/src/main/java/domain/piece/ChoSoldierStrategy.java +++ /dev/null @@ -1,33 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public class ChoSoldierStrategy implements MoveStrategy { - - @Override - public List getPathPositions(Position from, Position to) { - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - int straight = 1; - - boolean isMoveStraight = dx == 0 && dy == straight; - boolean isMoveLeft = dx == -1 && dy == 0; - boolean isMoveRight = dx == 1 && dy == 0; - - if (!(isMoveLeft || isMoveRight || isMoveStraight)) { - throw new IllegalArgumentException("움직일 수 없는 위치입니다."); - } - return List.of(); - } - - @Override - public void canMove(List paths, Piece to) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/ElephantStrategy.java b/src/main/java/domain/piece/ElephantStrategy.java deleted file mode 100644 index 114a84e40c..0000000000 --- a/src/main/java/domain/piece/ElephantStrategy.java +++ /dev/null @@ -1,59 +0,0 @@ -package domain.piece; - -import domain.Direction; -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public class ElephantStrategy implements MoveStrategy { - @Override - public List getPathPositions(Position from, Position to) { - - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - if (!((Math.abs(dx) == 3 && Math.abs(dy) == 2) || (Math.abs(dx) == 2 && Math.abs(dy) == 3))) { - throw new IllegalArgumentException("상이 이동할 수 없습니다."); - } - - Direction xDirection = decideXDirection(dx); - Direction yDirection = decideYDirection(dy); - - Direction mainDirection; - Direction subDirection; - if (Math.abs(dx) > Math.abs(dy)) { - mainDirection = xDirection; - subDirection = yDirection; - } else { - mainDirection = yDirection; - subDirection = xDirection; - } - - Position step1 = from.next(mainDirection); - Position step2 = step1.next(mainDirection).next(subDirection); - - return List.of(step1, step2); - } - - private Direction decideXDirection(int dx) { - if (dx > 0) { - return Direction.RIGHT; - } - return Direction.LEFT; - } - - private Direction decideYDirection(int dy) { - if (dy > 0) { - return Direction.UP; - } - return Direction.DOWN; - } - - @Override - public void canMove(List paths, Piece to) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/GeneralStrategy.java b/src/main/java/domain/piece/GeneralStrategy.java deleted file mode 100644 index df6a3425f4..0000000000 --- a/src/main/java/domain/piece/GeneralStrategy.java +++ /dev/null @@ -1,31 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public class GeneralStrategy implements MoveStrategy { - @Override - public List getPathPositions(Position from, Position to) { - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - boolean isMoveUp = dx == 0 && dy == 1; - boolean isMoveLeft = dx == -1 && dy == 0; - boolean isMoveRight = dx == 1 && dy == 0; - boolean isMoveDown = dx == 0 && dy == -1; - - if (!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { - throw new IllegalArgumentException("움직일 수 없는 위치입니다."); - } - return List.of(); - } - - @Override - public void canMove(List paths, Piece toa) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/GuardStrategy.java b/src/main/java/domain/piece/GuardStrategy.java deleted file mode 100644 index 063df8517f..0000000000 --- a/src/main/java/domain/piece/GuardStrategy.java +++ /dev/null @@ -1,32 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public class GuardStrategy implements MoveStrategy { - @Override - public List getPathPositions(Position from, Position to) { - - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - boolean isMoveUp = dx == 0 && dy == 1; - boolean isMoveLeft = dx == -1 && dy == 0; - boolean isMoveRight = dx == 1 && dy == 0; - boolean isMoveDown = dx == 0 && dy == -1; - - if (!(isMoveLeft || isMoveRight || isMoveUp || isMoveDown)) { - throw new IllegalArgumentException("움직일 수 없는 위치입니다."); - } - return List.of(); - } - - @Override - public void canMove(List paths, Piece to) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/HanSoldierStrategy.java b/src/main/java/domain/piece/HanSoldierStrategy.java deleted file mode 100644 index 070200d505..0000000000 --- a/src/main/java/domain/piece/HanSoldierStrategy.java +++ /dev/null @@ -1,33 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public class HanSoldierStrategy implements MoveStrategy { - - @Override - public List getPathPositions(Position from, Position to) { - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - int straight = -1; - - boolean isMoveStraight = dx == 0 && dy == straight; - boolean isMoveLeft = dx == -1 && dy == 0; - boolean isMoveRight = dx == 1 && dy == 0; - - if (!(isMoveLeft || isMoveRight || isMoveStraight)) { - throw new IllegalArgumentException("움직일 수 없는 위치입니다."); - } - return List.of(); - } - - @Override - public void canMove(List paths, Piece to) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/HorseStrategy.java b/src/main/java/domain/piece/HorseStrategy.java deleted file mode 100644 index 8aadfa559b..0000000000 --- a/src/main/java/domain/piece/HorseStrategy.java +++ /dev/null @@ -1,59 +0,0 @@ -package domain.piece; - -import domain.Direction; -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public class HorseStrategy implements MoveStrategy { - @Override - public List getPathPositions(Position from, Position to) { - - int dx = to.getX() - from.getX(); - int dy = to.getY() - from.getY(); - - if (!((Math.abs(dx) == 2 && Math.abs(dy) == 1) || (Math.abs(dx) == 1 && Math.abs(dy) == 2))) { - throw new IllegalArgumentException("마가 이동할 수 없습니다."); - } - - Direction xDirection = decideXDirection(dx); - Direction yDirection = decideYDirection(dy); - - Direction mainDirection; - Direction subDirection; - if (Math.abs(dx) > Math.abs(dy)) { - mainDirection = xDirection; - subDirection = yDirection; - } else { - mainDirection = yDirection; - subDirection = xDirection; - } - - Position step1 = from.next(mainDirection); - - - return List.of(step1); - } - - private Direction decideXDirection(int dx) { - if (dx > 0) { - return Direction.RIGHT; - } - return Direction.LEFT; - } - - private Direction decideYDirection(int dy) { - if (dy > 0) { - return Direction.UP; - } - return Direction.DOWN; - } - - @Override - public void canMove(List paths, Piece to) { - if (!paths.isEmpty()) { - throw new IllegalArgumentException("이동 경로에 기물이 존재하면 이동할 수 없습니다."); - } - } -} diff --git a/src/main/java/domain/piece/MoveStrategy.java b/src/main/java/domain/piece/MoveStrategy.java deleted file mode 100644 index 5d85e016a8..0000000000 --- a/src/main/java/domain/piece/MoveStrategy.java +++ /dev/null @@ -1,15 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; - -import java.util.List; - -public interface MoveStrategy { - // piece가 from에서 해당 도착지 to로 도착할 수 있는지 없다면 예외를 던진다 - // from에서 to까지의 경로 Position을 반환 - List getPathPositions(Position from, Position to); - - // 기물 각각의 이동 로직(각각의 이동 로직은 전략으로 주입) - void canMove(List paths, Piece to); -} diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java deleted file mode 100644 index 2484d01abc..0000000000 --- a/src/main/java/domain/piece/Piece.java +++ /dev/null @@ -1,33 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; - -import java.util.List; -import java.util.Objects; - -public record Piece(PieceType pieceType, Team team, MoveStrategy moveStrategy) { - - public List getPathPositions(Position from, Position to) { - return moveStrategy.getPathPositions(from, to); - } - - public void canMove(List paths, Piece to) { - moveStrategy.canMove(paths, to); - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof Piece piece)) return false; - return team == piece.team && pieceType == piece.pieceType; - } - - @Override - public int hashCode() { - return Objects.hash(pieceType, team); - } - - public boolean isSameTeam(Piece another) { - return another.team == team; - } -} diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java deleted file mode 100644 index 1ef8954a54..0000000000 --- a/src/main/java/domain/piece/PieceType.java +++ /dev/null @@ -1,11 +0,0 @@ -package domain.piece; - -public enum PieceType { - GENERAL, - CHARIOT, - CANNON, - HORSE, - ELEPHANT, - GUARD, - SOLDIER -} diff --git a/src/main/java/domain/piece/Team.java b/src/main/java/domain/piece/Team.java deleted file mode 100644 index 2652d94840..0000000000 --- a/src/main/java/domain/piece/Team.java +++ /dev/null @@ -1,5 +0,0 @@ -package domain.piece; - -public enum Team { - CHO, HAN -} diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java deleted file mode 100644 index 2e6e488a40..0000000000 --- a/src/main/java/view/InputView.java +++ /dev/null @@ -1,48 +0,0 @@ -package view; - -import domain.board.InitializeSetting; -import domain.board.Position; - -import java.util.Scanner; - -public class InputView { - private final Scanner scanner = new Scanner(System.in); - - public InitializeSetting readInitialSetting(String teamName) { - System.out.println("===" + teamName + " 진영 상차림을 선택하세요 ==="); - System.out.println("1. 왼상차림 (상마상마)"); - System.out.println("2. 오른상차림 (마상마상)"); - System.out.println("3. 안상차림 (마상상마)"); - System.out.println("4. 바깥상차림 (상마마상)"); - System.out.print("선택: "); - - int choice = Integer.parseInt(scanner.nextLine().trim()); - return switch (choice) { - case 1 -> InitializeSetting.LEFT_ELEPHANT_SETTING; - case 2 -> InitializeSetting.RIGHT_ELEPHANT_SETTING; - case 3 -> InitializeSetting.INNER_ELEPHANT_SETTING; - case 4 -> InitializeSetting.OUTER_ELEPHANT_SETTING; - default -> throw new IllegalArgumentException("잘못된 선택입니다."); - }; - } - - public Position[] readMoveCommand() { - System.out.println("\n이동할 기물의 시작 좌표와 도착 좌표를 입력하세요. (예: 0,0 1,0)"); - System.out.print("입력: "); - String input = scanner.nextLine().trim(); - String[] parts = input.split(" "); - - if (parts.length != 2) { - throw new IllegalArgumentException("올바른 형식이 아닙니다. (예: 0,0 1,0)"); - } - - return new Position[]{parsePosition(parts[0]), parsePosition(parts[1])}; - } - - private Position parsePosition(String positionStr) { - String[] coords = positionStr.split(","); - int x = Integer.parseInt(coords[0].trim()); - int y = Integer.parseInt(coords[1].trim()); - return new Position(x, y); - } -} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java deleted file mode 100644 index c6c232fbf8..0000000000 --- a/src/main/java/view/OutputView.java +++ /dev/null @@ -1,46 +0,0 @@ -package view; - -import domain.board.Board; -import domain.board.Position; -import domain.piece.Piece; -import domain.piece.Team; - -public class OutputView { - - public void printBoard(Board board) { - System.out.println("\n 0 1 2 3 4 5 6 7 8 (X)"); - for (int y = 9; y >= 0; y--) { - System.out.print(y + " "); - for (int x = 0; x <= 8; x++) { - Position currentPosition = new Position(x, y); - Piece piece = board.getPiece(currentPosition); - System.out.print(getPieceSymbol(piece) + " "); - } - System.out.println(); - } - System.out.println("(Y)\n"); - } - - public void printError(Exception e) { - System.out.println("[ERROR] " + e.getMessage()); - } - - private String getPieceSymbol(Piece piece) { - if (piece == null) { - return " . "; - } - - String teamPrefix = piece.team() == Team.CHO ? "초" : "한"; - String typeName = switch (piece.pieceType()) { - case GENERAL -> "장"; - case CHARIOT -> "차"; - case CANNON -> "포"; - case HORSE -> "마"; - case ELEPHANT -> "상"; - case GUARD -> "사"; - case SOLDIER -> piece.team() == Team.CHO ? "졸" : "병"; - }; - - return teamPrefix + typeName; - } -} diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java new file mode 100644 index 0000000000..d468d6ea11 --- /dev/null +++ b/src/test/java/domain/PositionTest.java @@ -0,0 +1,37 @@ +package domain; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + + +class PositionTest { + + @Nested + class 좌표_범위_검증_테스트 { + @Test + void x좌표가_0_미만일_경우_예외를_던진다() { + Assertions.assertThatThrownBy(() -> new Position(9, 2)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void x좌표가_8을_초과할_경우_예외를_던진다() { + Assertions.assertThatThrownBy(() -> new Position(-1, 2)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void y좌표가_0_미만일_경우_예외를_던진다() { + Assertions.assertThatThrownBy(() -> new Position(3, -1)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void y좌표가_9를_초과할_경우_예외를_던진다() { + Assertions.assertThatThrownBy(() -> new Position(2, 10)) + .isInstanceOf(IllegalArgumentException.class); + } + } + +} diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java deleted file mode 100644 index ef45dbc644..0000000000 --- a/src/test/java/domain/board/BoardTest.java +++ /dev/null @@ -1,108 +0,0 @@ -package domain.board; - -import domain.Path; -import domain.piece.*; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import java.util.List; -import java.util.stream.Stream; - -import static org.assertj.core.api.Assertions.assertThat; - -public class BoardTest { - private Board board; - - @BeforeEach - void setUp() { - board = BoardFactory.createBoard(InitializeSetting.RIGHT_ELEPHANT_SETTING, InitializeSetting.RIGHT_ELEPHANT_SETTING); - } - - @Nested - class 기물_위치_테스트 { - - @ParameterizedTest - @MethodSource("soldierProvider") - void 졸을_올바른_위치에_초기화한다(Position position) { - Piece piece = board.getPiece(position); - assertThat(piece.pieceType()).isEqualTo(PieceType.SOLDIER); - } - - static Stream soldierProvider() { - return Stream.of( - Arguments.of(new Position(0, 3)), - Arguments.of(new Position(2, 3)), - Arguments.of(new Position(4, 3)), - Arguments.of(new Position(6, 3)), - Arguments.of(new Position(8, 3)) - ); - } - - @ParameterizedTest - @MethodSource("chariotProvider") - void 차를_올바른_위치에_초기화한다(Position position) { - Piece piece = board.getPiece(position); - assertThat(piece.pieceType()).isEqualTo(PieceType.CHARIOT); - } - - static Stream chariotProvider() { - return Stream.of( - Arguments.of(new Position(0, 0)), - Arguments.of(new Position(8, 0)) - ); - } - - @ParameterizedTest - @MethodSource("guardProvider") - void 사를_올바른_위치에_초기화한다(Position position) { - Piece piece = board.getPiece(position); - assertThat(piece.pieceType()).isEqualTo(PieceType.GUARD); - } - - static Stream guardProvider() { - return Stream.of( - Arguments.of(new Position(3, 0)), - Arguments.of(new Position(5, 0)) - ); - } - - - @Test - void 궁을_올바른_위치에_초기화한다() { - Piece piece = board.getPiece(new Position(4, 1)); - assertThat(piece.pieceType()).isEqualTo(PieceType.GENERAL); - } - - - @ParameterizedTest - @MethodSource("cannonProvider") - void 포를_올바른_위치에_초기화한다(Position position) { - Piece piece = board.getPiece(position); - assertThat(piece.pieceType()).isEqualTo(PieceType.CANNON); - } - - static Stream cannonProvider() { - return Stream.of( - Arguments.of(new Position(1, 2)), - Arguments.of(new Position(7, 2)) - ); - } - } - - - @Test - void 기물이_이동할_경로에_대한_다른_기물의_위치_정보를_반환한다() { - List positions = List.of(new Position(1, 0), new Position(2, 0)); - List path = board.getPath(positions); - - assertThat(path).isEqualTo(List.of(new Path( - new Position(1, 0), new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy())), - new Path(new Position(2, 0), new Piece(PieceType.ELEPHANT, Team.CHO, new ElephantStrategy())) - )); - } -} diff --git a/src/test/java/domain/board/PositionTest.java b/src/test/java/domain/board/PositionTest.java deleted file mode 100644 index dbc1160b58..0000000000 --- a/src/test/java/domain/board/PositionTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package domain.board; - -import static org.assertj.core.api.Assertions.*; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -class PositionTest { - @Test - void 장기판의_좌표의_범위는_가로_9칸_세로_10칸이다() { - Position position = new Position(2, 7); - - assertThat(position).isInstanceOf(Position.class); - } - - @Test - void 장기판의_가로_범위를_벗어날_경우_예외를_뱐환한다() { - Assertions.assertThrows(IllegalArgumentException.class, () -> - new Position(9, 7)); - } - - @Test - void 장기판의_세로_범위를_벗어날_경우_예외를_뱐환한다() { - Assertions.assertThrows(IllegalArgumentException.class, () -> - new Position(7, 11)); - } -} diff --git a/src/test/java/domain/piece/CannonStrategyTest.java b/src/test/java/domain/piece/CannonStrategyTest.java deleted file mode 100644 index b9ca552153..0000000000 --- a/src/test/java/domain/piece/CannonStrategyTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package domain.piece; - -import domain.Path; -import domain.board.Position; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; - - -class CannonStrategyTest { - - Piece piece; - - @BeforeEach - void setUp() { - piece = new Piece(PieceType.CANNON, Team.CHO, new CannonStrategy()); - } - - @Test - void 포는_기물이_사이에_하나의_기물이_있으면_정상적으로_움직일_수_있다() { - List paths = List.of(new Path(new Position(3, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy()))); - - assertDoesNotThrow(() -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy()))); - } - - - @Test - void 포는_기물이_사이에_하나라도_존재하지_않으면_예외를_반환한다() { - List paths = List.of(); - - assertThrows(IllegalStateException.class, - () -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) - ); - } - - @Test - void 포는_기물이_사이에_두개_이상_존재하면_예외를_반환한다() { - List paths = List.of( - new Path(new Position(3, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())), - new Path(new Position(6, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) - ); - - - assertThrows(IllegalStateException.class, - () -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) - ); - } - - @Test - void 포는_기물이_사이에_포가_존재하면_예외를_반환한다() { - List paths = List.of( - new Path(new Position(3, 0), new Piece(PieceType.CANNON, Team.HAN, new CannonStrategy())) - ); - - assertThrows(IllegalStateException.class, - () -> piece.canMove(paths, new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) - ); - } - - @Test - void 포는_목적지에_포가_존재하면_예외를_반환한다() { - List paths = List.of( - new Path(new Position(3, 0), new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy())) - ); - - assertThrows(IllegalStateException.class, - () -> piece.canMove(paths, new Piece(PieceType.CANNON, Team.HAN, new CannonStrategy())) - ); - } - -} diff --git a/src/test/java/domain/piece/CannonTest.java b/src/test/java/domain/piece/CannonTest.java deleted file mode 100644 index a0faf6f559..0000000000 --- a/src/test/java/domain/piece/CannonTest.java +++ /dev/null @@ -1,67 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class CannonTest { - - private Piece cannon; - - @BeforeEach - void setUp() { - cannon = new Piece(PieceType.CANNON, Team.CHO, new CannonStrategy()); - } - - @Test - void 포는_왼쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(2, 5); - - List pathPositions = cannon.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5))); - } - - @Test - void 포는_오른쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(8, 5); - - List pathPositions = cannon.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5))); - } - - - @Test - void 포는_위쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(5, 7); - - List pathPositions = cannon.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); - } - - - @Test - void 포는_아래쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(5, 0); - - List pathPositions = cannon.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of( - new Position(5, 4), new Position(5, 3), new Position(5, 2), new Position(5, 1))); - } - -} diff --git a/src/test/java/domain/piece/ChariotTest.java b/src/test/java/domain/piece/ChariotTest.java deleted file mode 100644 index 194d3c161c..0000000000 --- a/src/test/java/domain/piece/ChariotTest.java +++ /dev/null @@ -1,68 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class ChariotTest { - - private Piece chariot; - - @BeforeEach - void setUp() { - chariot = new Piece(PieceType.CHARIOT, Team.CHO, new ChariotStrategy()); - } - - @Test - void 차는_왼쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(2, 5); - - List pathPositions = chariot.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 5))); - } - - @Test - void 차는_오른쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(8, 5); - - List pathPositions = chariot.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 5))); - } - - - @Test - void 차는_위쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(5, 7); - - List pathPositions = chariot.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); - } - - - @Test - void 차는_아래쪽_직선으로_가는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(5, 0); - - List pathPositions = chariot.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of( - new Position(5, 4), new Position(5, 3), new Position(5, 2), new Position(5, 1))); - } - - -} diff --git a/src/test/java/domain/piece/ElephantTest.java b/src/test/java/domain/piece/ElephantTest.java deleted file mode 100644 index b6679e95db..0000000000 --- a/src/test/java/domain/piece/ElephantTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class ElephantTest { - private Piece elephant; - - @BeforeEach - void setUp() { - elephant = new Piece(PieceType.ELEPHANT, Team.CHO, new ElephantStrategy()); - } - - @Test - void 상은_위로_세칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(3, 8); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(4, 7))); - } - - @Test - void 상은_위로_세칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(7, 8); - - List pathPositions = elephant.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6), new Position(6, 7))); - } - - - @Test - void 마는_위로_두칸_왼쪽으로_세칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(2, 7); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 6))); - } - - - @Test - void 마는_아래로_두칸_왼쪽으로_세칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(2, 3); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5), new Position(3, 4))); - } - - - @Test - void 마는_아래로_세칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(3, 2); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(4, 3))); - } - - - @Test - void 마는_아래로_세칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(7, 2); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4), new Position(6, 3))); - } - - - @Test - void 상은_위로_두칸_오른쪽으로_세칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(8, 7); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); - } - - - @Test - void 상은_아래로_두칸_오른쪽으로_세칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(8, 7); - - List pathPositions = elephant.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5), new Position(7, 6))); - } -} diff --git a/src/test/java/domain/piece/GeneralTest.java b/src/test/java/domain/piece/GeneralTest.java deleted file mode 100644 index 5f2095a581..0000000000 --- a/src/test/java/domain/piece/GeneralTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class GeneralTest { - private Piece general; - - @BeforeEach - void setUp() { - general = new Piece(PieceType.GENERAL, Team.CHO, new GeneralStrategy()); - } - - @Test - void 궁은_위로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(4, 1); - Position to = new Position(4, 2); - - List pathPositions = general.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 궁은_좌로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(4, 1); - Position to = new Position(3, 1); - - List pathPositions = general.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 궁은_우로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(4, 1); - Position to = new Position(5, 1); - - List pathPositions = general.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - - @Test - void 궁은_아래로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(4, 1); - Position to = new Position(4, 0); - - List pathPositions = general.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } -} diff --git a/src/test/java/domain/piece/GuardTest.java b/src/test/java/domain/piece/GuardTest.java deleted file mode 100644 index 18a59ee82d..0000000000 --- a/src/test/java/domain/piece/GuardTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class GuardTest { - private Piece guard; - - @BeforeEach - void setUp() { - guard = new Piece(PieceType.GUARD, Team.CHO, new GuardStrategy()); - } - - @Test - void 사는_위로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(3, 0); - Position to = new Position(3, 1); - - List pathPositions = guard.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 사는_좌로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 0); - Position to = new Position(4, 0); - - List pathPositions = guard.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 졸은_우로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(3, 0); - Position to = new Position(4, 0); - - List pathPositions = guard.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - - @Test - void 사는_아래로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(3, 1); - Position to = new Position(3, 0); - - List pathPositions = guard.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } -} diff --git a/src/test/java/domain/piece/HorseTest.java b/src/test/java/domain/piece/HorseTest.java deleted file mode 100644 index 2f7c18a61e..0000000000 --- a/src/test/java/domain/piece/HorseTest.java +++ /dev/null @@ -1,105 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class HorseTest { - private Piece horse; - - @BeforeEach - void setUp() { - horse = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); - } - - @Test - void 마는_위로_두칸_왼쪽으로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(4, 7); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); - } - - @Test - void 마는_위로_두칸_오른쪽으로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(6, 7); - - List pathPositions = horse.getPathPositions(from, to); - - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 6))); - } - - - @Test - void 마는_위로_한칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(3, 6); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5))); - } - - - @Test - void 마는_아래로_한칸_왼쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(3, 4); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(4, 5))); - } - - - @Test - void 마는_아래로_두칸_왼쪽으로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(4, 3); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4))); - } - - - @Test - void 마는_아래로_두칸_오른쪽으로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(6, 3); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(5, 4))); - } - - - @Test - void 마는_위로_한칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(7, 6); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5))); - } - - - @Test - void 마는_아래로_한칸_오른쪽으로_두칸_움직일_수_있는_경로가_있다() { - Position from = new Position(5, 5); - Position to = new Position(7, 6); - - List pathPositions = horse.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of(new Position(6, 5))); - } -} diff --git a/src/test/java/domain/piece/PieceTest.java b/src/test/java/domain/piece/PieceTest.java deleted file mode 100644 index abfee85ab7..0000000000 --- a/src/test/java/domain/piece/PieceTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package domain.piece; - -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.Test; - - -class PieceTest { - @Test - void 같은_팀의_기물인지_확인한다() { - Piece piece = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); - Piece anotherPiece = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); - - Assertions.assertThat(piece.isSameTeam(anotherPiece)).isTrue(); - } - - @Test - void 다른_팀의_기물인지_확인한다() { - Piece piece = new Piece(PieceType.HORSE, Team.CHO, new HorseStrategy()); - Piece anotherPiece = new Piece(PieceType.HORSE, Team.HAN, new HorseStrategy()); - - Assertions.assertThat(piece.isSameTeam(anotherPiece)).isFalse(); - } -} diff --git a/src/test/java/domain/piece/SoldierChoTest.java b/src/test/java/domain/piece/SoldierChoTest.java deleted file mode 100644 index 9034d3a7f3..0000000000 --- a/src/test/java/domain/piece/SoldierChoTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class SoldierChoTest { - - private Piece soldier; - - @BeforeEach - void setUp() { - soldier = new Piece(PieceType.SOLDIER, Team.CHO, new ChoSoldierStrategy()); - } - - @Test - void 졸은_위로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(0, 3); - Position to = new Position(0, 4); - - List pathPositions = soldier.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 졸은_좌로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(2, 3); - Position to = new Position(1, 3); - - List pathPositions = soldier.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 졸은_우로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(0, 3); - Position to = new Position(1, 3); - - List pathPositions = soldier.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - -} diff --git a/src/test/java/domain/piece/SoldierHanTest.java b/src/test/java/domain/piece/SoldierHanTest.java deleted file mode 100644 index 88174a3804..0000000000 --- a/src/test/java/domain/piece/SoldierHanTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package domain.piece; - -import domain.board.Position; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -class SoldierHanTest { - - private Piece soldier; - - @BeforeEach - void setUp() { - soldier = new Piece(PieceType.SOLDIER, Team.HAN, new HanSoldierStrategy()); - } - - @Test - void 병은_위로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(0, 4); - Position to = new Position(0, 3); - - List pathPositions = soldier.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 병은_좌로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(2, 3); - Position to = new Position(1, 3); - - List pathPositions = soldier.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - - @Test - void 병은_우로_한칸_움직일_수_있는_경로가_있다() { - Position from = new Position(0, 3); - Position to = new Position(1, 3); - - List pathPositions = soldier.getPathPositions(from, to); - - assertThat(pathPositions).isEqualTo(List.of()); - } - -} From 563868beded3356c359c56008863e89291b2bec8 Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 1 Apr 2026 11:06:15 +0900 Subject: [PATCH 27/58] =?UTF-8?q?feat(Board):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=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 --- README.md | 12 +- src/main/java/domain/Board.java | 4 + src/main/java/domain/BoardInitializer.java | 97 ++++++++++++++ src/main/java/domain/BoardSetting.java | 23 ++++ src/main/java/domain/Camp.java | 6 + src/main/java/domain/Piece.java | 4 + src/main/java/domain/PieceType.java | 11 ++ src/main/java/domain/Position.java | 9 +- .../java/domain/BoardInitializerTest.java | 122 ++++++++++++++++++ 9 files changed, 275 insertions(+), 13 deletions(-) create mode 100644 src/main/java/domain/Board.java create mode 100644 src/main/java/domain/BoardInitializer.java create mode 100644 src/main/java/domain/BoardSetting.java create mode 100644 src/main/java/domain/Camp.java create mode 100644 src/main/java/domain/Piece.java create mode 100644 src/main/java/domain/PieceType.java create mode 100644 src/test/java/domain/BoardInitializerTest.java diff --git a/README.md b/README.md index 1cdb5275ad..4656dbb28e 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ - [x] 보드의 범위를 벗어난 좌표에 접근할 경우, IllegalArgumentException을 발생시킨다. - [x] 보드의 좌측 하단을 (0, 0)으로 정의한다. --[ ] 보드를 초기화한다. - - [ ] 상차림에 맞도록 기물을 배치한다. - - [ ] 왼상차림 : 상마상마 - - [ ] 오른상차림 : 마상마상 - - [ ] 바깥상차림 : 마상상마 - - [ ] 안상차림 : 상마마상 +-[x] 보드를 초기화한다. + - [x] 상차림에 맞도록 기물을 배치한다. + - [x] 왼상차림 : 상마상마 + - [x] 오른상차림 : 마상마상 + - [x] 바깥상차림 : 마상상마 + - [x] 안상차림 : 상마마상 diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/Board.java new file mode 100644 index 0000000000..912e312bae --- /dev/null +++ b/src/main/java/domain/Board.java @@ -0,0 +1,4 @@ +package domain; + +public class Board { +} diff --git a/src/main/java/domain/BoardInitializer.java b/src/main/java/domain/BoardInitializer.java new file mode 100644 index 0000000000..9ea925a04f --- /dev/null +++ b/src/main/java/domain/BoardInitializer.java @@ -0,0 +1,97 @@ +package domain; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class BoardInitializer { + private static final int CHO_BASE_ROW = 0; + private static final int CHO_GENERAL_ROW = CHO_BASE_ROW + 1; + private static final int CHO_CANNON_ROW = CHO_BASE_ROW + 2; + private static final int CHO_SOLDIER_ROW = CHO_BASE_ROW + 3; + + private static final int HAN_BASE_ROW = 9; + private static final int HAN_GENERAL_ROW = HAN_BASE_ROW - 1; + private static final int HAN_CANNON_ROW = HAN_BASE_ROW - 2; + private static final int HAN_SOLDIER_ROW = HAN_BASE_ROW - 3; + + private static final List CHARIOT_COLUMNS = List.of(0, 8); + private static final List HORSE_AND_ELEPHANT_COLUMNS = List.of(1, 2, 6, 7); + private static final List CANNON_COLUMNS = List.of(1, 7); + private static final List SOLDIER_COLUMNS = List.of(0, 2, 4, 6, 8); + private static final List GUARD_COLUMNS = List.of(3, 5); + private static final int GENERAL_COLUMN = 4; + + + public static Map init(BoardSetting boardSetting) { + Map pieces = new HashMap<>(); + + pieces.putAll(createGeneral()); + pieces.putAll(createCannon()); + pieces.putAll(createSoldier()); + pieces.putAll(createChariot()); + pieces.putAll(createHorseAndElephant(boardSetting)); + pieces.putAll(createGuard()); + + return pieces; + } + + private static Map createGeneral() { + Map pieces = new HashMap<>(); + pieces.put(new Position(GENERAL_COLUMN, CHO_GENERAL_ROW), new Piece(Camp.CHO, PieceType.GENERAL)); + pieces.put(new Position(GENERAL_COLUMN, HAN_GENERAL_ROW), new Piece(Camp.HAN, PieceType.GENERAL)); + + return pieces; + } + + private static Map createCannon() { + Map pieces = new HashMap<>(); + for (Integer column : CANNON_COLUMNS) { + pieces.put(new Position(column, CHO_CANNON_ROW), new Piece(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(column, HAN_CANNON_ROW), new Piece(Camp.HAN, PieceType.CANNON)); + } + + return pieces; + } + + private static Map createSoldier() { + Map pieces = new HashMap<>(); + for (Integer column : SOLDIER_COLUMNS) { + pieces.put(new Position(column, CHO_SOLDIER_ROW), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(column, HAN_SOLDIER_ROW), new Piece(Camp.HAN, PieceType.SOLDIER)); + } + + return pieces; + } + + private static Map createChariot() { + Map pieces = new HashMap<>(); + for (Integer column : CHARIOT_COLUMNS) { + pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.CHARIOT)); + } + + return pieces; + } + + private static Map createHorseAndElephant(BoardSetting boardSetting) { + Map pieces = new HashMap<>(); + for (int i = 0; i < boardSetting.piecesArrangement().size(); i++) { + pieces.put(new Position(HORSE_AND_ELEPHANT_COLUMNS.get(i), CHO_BASE_ROW), new Piece(Camp.CHO, boardSetting.piecesArrangement().get(i))); + pieces.put(new Position(HORSE_AND_ELEPHANT_COLUMNS.get(i), HAN_BASE_ROW), new Piece(Camp.HAN, boardSetting.piecesArrangement().get(i))); + } + + return pieces; + } + + private static Map createGuard() { + Map pieces = new HashMap<>(); + for (Integer column : GUARD_COLUMNS) { + pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.GUARD)); + } + + return pieces; + } + +} diff --git a/src/main/java/domain/BoardSetting.java b/src/main/java/domain/BoardSetting.java new file mode 100644 index 0000000000..486ec6dad7 --- /dev/null +++ b/src/main/java/domain/BoardSetting.java @@ -0,0 +1,23 @@ +package domain; + +import java.util.List; + +import static domain.PieceType.ELEPHANT; +import static domain.PieceType.HORSE; + +public enum BoardSetting { + LEFT_ELEPHANT_SET_UP(List.of(ELEPHANT, HORSE, ELEPHANT, HORSE)), + RIGHT_ELEPHANT_SET_UP(List.of(HORSE, ELEPHANT, HORSE, ELEPHANT)), + OUTER_ELEPHANT_SET_UP(List.of(HORSE, ELEPHANT, ELEPHANT, HORSE)), + INNER_ELEPHANT_SET_UP(List.of(ELEPHANT, HORSE, HORSE, ELEPHANT)); + + private final List piecesArrangement; + + BoardSetting(List pieceTypes) { + this.piecesArrangement = pieceTypes; + } + + public List piecesArrangement() { + return piecesArrangement; + } +} diff --git a/src/main/java/domain/Camp.java b/src/main/java/domain/Camp.java new file mode 100644 index 0000000000..b942e3e06a --- /dev/null +++ b/src/main/java/domain/Camp.java @@ -0,0 +1,6 @@ +package domain; + +public enum Camp { + CHO, + HAN +} diff --git a/src/main/java/domain/Piece.java b/src/main/java/domain/Piece.java new file mode 100644 index 0000000000..9b8762328e --- /dev/null +++ b/src/main/java/domain/Piece.java @@ -0,0 +1,4 @@ +package domain; + +public record Piece(Camp camp, PieceType pieceType) { +} diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/PieceType.java new file mode 100644 index 0000000000..4c1c24135c --- /dev/null +++ b/src/main/java/domain/PieceType.java @@ -0,0 +1,11 @@ +package domain; + +public enum PieceType { + GENERAL, + GUARD, + HORSE, + ELEPHANT, + CHARIOT, + CANNON, + SOLDIER +} diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index e8fc82c394..8e37e5c265 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -1,19 +1,14 @@ package domain; -public class Position { +public record Position(int column, int row) { private static final int MIN_POSITION = 0; private static final int MAX_COLUMN = 8; private static final int MAX_ROW = 9; - private final int column; - private final int row; - - public Position(int column, int row) { + public Position { validateColumn(column); validateRow(row); - this.column = column; - this.row = row; } private void validateColumn(int column) { diff --git a/src/test/java/domain/BoardInitializerTest.java b/src/test/java/domain/BoardInitializerTest.java new file mode 100644 index 0000000000..7cd6c30876 --- /dev/null +++ b/src/test/java/domain/BoardInitializerTest.java @@ -0,0 +1,122 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static domain.BoardSetting.*; +import static org.assertj.core.api.Assertions.assertThat; + +class BoardInitializerTest { + private Map positions; + + @BeforeEach + void setUp() { + positions = createFixPosition(); + } + + + @Nested + class 상차림_테스트 { + @Test + void 왼상차림은_상마상마_순서대로_배치한다() { + Map pieces = BoardInitializer.init(LEFT_ELEPHANT_SET_UP); + positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.HORSE)); + positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.HORSE)); + + assertThat(pieces).isEqualTo(positions); + } + + @Test + void 오른상차림은_마상마상_순서대로_배치한다() { + Map pieces = BoardInitializer.init(RIGHT_ELEPHANT_SET_UP); + positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.HORSE)); + positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.HORSE)); + positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + + + assertThat(pieces).isEqualTo(positions); + } + + @Test + void 바깥상차림은_마상상마_순서대로_배치한다() { + Map pieces = BoardInitializer.init(OUTER_ELEPHANT_SET_UP); + positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.HORSE)); + positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.HORSE)); + + + assertThat(pieces).isEqualTo(positions); + } + + @Test + void 안상차림은_상마마상_순서대로_배치한다() { + Map pieces = BoardInitializer.init(INNER_ELEPHANT_SET_UP); + positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.HORSE)); + positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); + positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.HORSE)); + positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.HORSE)); + positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); + + + assertThat(pieces).isEqualTo(positions); + } + } + + private static Map createFixPosition() { + Map pieces = new HashMap<>(); + + pieces.put(new Position(8, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(0, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(0, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(8, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); + + pieces.put(new Position(3, 0), new Piece(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(5, 0), new Piece(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(3, 9), new Piece(Camp.HAN, PieceType.GUARD)); + pieces.put(new Position(5, 9), new Piece(Camp.HAN, PieceType.GUARD)); + + pieces.put(new Position(1, 2), new Piece(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(7, 2), new Piece(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(1, 7), new Piece(Camp.HAN, PieceType.CANNON)); + pieces.put(new Position(7, 7), new Piece(Camp.HAN, PieceType.CANNON)); + + pieces.put(new Position(0, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(2, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(4, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(6, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(8, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(0, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(2, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(4, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(6, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(8, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); + + pieces.put(new Position(4, 1), new Piece(Camp.CHO, PieceType.GENERAL)); + pieces.put(new Position(4, 8), new Piece(Camp.HAN, PieceType.GENERAL)); + + return pieces; + } +} From 779dd7e8b4be864ce57b83c25572e6009cd7bf6e Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 1 Apr 2026 11:10:15 +0900 Subject: [PATCH 28/58] =?UTF-8?q?refactor(Position):=20=EB=A7=A4=EC=A7=81?= =?UTF-8?q?=EB=84=98=EB=B2=84=20=EC=83=81=EC=88=98=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/Position.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 8e37e5c265..5ce9226e8b 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -12,14 +12,14 @@ public record Position(int column, int row) { } private void validateColumn(int column) { - if (column < 0 || column > MAX_COLUMN) { + if (column < MIN_POSITION || column > MAX_COLUMN) { throw new IllegalArgumentException( String.format("[ERROR] x좌표는 %d에서 %d 사이입니다.", MIN_POSITION, MAX_COLUMN)); } } private void validateRow(int row) { - if (row < 0 || row > MAX_ROW) { + if (row < MIN_POSITION || row > MAX_ROW) { throw new IllegalArgumentException( String.format("[ERROR] y좌표는 %d에서 %d 사이입니다.", MIN_POSITION, MAX_ROW)); } From 0fc9a24aa32115d4c7fec137adda75228cdbdf57 Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 1 Apr 2026 11:33:13 +0900 Subject: [PATCH 29/58] =?UTF-8?q?test(Board):=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=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.java | 7 ++ src/main/java/domain/BoardInitializer.java | 46 ++++---- .../java/domain/BoardInitializerTest.java | 109 +++++------------- 3 files changed, 55 insertions(+), 107 deletions(-) diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/Board.java index 912e312bae..74fd262e2a 100644 --- a/src/main/java/domain/Board.java +++ b/src/main/java/domain/Board.java @@ -1,4 +1,11 @@ package domain; +import java.util.Map; + public class Board { + Map pieces; + + public Board(Map pieces) { + this.pieces = pieces; + } } diff --git a/src/main/java/domain/BoardInitializer.java b/src/main/java/domain/BoardInitializer.java index 9ea925a04f..ba1f417092 100644 --- a/src/main/java/domain/BoardInitializer.java +++ b/src/main/java/domain/BoardInitializer.java @@ -15,23 +15,22 @@ public class BoardInitializer { private static final int HAN_CANNON_ROW = HAN_BASE_ROW - 2; private static final int HAN_SOLDIER_ROW = HAN_BASE_ROW - 3; + private static final int GENERAL_COLUMN = 4; + private static final List GUARD_COLUMNS = List.of(3, 5); private static final List CHARIOT_COLUMNS = List.of(0, 8); - private static final List HORSE_AND_ELEPHANT_COLUMNS = List.of(1, 2, 6, 7); private static final List CANNON_COLUMNS = List.of(1, 7); + private static final List HORSE_AND_ELEPHANT_COLUMNS = List.of(1, 2, 6, 7); private static final List SOLDIER_COLUMNS = List.of(0, 2, 4, 6, 8); - private static final List GUARD_COLUMNS = List.of(3, 5); - private static final int GENERAL_COLUMN = 4; - public static Map init(BoardSetting boardSetting) { Map pieces = new HashMap<>(); pieces.putAll(createGeneral()); - pieces.putAll(createCannon()); - pieces.putAll(createSoldier()); + pieces.putAll(createGuard()); pieces.putAll(createChariot()); + pieces.putAll(createCannon()); pieces.putAll(createHorseAndElephant(boardSetting)); - pieces.putAll(createGuard()); + pieces.putAll(createSoldier()); return pieces; } @@ -44,31 +43,31 @@ private static Map createGeneral() { return pieces; } - private static Map createCannon() { + private static Map createGuard() { Map pieces = new HashMap<>(); - for (Integer column : CANNON_COLUMNS) { - pieces.put(new Position(column, CHO_CANNON_ROW), new Piece(Camp.CHO, PieceType.CANNON)); - pieces.put(new Position(column, HAN_CANNON_ROW), new Piece(Camp.HAN, PieceType.CANNON)); + for (Integer column : GUARD_COLUMNS) { + pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.GUARD)); } return pieces; } - private static Map createSoldier() { + private static Map createChariot() { Map pieces = new HashMap<>(); - for (Integer column : SOLDIER_COLUMNS) { - pieces.put(new Position(column, CHO_SOLDIER_ROW), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(column, HAN_SOLDIER_ROW), new Piece(Camp.HAN, PieceType.SOLDIER)); + for (Integer column : CHARIOT_COLUMNS) { + pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.CHARIOT)); } return pieces; } - private static Map createChariot() { + private static Map createCannon() { Map pieces = new HashMap<>(); - for (Integer column : CHARIOT_COLUMNS) { - pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.CHARIOT)); - pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.CHARIOT)); + for (Integer column : CANNON_COLUMNS) { + pieces.put(new Position(column, CHO_CANNON_ROW), new Piece(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(column, HAN_CANNON_ROW), new Piece(Camp.HAN, PieceType.CANNON)); } return pieces; @@ -84,14 +83,13 @@ private static Map createHorseAndElephant(BoardSetting boardSet return pieces; } - private static Map createGuard() { + private static Map createSoldier() { Map pieces = new HashMap<>(); - for (Integer column : GUARD_COLUMNS) { - pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.GUARD)); - pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.GUARD)); + for (Integer column : SOLDIER_COLUMNS) { + pieces.put(new Position(column, CHO_SOLDIER_ROW), new Piece(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(column, HAN_SOLDIER_ROW), new Piece(Camp.HAN, PieceType.SOLDIER)); } return pieces; } - } diff --git a/src/test/java/domain/BoardInitializerTest.java b/src/test/java/domain/BoardInitializerTest.java index 7cd6c30876..8490fc8d39 100644 --- a/src/test/java/domain/BoardInitializerTest.java +++ b/src/test/java/domain/BoardInitializerTest.java @@ -1,108 +1,54 @@ package domain; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import java.util.HashMap; +import java.util.List; import java.util.Map; -import static domain.BoardSetting.*; import static org.assertj.core.api.Assertions.assertThat; class BoardInitializerTest { - private Map positions; - @BeforeEach - void setUp() { - positions = createFixPosition(); + @ParameterizedTest + @EnumSource(BoardSetting.class) + void 상차림에_따라_모든_기물이_올바른_위치에_초기화된다(BoardSetting boardSetting) { + Map pieces = BoardInitializer.init(boardSetting); + assertThat(pieces).isEqualTo(createPieces(boardSetting)); } - - @Nested - class 상차림_테스트 { - @Test - void 왼상차림은_상마상마_순서대로_배치한다() { - Map pieces = BoardInitializer.init(LEFT_ELEPHANT_SET_UP); - positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.HORSE)); - positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.HORSE)); - - assertThat(pieces).isEqualTo(positions); - } - - @Test - void 오른상차림은_마상마상_순서대로_배치한다() { - Map pieces = BoardInitializer.init(RIGHT_ELEPHANT_SET_UP); - positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.HORSE)); - positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.HORSE)); - positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - - - assertThat(pieces).isEqualTo(positions); - } - - @Test - void 바깥상차림은_마상상마_순서대로_배치한다() { - Map pieces = BoardInitializer.init(OUTER_ELEPHANT_SET_UP); - positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.HORSE)); - positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.HORSE)); - - - assertThat(pieces).isEqualTo(positions); - } - - @Test - void 안상차림은_상마마상_순서대로_배치한다() { - Map pieces = BoardInitializer.init(INNER_ELEPHANT_SET_UP); - positions.put(new Position(1, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(2, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(6, 0), new Piece(Camp.CHO, PieceType.HORSE)); - positions.put(new Position(7, 0), new Piece(Camp.CHO, PieceType.ELEPHANT)); - positions.put(new Position(1, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - positions.put(new Position(2, 9), new Piece(Camp.HAN, PieceType.HORSE)); - positions.put(new Position(6, 9), new Piece(Camp.HAN, PieceType.HORSE)); - positions.put(new Position(7, 9), new Piece(Camp.HAN, PieceType.ELEPHANT)); - - - assertThat(pieces).isEqualTo(positions); - } - } - - private static Map createFixPosition() { + private static Map createPieces(BoardSetting boardSetting) { Map pieces = new HashMap<>(); - pieces.put(new Position(8, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); - pieces.put(new Position(0, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); - pieces.put(new Position(0, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); - pieces.put(new Position(8, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(4, 1), new Piece(Camp.CHO, PieceType.GENERAL)); + pieces.put(new Position(4, 8), new Piece(Camp.HAN, PieceType.GENERAL)); pieces.put(new Position(3, 0), new Piece(Camp.CHO, PieceType.GUARD)); pieces.put(new Position(5, 0), new Piece(Camp.CHO, PieceType.GUARD)); pieces.put(new Position(3, 9), new Piece(Camp.HAN, PieceType.GUARD)); pieces.put(new Position(5, 9), new Piece(Camp.HAN, PieceType.GUARD)); + pieces.put(new Position(8, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(0, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(0, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(8, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(1, 2), new Piece(Camp.CHO, PieceType.CANNON)); pieces.put(new Position(7, 2), new Piece(Camp.CHO, PieceType.CANNON)); pieces.put(new Position(1, 7), new Piece(Camp.HAN, PieceType.CANNON)); pieces.put(new Position(7, 7), new Piece(Camp.HAN, PieceType.CANNON)); + List horseAndElephantArrangement = boardSetting.piecesArrangement(); + pieces.put(new Position(1, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(0))); + pieces.put(new Position(2, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(1))); + pieces.put(new Position(6, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(2))); + pieces.put(new Position(7, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(3))); + pieces.put(new Position(1, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(0))); + pieces.put(new Position(2, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(1))); + pieces.put(new Position(6, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(2))); + pieces.put(new Position(7, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(3))); + pieces.put(new Position(0, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); pieces.put(new Position(2, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); pieces.put(new Position(4, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); @@ -114,9 +60,6 @@ private static Map createFixPosition() { pieces.put(new Position(6, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); pieces.put(new Position(8, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); - pieces.put(new Position(4, 1), new Piece(Camp.CHO, PieceType.GENERAL)); - pieces.put(new Position(4, 8), new Piece(Camp.HAN, PieceType.GENERAL)); - return pieces; } } From 1439b548e0ada84d8b6c34606dafe5444f1b8fc6 Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 1 Apr 2026 13:57:21 +0900 Subject: [PATCH 30/58] =?UTF-8?q?feat(Board):=20=EB=B3=B4=EB=93=9C=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 --- src/main/java/domain/Board.java | 8 ++++++++ src/test/java/domain/BoardTest.java | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 src/test/java/domain/BoardTest.java diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/Board.java index 74fd262e2a..46a4f52138 100644 --- a/src/main/java/domain/Board.java +++ b/src/main/java/domain/Board.java @@ -8,4 +8,12 @@ public class Board { public Board(Map pieces) { this.pieces = pieces; } + + public Piece pieceAt(Position position) { + if (!pieces.containsKey(position)) { + throw new IllegalArgumentException("해당 위치에 기물이 존재하지 않습니다."); + } + + return pieces.get(position); + } } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java new file mode 100644 index 0000000000..8a27e0fb54 --- /dev/null +++ b/src/test/java/domain/BoardTest.java @@ -0,0 +1,27 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class BoardTest { + private Board board; + + @BeforeEach + void setUp() { + board = new Board(BoardInitializer.init(BoardSetting.LEFT_ELEPHANT_SET_UP)); + } + + @Test + void 선택한_좌표에_위치한_기물을_반환한다() { + assertThat(board.pieceAt(new Position(8, 0))).isEqualTo(new Piece(Camp.CHO, PieceType.CHARIOT)); + } + + @Test + void 선택한_좌표에_기물이_없을_경우_예외를_반환한다() { + assertThatThrownBy(() -> board.pieceAt(new Position(5, 5))).isInstanceOf(IllegalArgumentException.class); + } + +} From 17052137486a48a8aaef481c2ddaf28946402b65 Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 1 Apr 2026 14:17:07 +0900 Subject: [PATCH 31/58] =?UTF-8?q?feat(Piece):=20Piece=EC=97=90=20=EC=A0=95?= =?UTF-8?q?=EC=A0=81=20=ED=8C=A9=ED=86=A0=EB=A6=AC=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EB=8F=84=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/BoardInitializer.java | 24 +++---- src/main/java/domain/Piece.java | 5 +- src/main/java/domain/PieceType.java | 12 +++- .../java/domain/BoardInitializerTest.java | 64 +++++++++---------- src/test/java/domain/BoardTest.java | 3 +- 5 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/main/java/domain/BoardInitializer.java b/src/main/java/domain/BoardInitializer.java index ba1f417092..2ce709d057 100644 --- a/src/main/java/domain/BoardInitializer.java +++ b/src/main/java/domain/BoardInitializer.java @@ -37,8 +37,8 @@ public static Map init(BoardSetting boardSetting) { private static Map createGeneral() { Map pieces = new HashMap<>(); - pieces.put(new Position(GENERAL_COLUMN, CHO_GENERAL_ROW), new Piece(Camp.CHO, PieceType.GENERAL)); - pieces.put(new Position(GENERAL_COLUMN, HAN_GENERAL_ROW), new Piece(Camp.HAN, PieceType.GENERAL)); + pieces.put(new Position(GENERAL_COLUMN, CHO_GENERAL_ROW), Piece.of(Camp.CHO, PieceType.GENERAL)); + pieces.put(new Position(GENERAL_COLUMN, HAN_GENERAL_ROW), Piece.of(Camp.HAN, PieceType.GENERAL)); return pieces; } @@ -46,8 +46,8 @@ private static Map createGeneral() { private static Map createGuard() { Map pieces = new HashMap<>(); for (Integer column : GUARD_COLUMNS) { - pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.GUARD)); - pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.GUARD)); + pieces.put(new Position(column, CHO_BASE_ROW), Piece.of(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(column, HAN_BASE_ROW), Piece.of(Camp.HAN, PieceType.GUARD)); } return pieces; @@ -56,8 +56,8 @@ private static Map createGuard() { private static Map createChariot() { Map pieces = new HashMap<>(); for (Integer column : CHARIOT_COLUMNS) { - pieces.put(new Position(column, CHO_BASE_ROW), new Piece(Camp.CHO, PieceType.CHARIOT)); - pieces.put(new Position(column, HAN_BASE_ROW), new Piece(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(column, CHO_BASE_ROW), Piece.of(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(column, HAN_BASE_ROW), Piece.of(Camp.HAN, PieceType.CHARIOT)); } return pieces; @@ -66,8 +66,8 @@ private static Map createChariot() { private static Map createCannon() { Map pieces = new HashMap<>(); for (Integer column : CANNON_COLUMNS) { - pieces.put(new Position(column, CHO_CANNON_ROW), new Piece(Camp.CHO, PieceType.CANNON)); - pieces.put(new Position(column, HAN_CANNON_ROW), new Piece(Camp.HAN, PieceType.CANNON)); + pieces.put(new Position(column, CHO_CANNON_ROW), Piece.of(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(column, HAN_CANNON_ROW), Piece.of(Camp.HAN, PieceType.CANNON)); } return pieces; @@ -76,8 +76,8 @@ private static Map createCannon() { private static Map createHorseAndElephant(BoardSetting boardSetting) { Map pieces = new HashMap<>(); for (int i = 0; i < boardSetting.piecesArrangement().size(); i++) { - pieces.put(new Position(HORSE_AND_ELEPHANT_COLUMNS.get(i), CHO_BASE_ROW), new Piece(Camp.CHO, boardSetting.piecesArrangement().get(i))); - pieces.put(new Position(HORSE_AND_ELEPHANT_COLUMNS.get(i), HAN_BASE_ROW), new Piece(Camp.HAN, boardSetting.piecesArrangement().get(i))); + pieces.put(new Position(HORSE_AND_ELEPHANT_COLUMNS.get(i), CHO_BASE_ROW), Piece.of(Camp.CHO, boardSetting.piecesArrangement().get(i))); + pieces.put(new Position(HORSE_AND_ELEPHANT_COLUMNS.get(i), HAN_BASE_ROW), Piece.of(Camp.HAN, boardSetting.piecesArrangement().get(i))); } return pieces; @@ -86,8 +86,8 @@ private static Map createHorseAndElephant(BoardSetting boardSet private static Map createSoldier() { Map pieces = new HashMap<>(); for (Integer column : SOLDIER_COLUMNS) { - pieces.put(new Position(column, CHO_SOLDIER_ROW), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(column, HAN_SOLDIER_ROW), new Piece(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(column, CHO_SOLDIER_ROW), Piece.of(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(column, HAN_SOLDIER_ROW), Piece.of(Camp.HAN, PieceType.SOLDIER)); } return pieces; diff --git a/src/main/java/domain/Piece.java b/src/main/java/domain/Piece.java index 9b8762328e..20d2df56fc 100644 --- a/src/main/java/domain/Piece.java +++ b/src/main/java/domain/Piece.java @@ -1,4 +1,7 @@ package domain; -public record Piece(Camp camp, PieceType pieceType) { +public record Piece(Camp camp, PieceType pieceType, MoveStrategy moveStrategy) { + public static Piece of(Camp camp, PieceType pieceType){ + return new Piece(camp, pieceType, pieceType.moveStrategy()); + } } diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/PieceType.java index 4c1c24135c..72c9cc0681 100644 --- a/src/main/java/domain/PieceType.java +++ b/src/main/java/domain/PieceType.java @@ -3,9 +3,15 @@ public enum PieceType { GENERAL, GUARD, - HORSE, - ELEPHANT, CHARIOT, CANNON, - SOLDIER + HORSE, + ELEPHANT, + SOLDIER; + + private MoveStrategy moveStrategy; + + public MoveStrategy moveStrategy() { + return moveStrategy; + } } diff --git a/src/test/java/domain/BoardInitializerTest.java b/src/test/java/domain/BoardInitializerTest.java index 8490fc8d39..bcbf547a50 100644 --- a/src/test/java/domain/BoardInitializerTest.java +++ b/src/test/java/domain/BoardInitializerTest.java @@ -21,44 +21,44 @@ class BoardInitializerTest { private static Map createPieces(BoardSetting boardSetting) { Map pieces = new HashMap<>(); - pieces.put(new Position(4, 1), new Piece(Camp.CHO, PieceType.GENERAL)); - pieces.put(new Position(4, 8), new Piece(Camp.HAN, PieceType.GENERAL)); + pieces.put(new Position(4, 1), Piece.of(Camp.CHO, PieceType.GENERAL)); + pieces.put(new Position(4, 8), Piece.of(Camp.HAN, PieceType.GENERAL)); - pieces.put(new Position(3, 0), new Piece(Camp.CHO, PieceType.GUARD)); - pieces.put(new Position(5, 0), new Piece(Camp.CHO, PieceType.GUARD)); - pieces.put(new Position(3, 9), new Piece(Camp.HAN, PieceType.GUARD)); - pieces.put(new Position(5, 9), new Piece(Camp.HAN, PieceType.GUARD)); + pieces.put(new Position(3, 0), Piece.of(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(5, 0), Piece.of(Camp.CHO, PieceType.GUARD)); + pieces.put(new Position(3, 9), Piece.of(Camp.HAN, PieceType.GUARD)); + pieces.put(new Position(5, 9), Piece.of(Camp.HAN, PieceType.GUARD)); - pieces.put(new Position(8, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); - pieces.put(new Position(0, 0), new Piece(Camp.CHO, PieceType.CHARIOT)); - pieces.put(new Position(0, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); - pieces.put(new Position(8, 9), new Piece(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(8, 0), Piece.of(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(0, 0), Piece.of(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(0, 9), Piece.of(Camp.HAN, PieceType.CHARIOT)); + pieces.put(new Position(8, 9), Piece.of(Camp.HAN, PieceType.CHARIOT)); - pieces.put(new Position(1, 2), new Piece(Camp.CHO, PieceType.CANNON)); - pieces.put(new Position(7, 2), new Piece(Camp.CHO, PieceType.CANNON)); - pieces.put(new Position(1, 7), new Piece(Camp.HAN, PieceType.CANNON)); - pieces.put(new Position(7, 7), new Piece(Camp.HAN, PieceType.CANNON)); + pieces.put(new Position(1, 2), Piece.of(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(7, 2), Piece.of(Camp.CHO, PieceType.CANNON)); + pieces.put(new Position(1, 7), Piece.of(Camp.HAN, PieceType.CANNON)); + pieces.put(new Position(7, 7), Piece.of(Camp.HAN, PieceType.CANNON)); List horseAndElephantArrangement = boardSetting.piecesArrangement(); - pieces.put(new Position(1, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(0))); - pieces.put(new Position(2, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(1))); - pieces.put(new Position(6, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(2))); - pieces.put(new Position(7, 0), new Piece(Camp.CHO, horseAndElephantArrangement.get(3))); - pieces.put(new Position(1, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(0))); - pieces.put(new Position(2, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(1))); - pieces.put(new Position(6, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(2))); - pieces.put(new Position(7, 9), new Piece(Camp.HAN, horseAndElephantArrangement.get(3))); + pieces.put(new Position(1, 0), Piece.of(Camp.CHO, horseAndElephantArrangement.get(0))); + pieces.put(new Position(2, 0), Piece.of(Camp.CHO, horseAndElephantArrangement.get(1))); + pieces.put(new Position(6, 0), Piece.of(Camp.CHO, horseAndElephantArrangement.get(2))); + pieces.put(new Position(7, 0), Piece.of(Camp.CHO, horseAndElephantArrangement.get(3))); + pieces.put(new Position(1, 9), Piece.of(Camp.HAN, horseAndElephantArrangement.get(0))); + pieces.put(new Position(2, 9), Piece.of(Camp.HAN, horseAndElephantArrangement.get(1))); + pieces.put(new Position(6, 9), Piece.of(Camp.HAN, horseAndElephantArrangement.get(2))); + pieces.put(new Position(7, 9), Piece.of(Camp.HAN, horseAndElephantArrangement.get(3))); - pieces.put(new Position(0, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(2, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(4, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(6, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(8, 3), new Piece(Camp.CHO, PieceType.SOLDIER)); - pieces.put(new Position(0, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); - pieces.put(new Position(2, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); - pieces.put(new Position(4, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); - pieces.put(new Position(6, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); - pieces.put(new Position(8, 6), new Piece(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(0, 3), Piece.of(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(2, 3), Piece.of(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(4, 3), Piece.of(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(6, 3), Piece.of(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(8, 3), Piece.of(Camp.CHO, PieceType.SOLDIER)); + pieces.put(new Position(0, 6), Piece.of(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(2, 6), Piece.of(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(4, 6), Piece.of(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(6, 6), Piece.of(Camp.HAN, PieceType.SOLDIER)); + pieces.put(new Position(8, 6), Piece.of(Camp.HAN, PieceType.SOLDIER)); return pieces; } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index 8a27e0fb54..b227643306 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -16,12 +16,11 @@ void setUp() { @Test void 선택한_좌표에_위치한_기물을_반환한다() { - assertThat(board.pieceAt(new Position(8, 0))).isEqualTo(new Piece(Camp.CHO, PieceType.CHARIOT)); + assertThat(board.pieceAt(new Position(8, 0))).isEqualTo(Piece.of(Camp.CHO, PieceType.CHARIOT)); } @Test void 선택한_좌표에_기물이_없을_경우_예외를_반환한다() { assertThatThrownBy(() -> board.pieceAt(new Position(5, 5))).isInstanceOf(IllegalArgumentException.class); } - } From 11e40a635e218d76b6c4c5c9e65419f3c993ded1 Mon Sep 17 00:00:00 2001 From: frombunny Date: Wed, 1 Apr 2026 15:23:25 +0900 Subject: [PATCH 32/58] =?UTF-8?q?feat(Position):=20=EC=A2=8C=ED=91=9C=20?= =?UTF-8?q?=EC=B0=A8=EC=9D=B4=20=EA=B3=84=EC=82=B0=20=EB=A1=9C=EC=A7=81=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 --- src/main/java/domain/Position.java | 8 ++++++++ src/test/java/domain/PositionTest.java | 27 +++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 5ce9226e8b..4d48b0f641 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -11,6 +11,14 @@ public record Position(int column, int row) { } + public int calculateDeltaX(Position destination) { + return destination.column - this.column; + } + + public int calculateDeltaY(Position destination) { + return destination.row - this.row; + } + private void validateColumn(int column) { if (column < MIN_POSITION || column > MAX_COLUMN) { throw new IllegalArgumentException( diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/PositionTest.java index d468d6ea11..9f7e94c9da 100644 --- a/src/test/java/domain/PositionTest.java +++ b/src/test/java/domain/PositionTest.java @@ -1,8 +1,9 @@ package domain; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; class PositionTest { @@ -11,27 +12,43 @@ class PositionTest { class 좌표_범위_검증_테스트 { @Test void x좌표가_0_미만일_경우_예외를_던진다() { - Assertions.assertThatThrownBy(() -> new Position(9, 2)) + assertThatThrownBy(() -> new Position(9, 2)) .isInstanceOf(IllegalArgumentException.class); } @Test void x좌표가_8을_초과할_경우_예외를_던진다() { - Assertions.assertThatThrownBy(() -> new Position(-1, 2)) + assertThatThrownBy(() -> new Position(-1, 2)) .isInstanceOf(IllegalArgumentException.class); } @Test void y좌표가_0_미만일_경우_예외를_던진다() { - Assertions.assertThatThrownBy(() -> new Position(3, -1)) + assertThatThrownBy(() -> new Position(3, -1)) .isInstanceOf(IllegalArgumentException.class); } @Test void y좌표가_9를_초과할_경우_예외를_던진다() { - Assertions.assertThatThrownBy(() -> new Position(2, 10)) + assertThatThrownBy(() -> new Position(2, 10)) .isInstanceOf(IllegalArgumentException.class); } } + @Nested + class 좌표_차이_계산_테스트 { + Position position = new Position(0, 0); + + @Test + void 두_좌표의_x_증가량을_계산한다() { + assertThat(position.calculateDeltaX(new Position(1,0))).isEqualTo(1); + } + + @Test + void 두_좌표의_y_증가량을_계산한다() { + assertThat(position.calculateDeltaY(new Position(0,1))).isEqualTo(1); + + } + } + } From 8f6a7db9051693749a713c7eb330b9756caf7e7e Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 13:28:59 +0900 Subject: [PATCH 33/58] =?UTF-8?q?feat(Direction):=20=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95=20=EB=A1=9C=EC=A7=81=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/Direction.java | 74 ++++++++++++++++++++ src/test/java/domain/DirectionTest.java | 89 +++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/main/java/domain/Direction.java create mode 100644 src/test/java/domain/DirectionTest.java diff --git a/src/main/java/domain/Direction.java b/src/main/java/domain/Direction.java new file mode 100644 index 0000000000..ccf6cbb7d6 --- /dev/null +++ b/src/main/java/domain/Direction.java @@ -0,0 +1,74 @@ +package domain; + +public enum Direction { + UP(0, 1), + DOWN(0, -1), + RIGHT(1, 0), + LEFT(-1, 0), + NORTHEAST(1, 1), + NORTHWEST(-1, 1), + SOUTHEAST(1, -1), + SOUTHWEST(-1, -1); + + private final int deltaX; + private final int deltaY; + + Direction(int deltaX, int deltaY) { + this.deltaX = deltaX; + this.deltaY = deltaY; + } + + public static Direction decideDirection(int deltaX, int deltaY) { + if (deltaX == 0 && deltaY == 0) { + throw new IllegalArgumentException("출발 위치와 도착 위치가 같습니다."); + } + + if (deltaX == 0 || deltaY == 0) { + return decideStraightDirection(deltaX, deltaY); + } + + if (Math.abs(deltaX) == Math.abs(deltaY)) { + return decideDiagonalDirection(deltaX, deltaY); + } + + throw new IllegalArgumentException("이동할 수 없는 방향입니다."); + } + + private static Direction decideStraightDirection(int deltaX, int deltaY) { + if (deltaX > 0) { + return RIGHT; + } + + if (deltaX < 0) { + return LEFT; + } + + if (deltaY > 0) { + return UP; + } + + return DOWN; + } + + private static Direction decideDiagonalDirection(int deltaX, int deltaY) { + if (deltaX > 0) { + if (deltaY > 0) { + return NORTHEAST; + } + return SOUTHEAST; + } + + if (deltaY > 0) { + return NORTHWEST; + } + return SOUTHWEST; + } + + public int getDeltaX() { + return deltaX; + } + + public int getDeltaY() { + return deltaY; + } +} diff --git a/src/test/java/domain/DirectionTest.java b/src/test/java/domain/DirectionTest.java new file mode 100644 index 0000000000..80e4dfe1a6 --- /dev/null +++ b/src/test/java/domain/DirectionTest.java @@ -0,0 +1,89 @@ +package domain; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class DirectionTest { + private Position departure; + + @BeforeEach + void setUp() { + departure = new Position(5, 5); + } + + @Test + void 왼쪽_방향을_판정한다() { + Position destination = new Position(4, 5); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.LEFT); + } + + @Test + void 오른쪽_방향을_판정한다() { + Position destination = new Position(6, 5); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.RIGHT); + } + + @Test + void 위쪽_방향을_판정한다() { + Position destination = new Position(5, 6); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.UP); + } + + @Test + void 아래쪽_방향을_판정한다() { + Position destination = new Position(5, 4); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.DOWN); + } + + @Test + void 북동쪽_방향을_판정한다() { + Position destination = new Position(6, 6); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.NORTHEAST); + } + + @Test + void 북서쪽_방향을_판정한다() { + Position destination = new Position(4, 6); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.NORTHWEST); + } + + @Test + void 남동쪽_방향을_판정한다() { + Position destination = new Position(6, 4); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.SOUTHEAST); + } + + @Test + void 남서쪽_방향을_판정한다() { + Position destination = new Position(4, 4); + Direction direction = Direction.decideDirection(departure.calculateDeltaX(destination), departure.calculateDeltaY(destination)); + assertThat(direction).isEqualTo(Direction.SOUTHWEST); + } + + @Test + void 출발_위치와_도착_위치가_같으면_예외를_던진다() { + assertThatThrownBy(() -> + Direction.decideDirection(departure.calculateDeltaX(departure), + departure.calculateDeltaY(departure))).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 직선_방향과_대각선_방향_모두_아닐_경우_예외를_던진다() { + Position destination = new Position(2, 3); + assertThatThrownBy(() -> + Direction.decideDirection(departure.calculateDeltaX(destination), + departure.calculateDeltaY(destination))).isInstanceOf(IllegalArgumentException.class); + + } + +} From b36fa6ee695f1d1c212930fe7ac6cfd9159f915f Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 13:35:10 +0900 Subject: [PATCH 34/58] =?UTF-8?q?feat(MoveStrategy):=20=EC=B0=A8=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 28 ++++++++-- src/main/java/domain/Board.java | 32 +++++++++++- src/main/java/domain/ChariotMoveStrategy.java | 30 +++++++++++ src/main/java/domain/MoveStrategy.java | 8 +++ src/main/java/domain/PathGenerator.java | 18 +++++++ src/main/java/domain/PathInfo.java | 7 +++ src/main/java/domain/Piece.java | 16 +++++- src/main/java/domain/PieceType.java | 18 ++++--- src/main/java/domain/Position.java | 4 ++ src/test/java/domain/BoardTest.java | 25 +++++++-- .../java/domain/ChariotMoveStrategyTest.java | 52 +++++++++++++++++++ 11 files changed, 220 insertions(+), 18 deletions(-) create mode 100644 src/main/java/domain/ChariotMoveStrategy.java create mode 100644 src/main/java/domain/MoveStrategy.java create mode 100644 src/main/java/domain/PathGenerator.java create mode 100644 src/main/java/domain/PathInfo.java create mode 100644 src/test/java/domain/ChariotMoveStrategyTest.java diff --git a/README.md b/README.md index 4656dbb28e..2e7dfea775 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,34 @@ # java-janggi -## 1.1 보드 초기화 +## 1.1 장기판 초기화 -- [x] 보드는 9행 * 10열 크기이다. (x축은 가로, y축은 세로이다.) +- [x] 장기판은 9행 * 10열 크기이다. (x축은 가로, y축은 세로이다.) - [x] x좌표는 0 이상 8 이하의 범위를 가진다. (총 9칸) - [x] y좌표는 0 이상 9 이하의 범위를 가진다. (총 10칸) - - [x] 보드의 범위를 벗어난 좌표에 접근할 경우, IllegalArgumentException을 발생시킨다. -- [x] 보드의 좌측 하단을 (0, 0)으로 정의한다. + - [x] 장기판의 범위를 벗어난 좌표에 접근할 경우, IllegalArgumentException을 발생시킨다. +- [x] 장기판의 좌측 하단을 (0, 0)으로 정의한다. --[x] 보드를 초기화한다. +- [x] 장기판을 초기화한다. - [x] 상차림에 맞도록 기물을 배치한다. - [x] 왼상차림 : 상마상마 - [x] 오른상차림 : 마상마상 - [x] 바깥상차림 : 마상상마 - [x] 안상차림 : 상마마상 + +## 1.2 기물 이동 + +- [ ] `궁`은 왼쪽, 오른쪽, 앞쪽, 뒤쪽으로 1칸씩 움직일 수 있다. + - [ ] 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. +- [ ] `사`는 왼쪽, 오른쪽, 앞쪽, 뒤쪽으로 1칸씩 움직일 수 있다. + - [ ] 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. +- [x] `차`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 할 수 있다. + - [x] 단, 다른 기물을 뛰어넘을 수는 없다. + - [x] 가로막는 기물이 있는 지점의 바로 앞까지, 혹은 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. +- [ ] `포`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 가능하지만, 반드시 기물을 한 개 뛰어넘어야만 그 방향으로 이동이 가능하다. + - [ ] 단, 포끼리는 서로 뛰어넘을 수 없다. + - [ ] 단, 포끼리는 서로 잡을 수 없다. +- [ ] `마`는 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 한 칸 더 이동한다. + - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. +- [ ] `상`은 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 두 칸 더 이동한다. + - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. +- [ ] `졸, 병`은 왼쪽, 오른쪽, 앞쪽으로 1칸씩 움직일 수 있으나, 후퇴할 수 없다. diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/Board.java index 46a4f52138..936a372039 100644 --- a/src/main/java/domain/Board.java +++ b/src/main/java/domain/Board.java @@ -1,5 +1,7 @@ package domain; +import java.util.ArrayList; +import java.util.List; import java.util.Map; public class Board { @@ -9,11 +11,39 @@ public Board(Map pieces) { this.pieces = pieces; } + public boolean isExistPieceAt(Position position) { + return pieces.containsKey(position); + } + public Piece pieceAt(Position position) { - if (!pieces.containsKey(position)) { + if (!isExistPieceAt(position)) { throw new IllegalArgumentException("해당 위치에 기물이 존재하지 않습니다."); } return pieces.get(position); } + + public void move(Position departure, Position destination) { + Piece departurePiece = pieceAt(departure); + + List positions = departurePiece.getPath(departure, destination); + + List path = new ArrayList<>(); + positions.forEach(position -> path.add(new PathInfo(position, pieceAt(position)))); + + departurePiece.validateBlockingPiece(path, departure, destination); + + if (isExistPieceAt(destination)) { + validateCapture(departurePiece, pieceAt(destination)); + } + + pieces.remove(departure); + pieces.put(destination, departurePiece); + } + + private void validateCapture(Piece departurePiece, Piece destinationPiece) { + if (departurePiece.isSameCampe(destinationPiece)) { + throw new IllegalArgumentException("같은 팀끼리는 잡을 수 없습니다."); + } + } } diff --git a/src/main/java/domain/ChariotMoveStrategy.java b/src/main/java/domain/ChariotMoveStrategy.java new file mode 100644 index 0000000000..f86adeecfa --- /dev/null +++ b/src/main/java/domain/ChariotMoveStrategy.java @@ -0,0 +1,30 @@ +package domain; + +import java.util.List; + +public class ChariotMoveStrategy implements MoveStrategy { + @Override + public List getPath(Position departure, Position destination) { + int deltaX = departure.calculateDeltaX(destination); + int deltaY = departure.calculateDeltaY(destination); + + if (deltaX != 0 && deltaY != 0) { + throw new IllegalArgumentException("차는 직선 방향으로만 이동할 수 있습니다."); + } + + Direction direction = Direction.decideDirection(deltaX, deltaY); + + return PathGenerator.generateStraightPath(departure, destination, direction); + } + + @Override + public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + boolean hasBlockingPiece = pathInfos.stream() + .filter(path -> !path.position().equals(destination)) + .anyMatch(PathInfo::hasPiece); + + if (hasBlockingPiece) { + throw new IllegalArgumentException("이동 경로에 다른 기물을 뛰어넘을 수 없습니다."); + } + } +} diff --git a/src/main/java/domain/MoveStrategy.java b/src/main/java/domain/MoveStrategy.java new file mode 100644 index 0000000000..500b0d35b5 --- /dev/null +++ b/src/main/java/domain/MoveStrategy.java @@ -0,0 +1,8 @@ +package domain; + +import java.util.List; + +public interface MoveStrategy { + List getPath(Position departure, Position destination); + void validateBlockingPiece(List pathInfos, Position departure, Position destination); +} diff --git a/src/main/java/domain/PathGenerator.java b/src/main/java/domain/PathGenerator.java new file mode 100644 index 0000000000..289c76a26a --- /dev/null +++ b/src/main/java/domain/PathGenerator.java @@ -0,0 +1,18 @@ +package domain; + +import java.util.ArrayList; +import java.util.List; + +public class PathGenerator { + public static List generateStraightPath(Position departure, Position destination, Direction direction) { + List paths = new ArrayList<>(); + + Position current = departure; + while (!current.equals(destination)) { + current = current.move(direction.getDeltaX(), direction.getDeltaY()); + paths.add(current); + } + + return paths; + } +} diff --git a/src/main/java/domain/PathInfo.java b/src/main/java/domain/PathInfo.java new file mode 100644 index 0000000000..17bff4bb21 --- /dev/null +++ b/src/main/java/domain/PathInfo.java @@ -0,0 +1,7 @@ +package domain; + +public record PathInfo(Position position, Piece piece) { + public boolean hasPiece(){ + return piece != null; + } +} diff --git a/src/main/java/domain/Piece.java b/src/main/java/domain/Piece.java index 20d2df56fc..34d14d9158 100644 --- a/src/main/java/domain/Piece.java +++ b/src/main/java/domain/Piece.java @@ -1,7 +1,21 @@ package domain; +import java.util.List; + public record Piece(Camp camp, PieceType pieceType, MoveStrategy moveStrategy) { - public static Piece of(Camp camp, PieceType pieceType){ + public static Piece of(Camp camp, PieceType pieceType) { return new Piece(camp, pieceType, pieceType.moveStrategy()); } + + public boolean isSameCampe(Piece otherPiece){ + return otherPiece.camp.equals(camp); + } + + public List getPath(Position departure, Position destination) { + return moveStrategy.getPath(departure, destination); + } + + public void validateBlockingPiece(List pathInfos, Position departure, Position destination){ + moveStrategy.validateBlockingPiece(pathInfos, departure, destination); + } } diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/PieceType.java index 72c9cc0681..0bfb069b85 100644 --- a/src/main/java/domain/PieceType.java +++ b/src/main/java/domain/PieceType.java @@ -1,16 +1,20 @@ package domain; public enum PieceType { - GENERAL, - GUARD, - CHARIOT, - CANNON, - HORSE, - ELEPHANT, - SOLDIER; + GENERAL(new ChariotMoveStrategy()), + GUARD(new ChariotMoveStrategy()), + CHARIOT(new ChariotMoveStrategy()), + CANNON(new ChariotMoveStrategy()), + HORSE(new ChariotMoveStrategy()), + ELEPHANT(new ChariotMoveStrategy()), + SOLDIER(new ChariotMoveStrategy()); private MoveStrategy moveStrategy; + PieceType(MoveStrategy moveStrategy) { + this.moveStrategy = moveStrategy; + } + public MoveStrategy moveStrategy() { return moveStrategy; } diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/Position.java index 4d48b0f641..60244813c2 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/Position.java @@ -11,6 +11,10 @@ public record Position(int column, int row) { } + public Position move(int deltaX, int deltaY) { + return new Position(this.column + deltaX, this.row + deltaY); + } + public int calculateDeltaX(Position destination) { return destination.column - this.column; } diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/BoardTest.java index b227643306..1a3552822c 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/BoardTest.java @@ -3,8 +3,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.*; class BoardTest { private Board board; @@ -15,12 +14,30 @@ void setUp() { } @Test - void 선택한_좌표에_위치한_기물을_반환한다() { + void 해당_좌표에_기물의_존재_여부를_반환한다() { + assertThat(board.isExistPieceAt(new Position(8, 0))).isTrue(); + assertThat(board.isExistPieceAt(new Position(8, 5))).isFalse(); + } + + @Test + void 해당_좌표에_위치한_기물을_반환한다() { assertThat(board.pieceAt(new Position(8, 0))).isEqualTo(Piece.of(Camp.CHO, PieceType.CHARIOT)); } @Test - void 선택한_좌표에_기물이_없을_경우_예외를_반환한다() { + void 이동을_선택한_좌표에_기물이_없을_경우_예외를_던진다() { assertThatThrownBy(() -> board.pieceAt(new Position(5, 5))).isInstanceOf(IllegalArgumentException.class); } + + @Test + void 출발지와_도착지가_같을_경우_예외를_던진다() { + assertThatThrownBy(() -> board.move(new Position(8, 0), new Position(8, 0))) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 도착지에_위치한_기물이_같은_팀의_기물일_경우_예외를_던진다() { + assertThatThrownBy(() -> board.move(new Position(8, 0), new Position(7, 0))) + .isInstanceOf(IllegalArgumentException.class); + } } diff --git a/src/test/java/domain/ChariotMoveStrategyTest.java b/src/test/java/domain/ChariotMoveStrategyTest.java new file mode 100644 index 0000000000..fcdedfb9f6 --- /dev/null +++ b/src/test/java/domain/ChariotMoveStrategyTest.java @@ -0,0 +1,52 @@ +package domain; + +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class ChariotMoveStrategyTest { + private final ChariotMoveStrategy chariotMoveStrategy = new ChariotMoveStrategy(); + + @Test + void 차는_세로_직선_방향으로_이동할_수_있다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + List path = chariotMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(8, 1), new Position(8, 2)); + } + + @Test + void 차는_가로_직선_방향으로_이동할_수_있다() { + Position from = new Position(8, 0); + Position to = new Position(6, 0); + + List path = chariotMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(7, 0), new Position(6, 0)); + } + + @Test + void 차는_대각선_방향으로_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(7, 1); + + assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 차는_경로에_다른_기물이_있으면_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); + + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + } +} From 4368531840ed6d175fb606fc70fd9d22bccf1232 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 15:05:11 +0900 Subject: [PATCH 35/58] =?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/main/java/domain/{ => board}/Board.java | 5 ++++- src/main/java/domain/{ => board}/BoardInitializer.java | 6 +++++- src/main/java/domain/{ => board}/BoardSetting.java | 8 +++++--- src/main/java/domain/{ => board}/Position.java | 2 +- src/main/java/domain/{ => path}/PathGenerator.java | 5 ++++- src/main/java/domain/{ => path}/PathInfo.java | 5 ++++- src/main/java/domain/{ => piece}/Camp.java | 2 +- src/main/java/domain/{ => piece}/ChariotMoveStrategy.java | 6 +++++- src/main/java/domain/{ => piece}/Direction.java | 2 +- src/main/java/domain/{ => piece}/MoveStrategy.java | 5 ++++- src/main/java/domain/{ => piece}/Piece.java | 5 ++++- src/main/java/domain/{ => piece}/PieceType.java | 2 +- .../java/domain/{ => board}/BoardInitializerTest.java | 5 ++++- src/test/java/domain/{ => board}/BoardTest.java | 5 ++++- src/test/java/domain/{ => board}/PositionTest.java | 2 +- .../java/domain/{ => piece}/ChariotMoveStrategyTest.java | 4 +++- src/test/java/domain/{ => piece}/DirectionTest.java | 3 ++- 17 files changed, 53 insertions(+), 19 deletions(-) rename src/main/java/domain/{ => board}/Board.java (94%) rename src/main/java/domain/{ => board}/BoardInitializer.java (97%) rename src/main/java/domain/{ => board}/BoardSetting.java (79%) rename src/main/java/domain/{ => board}/Position.java (98%) rename src/main/java/domain/{ => path}/PathGenerator.java (85%) rename src/main/java/domain/{ => path}/PathInfo.java (61%) rename src/main/java/domain/{ => piece}/Camp.java (63%) rename src/main/java/domain/{ => piece}/ChariotMoveStrategy.java (90%) rename src/main/java/domain/{ => piece}/Direction.java (98%) rename src/main/java/domain/{ => piece}/MoveStrategy.java (73%) rename src/main/java/domain/{ => piece}/Piece.java (89%) rename src/main/java/domain/{ => piece}/PieceType.java (95%) rename src/test/java/domain/{ => board}/BoardInitializerTest.java (97%) rename src/test/java/domain/{ => board}/BoardTest.java (93%) rename src/test/java/domain/{ => board}/PositionTest.java (98%) rename src/test/java/domain/{ => piece}/ChariotMoveStrategyTest.java (95%) rename src/test/java/domain/{ => piece}/DirectionTest.java (98%) diff --git a/src/main/java/domain/Board.java b/src/main/java/domain/board/Board.java similarity index 94% rename from src/main/java/domain/Board.java rename to src/main/java/domain/board/Board.java index 936a372039..1364db39e5 100644 --- a/src/main/java/domain/Board.java +++ b/src/main/java/domain/board/Board.java @@ -1,4 +1,7 @@ -package domain; +package domain.board; + +import domain.path.PathInfo; +import domain.piece.Piece; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/domain/BoardInitializer.java b/src/main/java/domain/board/BoardInitializer.java similarity index 97% rename from src/main/java/domain/BoardInitializer.java rename to src/main/java/domain/board/BoardInitializer.java index 2ce709d057..910fcee925 100644 --- a/src/main/java/domain/BoardInitializer.java +++ b/src/main/java/domain/board/BoardInitializer.java @@ -1,4 +1,8 @@ -package domain; +package domain.board; + +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/domain/BoardSetting.java b/src/main/java/domain/board/BoardSetting.java similarity index 79% rename from src/main/java/domain/BoardSetting.java rename to src/main/java/domain/board/BoardSetting.java index 486ec6dad7..27e8fb40e3 100644 --- a/src/main/java/domain/BoardSetting.java +++ b/src/main/java/domain/board/BoardSetting.java @@ -1,9 +1,11 @@ -package domain; +package domain.board; + +import domain.piece.PieceType; import java.util.List; -import static domain.PieceType.ELEPHANT; -import static domain.PieceType.HORSE; +import static domain.piece.PieceType.ELEPHANT; +import static domain.piece.PieceType.HORSE; public enum BoardSetting { LEFT_ELEPHANT_SET_UP(List.of(ELEPHANT, HORSE, ELEPHANT, HORSE)), diff --git a/src/main/java/domain/Position.java b/src/main/java/domain/board/Position.java similarity index 98% rename from src/main/java/domain/Position.java rename to src/main/java/domain/board/Position.java index 60244813c2..f04c9c33d8 100644 --- a/src/main/java/domain/Position.java +++ b/src/main/java/domain/board/Position.java @@ -1,4 +1,4 @@ -package domain; +package domain.board; public record Position(int column, int row) { private static final int MIN_POSITION = 0; diff --git a/src/main/java/domain/PathGenerator.java b/src/main/java/domain/path/PathGenerator.java similarity index 85% rename from src/main/java/domain/PathGenerator.java rename to src/main/java/domain/path/PathGenerator.java index 289c76a26a..f422f9255d 100644 --- a/src/main/java/domain/PathGenerator.java +++ b/src/main/java/domain/path/PathGenerator.java @@ -1,4 +1,7 @@ -package domain; +package domain.path; + +import domain.board.Position; +import domain.piece.Direction; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/domain/PathInfo.java b/src/main/java/domain/path/PathInfo.java similarity index 61% rename from src/main/java/domain/PathInfo.java rename to src/main/java/domain/path/PathInfo.java index 17bff4bb21..a18e76139b 100644 --- a/src/main/java/domain/PathInfo.java +++ b/src/main/java/domain/path/PathInfo.java @@ -1,4 +1,7 @@ -package domain; +package domain.path; + +import domain.board.Position; +import domain.piece.Piece; public record PathInfo(Position position, Piece piece) { public boolean hasPiece(){ diff --git a/src/main/java/domain/Camp.java b/src/main/java/domain/piece/Camp.java similarity index 63% rename from src/main/java/domain/Camp.java rename to src/main/java/domain/piece/Camp.java index b942e3e06a..ffdb3e8a6b 100644 --- a/src/main/java/domain/Camp.java +++ b/src/main/java/domain/piece/Camp.java @@ -1,4 +1,4 @@ -package domain; +package domain.piece; public enum Camp { CHO, diff --git a/src/main/java/domain/ChariotMoveStrategy.java b/src/main/java/domain/piece/ChariotMoveStrategy.java similarity index 90% rename from src/main/java/domain/ChariotMoveStrategy.java rename to src/main/java/domain/piece/ChariotMoveStrategy.java index f86adeecfa..cde51194ad 100644 --- a/src/main/java/domain/ChariotMoveStrategy.java +++ b/src/main/java/domain/piece/ChariotMoveStrategy.java @@ -1,4 +1,8 @@ -package domain; +package domain.piece; + +import domain.path.PathGenerator; +import domain.path.PathInfo; +import domain.board.Position; import java.util.List; diff --git a/src/main/java/domain/Direction.java b/src/main/java/domain/piece/Direction.java similarity index 98% rename from src/main/java/domain/Direction.java rename to src/main/java/domain/piece/Direction.java index ccf6cbb7d6..1cdd32e51e 100644 --- a/src/main/java/domain/Direction.java +++ b/src/main/java/domain/piece/Direction.java @@ -1,4 +1,4 @@ -package domain; +package domain.piece; public enum Direction { UP(0, 1), diff --git a/src/main/java/domain/MoveStrategy.java b/src/main/java/domain/piece/MoveStrategy.java similarity index 73% rename from src/main/java/domain/MoveStrategy.java rename to src/main/java/domain/piece/MoveStrategy.java index 500b0d35b5..036369b225 100644 --- a/src/main/java/domain/MoveStrategy.java +++ b/src/main/java/domain/piece/MoveStrategy.java @@ -1,4 +1,7 @@ -package domain; +package domain.piece; + +import domain.path.PathInfo; +import domain.board.Position; import java.util.List; diff --git a/src/main/java/domain/Piece.java b/src/main/java/domain/piece/Piece.java similarity index 89% rename from src/main/java/domain/Piece.java rename to src/main/java/domain/piece/Piece.java index 34d14d9158..bdbbc063df 100644 --- a/src/main/java/domain/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -1,4 +1,7 @@ -package domain; +package domain.piece; + +import domain.path.PathInfo; +import domain.board.Position; import java.util.List; diff --git a/src/main/java/domain/PieceType.java b/src/main/java/domain/piece/PieceType.java similarity index 95% rename from src/main/java/domain/PieceType.java rename to src/main/java/domain/piece/PieceType.java index 0bfb069b85..7c3cf5b1da 100644 --- a/src/main/java/domain/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,4 +1,4 @@ -package domain; +package domain.piece; public enum PieceType { GENERAL(new ChariotMoveStrategy()), diff --git a/src/test/java/domain/BoardInitializerTest.java b/src/test/java/domain/board/BoardInitializerTest.java similarity index 97% rename from src/test/java/domain/BoardInitializerTest.java rename to src/test/java/domain/board/BoardInitializerTest.java index bcbf547a50..b72093e7a6 100644 --- a/src/test/java/domain/BoardInitializerTest.java +++ b/src/test/java/domain/board/BoardInitializerTest.java @@ -1,5 +1,8 @@ -package domain; +package domain.board; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; diff --git a/src/test/java/domain/BoardTest.java b/src/test/java/domain/board/BoardTest.java similarity index 93% rename from src/test/java/domain/BoardTest.java rename to src/test/java/domain/board/BoardTest.java index 1a3552822c..4297ce1caf 100644 --- a/src/test/java/domain/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -1,5 +1,8 @@ -package domain; +package domain.board; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/domain/PositionTest.java b/src/test/java/domain/board/PositionTest.java similarity index 98% rename from src/test/java/domain/PositionTest.java rename to src/test/java/domain/board/PositionTest.java index 9f7e94c9da..965a82c427 100644 --- a/src/test/java/domain/PositionTest.java +++ b/src/test/java/domain/board/PositionTest.java @@ -1,4 +1,4 @@ -package domain; +package domain.board; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; diff --git a/src/test/java/domain/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/ChariotMoveStrategyTest.java similarity index 95% rename from src/test/java/domain/ChariotMoveStrategyTest.java rename to src/test/java/domain/piece/ChariotMoveStrategyTest.java index fcdedfb9f6..0c27ca621d 100644 --- a/src/test/java/domain/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/ChariotMoveStrategyTest.java @@ -1,5 +1,7 @@ -package domain; +package domain.piece; +import domain.board.Position; +import domain.path.PathInfo; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/src/test/java/domain/DirectionTest.java b/src/test/java/domain/piece/DirectionTest.java similarity index 98% rename from src/test/java/domain/DirectionTest.java rename to src/test/java/domain/piece/DirectionTest.java index 80e4dfe1a6..7b52da200b 100644 --- a/src/test/java/domain/DirectionTest.java +++ b/src/test/java/domain/piece/DirectionTest.java @@ -1,5 +1,6 @@ -package domain; +package domain.piece; +import domain.board.Position; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 0637768f943609d2cfe6a9eb6ab7b23911c9b462 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 15:34:55 +0900 Subject: [PATCH 36/58] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=ED=8F=AC=EB=A7=B7=ED=8C=85=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/Board.java | 6 +++--- src/main/java/domain/board/Position.java | 1 - src/main/java/domain/piece/Piece.java | 5 +++-- src/main/java/domain/piece/PieceType.java | 3 +++ .../domain/piece/{ => strategy}/ChariotMoveStrategy.java | 3 ++- src/main/java/domain/piece/{ => strategy}/MoveStrategy.java | 2 +- src/test/java/domain/board/PositionTest.java | 5 +++-- src/test/java/domain/piece/ChariotMoveStrategyTest.java | 1 + 8 files changed, 16 insertions(+), 10 deletions(-) rename src/main/java/domain/piece/{ => strategy}/ChariotMoveStrategy.java (95%) rename src/main/java/domain/piece/{ => strategy}/MoveStrategy.java (90%) diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index 1364db39e5..dbd0d644b9 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -29,10 +29,10 @@ public Piece pieceAt(Position position) { public void move(Position departure, Position destination) { Piece departurePiece = pieceAt(departure); - List positions = departurePiece.getPath(departure, destination); - List path = new ArrayList<>(); - positions.forEach(position -> path.add(new PathInfo(position, pieceAt(position)))); + for (Position position : departurePiece.getPath(departure, destination)) { + path.add(new PathInfo(position, pieceAt(position))); + } departurePiece.validateBlockingPiece(path, departure, destination); diff --git a/src/main/java/domain/board/Position.java b/src/main/java/domain/board/Position.java index f04c9c33d8..77bec94338 100644 --- a/src/main/java/domain/board/Position.java +++ b/src/main/java/domain/board/Position.java @@ -8,7 +8,6 @@ public record Position(int column, int row) { public Position { validateColumn(column); validateRow(row); - } public Position move(int deltaX, int deltaY) { diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index bdbbc063df..97c7021c1b 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -2,6 +2,7 @@ import domain.path.PathInfo; import domain.board.Position; +import domain.piece.strategy.MoveStrategy; import java.util.List; @@ -10,7 +11,7 @@ public static Piece of(Camp camp, PieceType pieceType) { return new Piece(camp, pieceType, pieceType.moveStrategy()); } - public boolean isSameCampe(Piece otherPiece){ + public boolean isSameCampe(Piece otherPiece) { return otherPiece.camp.equals(camp); } @@ -18,7 +19,7 @@ public List getPath(Position departure, Position destination) { return moveStrategy.getPath(departure, destination); } - public void validateBlockingPiece(List pathInfos, Position departure, Position destination){ + public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { moveStrategy.validateBlockingPiece(pathInfos, departure, destination); } } diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 7c3cf5b1da..64429ac859 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,5 +1,8 @@ package domain.piece; +import domain.piece.strategy.ChariotMoveStrategy; +import domain.piece.strategy.MoveStrategy; + public enum PieceType { GENERAL(new ChariotMoveStrategy()), GUARD(new ChariotMoveStrategy()), diff --git a/src/main/java/domain/piece/ChariotMoveStrategy.java b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java similarity index 95% rename from src/main/java/domain/piece/ChariotMoveStrategy.java rename to src/main/java/domain/piece/strategy/ChariotMoveStrategy.java index cde51194ad..9fbf86d78b 100644 --- a/src/main/java/domain/piece/ChariotMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java @@ -1,8 +1,9 @@ -package domain.piece; +package domain.piece.strategy; import domain.path.PathGenerator; import domain.path.PathInfo; import domain.board.Position; +import domain.piece.Direction; import java.util.List; diff --git a/src/main/java/domain/piece/MoveStrategy.java b/src/main/java/domain/piece/strategy/MoveStrategy.java similarity index 90% rename from src/main/java/domain/piece/MoveStrategy.java rename to src/main/java/domain/piece/strategy/MoveStrategy.java index 036369b225..1181d4b546 100644 --- a/src/main/java/domain/piece/MoveStrategy.java +++ b/src/main/java/domain/piece/strategy/MoveStrategy.java @@ -1,4 +1,4 @@ -package domain.piece; +package domain.piece.strategy; import domain.path.PathInfo; import domain.board.Position; diff --git a/src/test/java/domain/board/PositionTest.java b/src/test/java/domain/board/PositionTest.java index 965a82c427..be19407837 100644 --- a/src/test/java/domain/board/PositionTest.java +++ b/src/test/java/domain/board/PositionTest.java @@ -2,6 +2,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -41,12 +42,12 @@ class 좌표_차이_계산_테스트 { @Test void 두_좌표의_x_증가량을_계산한다() { - assertThat(position.calculateDeltaX(new Position(1,0))).isEqualTo(1); + assertThat(position.calculateDeltaX(new Position(1, 0))).isEqualTo(1); } @Test void 두_좌표의_y_증가량을_계산한다() { - assertThat(position.calculateDeltaY(new Position(0,1))).isEqualTo(1); + assertThat(position.calculateDeltaY(new Position(0, 1))).isEqualTo(1); } } diff --git a/src/test/java/domain/piece/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/ChariotMoveStrategyTest.java index 0c27ca621d..1e90e5fc07 100644 --- a/src/test/java/domain/piece/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/ChariotMoveStrategyTest.java @@ -2,6 +2,7 @@ import domain.board.Position; import domain.path.PathInfo; +import domain.piece.strategy.ChariotMoveStrategy; import org.junit.jupiter.api.Test; import java.util.ArrayList; From d9c59fc26c1b6017f016bffb11a19132e3083f95 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 15:55:52 +0900 Subject: [PATCH 37/58] =?UTF-8?q?feat(MoveStrategy):=20=EA=B6=81/=EC=82=AC?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99=20=EB=A1=9C=EC=A7=81=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/piece/PieceType.java | 5 +- .../piece/strategy/GeneralMoveStrategy.java | 39 ++++++++++++++ .../domain/piece/ChariotMoveStrategyTest.java | 3 +- .../domain/piece/GeneralMoveStrategyTest.java | 51 +++++++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 src/main/java/domain/piece/strategy/GeneralMoveStrategy.java create mode 100644 src/test/java/domain/piece/GeneralMoveStrategyTest.java diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 64429ac859..1d729d00cb 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,11 +1,12 @@ package domain.piece; import domain.piece.strategy.ChariotMoveStrategy; +import domain.piece.strategy.GeneralMoveStrategy; import domain.piece.strategy.MoveStrategy; public enum PieceType { - GENERAL(new ChariotMoveStrategy()), - GUARD(new ChariotMoveStrategy()), + GENERAL(new GeneralMoveStrategy()), + GUARD(new GeneralMoveStrategy()), CHARIOT(new ChariotMoveStrategy()), CANNON(new ChariotMoveStrategy()), HORSE(new ChariotMoveStrategy()), diff --git a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java new file mode 100644 index 0000000000..22ccadcff8 --- /dev/null +++ b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java @@ -0,0 +1,39 @@ +package domain.piece.strategy; + +import domain.board.Position; +import domain.path.PathGenerator; +import domain.path.PathInfo; +import domain.piece.Direction; + +import java.util.List; + +public class GeneralMoveStrategy implements MoveStrategy { + @Override + public List getPath(Position departure, Position destination) { + int deltaX = departure.calculateDeltaX(destination); + int deltaY = departure.calculateDeltaY(destination); + + if (deltaX != 0 && deltaY != 0) { + throw new IllegalArgumentException("궁/사는 직선 방향으로만 이동할 수 있습니다."); + } + + if (deltaX > 1 || deltaY > 1) { + throw new IllegalArgumentException("궁/사는 직선 방향으로 한 칸만 이동 가능합니다."); + } + + Direction direction = Direction.decideDirection(deltaX, deltaY); + + return PathGenerator.generateStraightPath(departure, destination, direction); + } + + @Override + public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + boolean hasBlockingPiece = pathInfos.stream() + .filter(path -> !path.position().equals(destination)) + .anyMatch(PathInfo::hasPiece); + + if (hasBlockingPiece) { + throw new IllegalArgumentException("이동 경로에 다른 기물을 뛰어넘을 수 없습니다."); + } + } +} diff --git a/src/test/java/domain/piece/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/ChariotMoveStrategyTest.java index 1e90e5fc07..f57ab02182 100644 --- a/src/test/java/domain/piece/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/ChariotMoveStrategyTest.java @@ -3,6 +3,7 @@ import domain.board.Position; import domain.path.PathInfo; import domain.piece.strategy.ChariotMoveStrategy; +import domain.piece.strategy.MoveStrategy; import org.junit.jupiter.api.Test; import java.util.ArrayList; @@ -12,7 +13,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; class ChariotMoveStrategyTest { - private final ChariotMoveStrategy chariotMoveStrategy = new ChariotMoveStrategy(); + private final MoveStrategy chariotMoveStrategy = new ChariotMoveStrategy(); @Test void 차는_세로_직선_방향으로_이동할_수_있다() { diff --git a/src/test/java/domain/piece/GeneralMoveStrategyTest.java b/src/test/java/domain/piece/GeneralMoveStrategyTest.java new file mode 100644 index 0000000000..a8f58c4ee8 --- /dev/null +++ b/src/test/java/domain/piece/GeneralMoveStrategyTest.java @@ -0,0 +1,51 @@ +package domain.piece; + +import domain.board.Position; +import domain.piece.strategy.GeneralMoveStrategy; +import domain.piece.strategy.MoveStrategy; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class GeneralMoveStrategyTest { + private final MoveStrategy generalMoveStrategy = new GeneralMoveStrategy(); + + @Test + void 궁과_사는_두_칸_이상_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + assertThatThrownBy(() -> generalMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 궁과_사는_세로_직선_방향으로_한_칸_이동할_수_있다() { + Position from = new Position(8, 0); + Position to = new Position(8, 1); + + List path = generalMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(8, 1)); + } + + @Test + void 궁과_사는_가로_직선_방향으로_한_칸_이동할_수_있다() { + Position from = new Position(8, 0); + Position to = new Position(7, 0); + + List path = generalMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(7, 0)); + } + + @Test + void 궁과_사는_대각선_방향으로_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(7, 1); + + assertThatThrownBy(() -> generalMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } +} From 4087a05435ffdc8d726b093d7daf753ac127af29 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 16:20:34 +0900 Subject: [PATCH 38/58] =?UTF-8?q?feat(MoveStrategy):=20=ED=8F=AC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EB=A1=9C=EC=A7=81=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/Board.java | 4 +- src/main/java/domain/path/PathInfo.java | 5 ++ src/main/java/domain/piece/Piece.java | 6 +- src/main/java/domain/piece/PieceType.java | 5 +- .../piece/strategy/CannonMoveStrategy.java | 32 ++++++++ src/test/java/domain/board/BoardTest.java | 2 +- .../domain/piece/CannonMoveStrategyTest.java | 79 +++++++++++++++++++ .../domain/piece/ChariotMoveStrategyTest.java | 4 +- src/test/java/domain/piece/DirectionTest.java | 1 - .../domain/piece/GeneralMoveStrategyTest.java | 4 +- 10 files changed, 131 insertions(+), 11 deletions(-) create mode 100644 src/main/java/domain/piece/strategy/CannonMoveStrategy.java create mode 100644 src/test/java/domain/piece/CannonMoveStrategyTest.java diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index dbd0d644b9..c1e0970666 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -45,8 +45,8 @@ public void move(Position departure, Position destination) { } private void validateCapture(Piece departurePiece, Piece destinationPiece) { - if (departurePiece.isSameCampe(destinationPiece)) { - throw new IllegalArgumentException("같은 팀끼리는 잡을 수 없습니다."); + if (departurePiece.isSameCamp(destinationPiece)) { + throw new IllegalArgumentException("같은 진영의 기물은 잡을 수 없습니다."); } } } diff --git a/src/main/java/domain/path/PathInfo.java b/src/main/java/domain/path/PathInfo.java index a18e76139b..526993bf84 100644 --- a/src/main/java/domain/path/PathInfo.java +++ b/src/main/java/domain/path/PathInfo.java @@ -2,9 +2,14 @@ import domain.board.Position; import domain.piece.Piece; +import domain.piece.PieceType; public record PathInfo(Position position, Piece piece) { public boolean hasPiece(){ return piece != null; } + + public boolean isSamePieceType(PieceType pieceType){ + return piece.isSameType(pieceType); + } } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index 97c7021c1b..d1de73cd8e 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -11,10 +11,14 @@ public static Piece of(Camp camp, PieceType pieceType) { return new Piece(camp, pieceType, pieceType.moveStrategy()); } - public boolean isSameCampe(Piece otherPiece) { + public boolean isSameCamp(Piece otherPiece) { return otherPiece.camp.equals(camp); } + public boolean isSameType(PieceType otherPieceType) { + return pieceType.equals(otherPieceType); + } + public List getPath(Position departure, Position destination) { return moveStrategy.getPath(departure, destination); } diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 1d729d00cb..78ea08133d 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,5 +1,6 @@ package domain.piece; +import domain.piece.strategy.CannonMoveStrategy; import domain.piece.strategy.ChariotMoveStrategy; import domain.piece.strategy.GeneralMoveStrategy; import domain.piece.strategy.MoveStrategy; @@ -8,12 +9,12 @@ public enum PieceType { GENERAL(new GeneralMoveStrategy()), GUARD(new GeneralMoveStrategy()), CHARIOT(new ChariotMoveStrategy()), - CANNON(new ChariotMoveStrategy()), + CANNON(new CannonMoveStrategy()), HORSE(new ChariotMoveStrategy()), ELEPHANT(new ChariotMoveStrategy()), SOLDIER(new ChariotMoveStrategy()); - private MoveStrategy moveStrategy; + private final MoveStrategy moveStrategy; PieceType(MoveStrategy moveStrategy) { this.moveStrategy = moveStrategy; diff --git a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java new file mode 100644 index 0000000000..0e8aa1efab --- /dev/null +++ b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java @@ -0,0 +1,32 @@ +package domain.piece.strategy; + +import domain.board.Position; +import domain.path.PathGenerator; +import domain.path.PathInfo; +import domain.piece.Direction; +import domain.piece.PieceType; + +import java.util.List; + +public class CannonMoveStrategy implements MoveStrategy { + @Override + public List getPath(Position departure, Position destination) { + int deltaX = departure.calculateDeltaX(destination); + int deltaY = departure.calculateDeltaY(destination); + + if (deltaX != 0 && deltaY != 0) { + throw new IllegalArgumentException("포는 직선 방향으로만 이동할 수 있습니다."); + } + + Direction direction = Direction.decideDirection(deltaX, deltaY); + + return PathGenerator.generateStraightPath(departure, destination, direction); + } + + @Override + public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + if (pathInfos.stream().anyMatch(path -> path.isSamePieceType(PieceType.CANNON))) { + throw new IllegalArgumentException("포는 포를 넘거나 잡을 수 없습니다."); + } + } +} diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index 4297ce1caf..8aeec220d8 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -39,7 +39,7 @@ void setUp() { } @Test - void 도착지에_위치한_기물이_같은_팀의_기물일_경우_예외를_던진다() { + void 도착지에_위치한_기물이_같은_진영의_기물일_경우_예외를_던진다() { assertThatThrownBy(() -> board.move(new Position(8, 0), new Position(7, 0))) .isInstanceOf(IllegalArgumentException.class); } diff --git a/src/test/java/domain/piece/CannonMoveStrategyTest.java b/src/test/java/domain/piece/CannonMoveStrategyTest.java new file mode 100644 index 0000000000..83aff8b584 --- /dev/null +++ b/src/test/java/domain/piece/CannonMoveStrategyTest.java @@ -0,0 +1,79 @@ +package domain.piece; + +import domain.board.Position; +import domain.path.PathInfo; +import domain.piece.strategy.ChariotMoveStrategy; +import domain.piece.strategy.MoveStrategy; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CannonMoveStrategyTest { + private final MoveStrategy chariotMoveStrategy = new ChariotMoveStrategy(); + + @Test + void 포는_세로_직선_방향의_이동_경로를_가진다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + List path = chariotMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(8, 1), new Position(8, 2)); + } + + @Test + void 포는_가로_직선_방향의_이동_경로를_가진다() { + Position from = new Position(8, 0); + Position to = new Position(6, 0); + + List path = chariotMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(7, 0), new Position(6, 0)); + } + + @Test + void 포는_대각선_방향으로_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(7, 1); + + assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 포는_경로에_다른_기물이_없으면_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); + + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 포는_포를_잡을_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CANNON))); + + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 포는_포를_넘을_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CANNON))); + pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); + + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + } +} diff --git a/src/test/java/domain/piece/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/ChariotMoveStrategyTest.java index f57ab02182..e130972ec3 100644 --- a/src/test/java/domain/piece/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/ChariotMoveStrategyTest.java @@ -16,7 +16,7 @@ class ChariotMoveStrategyTest { private final MoveStrategy chariotMoveStrategy = new ChariotMoveStrategy(); @Test - void 차는_세로_직선_방향으로_이동할_수_있다() { + void 차는_세로_직선_방향의_이동_경로를_가진다() { Position from = new Position(8, 0); Position to = new Position(8, 2); @@ -26,7 +26,7 @@ class ChariotMoveStrategyTest { } @Test - void 차는_가로_직선_방향으로_이동할_수_있다() { + void 차는_가로_직선_방향의_이동_경로를_가진다() { Position from = new Position(8, 0); Position to = new Position(6, 0); diff --git a/src/test/java/domain/piece/DirectionTest.java b/src/test/java/domain/piece/DirectionTest.java index 7b52da200b..0c1fcb210a 100644 --- a/src/test/java/domain/piece/DirectionTest.java +++ b/src/test/java/domain/piece/DirectionTest.java @@ -86,5 +86,4 @@ void setUp() { departure.calculateDeltaY(destination))).isInstanceOf(IllegalArgumentException.class); } - } diff --git a/src/test/java/domain/piece/GeneralMoveStrategyTest.java b/src/test/java/domain/piece/GeneralMoveStrategyTest.java index a8f58c4ee8..b27a6b938a 100644 --- a/src/test/java/domain/piece/GeneralMoveStrategyTest.java +++ b/src/test/java/domain/piece/GeneralMoveStrategyTest.java @@ -22,7 +22,7 @@ class GeneralMoveStrategyTest { } @Test - void 궁과_사는_세로_직선_방향으로_한_칸_이동할_수_있다() { + void 궁과_사는_세로_직선_방향으로_한_칸_이동하는_경로를_가진다() { Position from = new Position(8, 0); Position to = new Position(8, 1); @@ -32,7 +32,7 @@ class GeneralMoveStrategyTest { } @Test - void 궁과_사는_가로_직선_방향으로_한_칸_이동할_수_있다() { + void 궁과_사는_가로_직선_방향으로_한_칸_이동하는_경로를_가진다() { Position from = new Position(8, 0); Position to = new Position(7, 0); From 6d434a033cfe1e34752c8d77f7e2b4b3e60fd296 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 21:54:26 +0900 Subject: [PATCH 39/58] =?UTF-8?q?feat(MoveStrategy):=20=EC=A1=B8/=EB=B3=91?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 ++--- src/main/java/domain/piece/Camp.java | 14 ++++- src/main/java/domain/piece/Piece.java | 26 +++++++- src/main/java/domain/piece/PieceType.java | 32 +++++----- .../piece/strategy/ChariotMoveStrategy.java | 2 +- .../piece/strategy/GeneralMoveStrategy.java | 2 +- .../piece/strategy/SoldierMoveStrategy.java | 50 ++++++++++++++++ .../CannonMoveStrategyTest.java | 7 ++- .../ChariotMoveStrategyTest.java | 7 ++- .../GeneralMoveStrategyTest.java | 4 +- .../strategy/SoldierMoveStrategyTest.java | 59 +++++++++++++++++++ 11 files changed, 180 insertions(+), 39 deletions(-) create mode 100644 src/main/java/domain/piece/strategy/SoldierMoveStrategy.java rename src/test/java/domain/piece/{ => strategy}/CannonMoveStrategyTest.java (96%) rename src/test/java/domain/piece/{ => strategy}/ChariotMoveStrategyTest.java (94%) rename src/test/java/domain/piece/{ => strategy}/GeneralMoveStrategyTest.java (93%) create mode 100644 src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java diff --git a/README.md b/README.md index 2e7dfea775..b73fab2c24 100644 --- a/README.md +++ b/README.md @@ -17,18 +17,18 @@ ## 1.2 기물 이동 -- [ ] `궁`은 왼쪽, 오른쪽, 앞쪽, 뒤쪽으로 1칸씩 움직일 수 있다. - - [ ] 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. -- [ ] `사`는 왼쪽, 오른쪽, 앞쪽, 뒤쪽으로 1칸씩 움직일 수 있다. - - [ ] 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. +- [x] `궁`은 왼쪽, 오른쪽, 앞쪽, 뒤쪽으로 1칸씩 움직일 수 있다. + - [x] 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. +- [x] `사`는 왼쪽, 오른쪽, 앞쪽, 뒤쪽으로 1칸씩 움직일 수 있다. + - [x] 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. - [x] `차`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 할 수 있다. - [x] 단, 다른 기물을 뛰어넘을 수는 없다. - [x] 가로막는 기물이 있는 지점의 바로 앞까지, 혹은 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. -- [ ] `포`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 가능하지만, 반드시 기물을 한 개 뛰어넘어야만 그 방향으로 이동이 가능하다. - - [ ] 단, 포끼리는 서로 뛰어넘을 수 없다. - - [ ] 단, 포끼리는 서로 잡을 수 없다. +- [x] `포`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 가능하지만, 반드시 기물을 한 개 뛰어넘어야만 그 방향으로 이동이 가능하다. + - [x] 단, 포끼리는 서로 뛰어넘을 수 없다. + - [x] 단, 포끼리는 서로 잡을 수 없다. - [ ] `마`는 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 한 칸 더 이동한다. - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. - [ ] `상`은 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 두 칸 더 이동한다. - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. -- [ ] `졸, 병`은 왼쪽, 오른쪽, 앞쪽으로 1칸씩 움직일 수 있으나, 후퇴할 수 없다. +- [x] `졸, 병`은 왼쪽, 오른쪽, 앞쪽으로 1칸씩 움직일 수 있으나, 후퇴할 수 없다. diff --git a/src/main/java/domain/piece/Camp.java b/src/main/java/domain/piece/Camp.java index ffdb3e8a6b..0204e2b17a 100644 --- a/src/main/java/domain/piece/Camp.java +++ b/src/main/java/domain/piece/Camp.java @@ -1,6 +1,16 @@ package domain.piece; public enum Camp { - CHO, - HAN + CHO(Direction.UP), + HAN(Direction.DOWN); + + private final Direction forwardDirection; + + Camp(Direction forwardDirection) { + this.forwardDirection = forwardDirection; + } + + public Direction getForwardDirection() { + return forwardDirection; + } } diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index d1de73cd8e..deb2cada62 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -5,10 +5,21 @@ import domain.piece.strategy.MoveStrategy; import java.util.List; +import java.util.Objects; + +public class Piece { + private final Camp camp; + private final PieceType pieceType; + private final MoveStrategy moveStrategy; + + public Piece(Camp camp, PieceType pieceType, MoveStrategy moveStrategy) { + this.camp = camp; + this.pieceType = pieceType; + this.moveStrategy = moveStrategy; + } -public record Piece(Camp camp, PieceType pieceType, MoveStrategy moveStrategy) { public static Piece of(Camp camp, PieceType pieceType) { - return new Piece(camp, pieceType, pieceType.moveStrategy()); + return new Piece(camp, pieceType, pieceType.moveStrategy(camp)); } public boolean isSameCamp(Piece otherPiece) { @@ -26,4 +37,15 @@ public List getPath(Position departure, Position destination) { public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { moveStrategy.validateBlockingPiece(pathInfos, departure, destination); } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Piece piece)) return false; + return camp == piece.camp && pieceType == piece.pieceType; + } + + @Override + public int hashCode() { + return Objects.hash(camp, pieceType); + } } diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 78ea08133d..6f46b396e2 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -1,26 +1,26 @@ package domain.piece; -import domain.piece.strategy.CannonMoveStrategy; -import domain.piece.strategy.ChariotMoveStrategy; -import domain.piece.strategy.GeneralMoveStrategy; -import domain.piece.strategy.MoveStrategy; +import domain.piece.strategy.*; + +import java.util.List; +import java.util.function.Function; public enum PieceType { - GENERAL(new GeneralMoveStrategy()), - GUARD(new GeneralMoveStrategy()), - CHARIOT(new ChariotMoveStrategy()), - CANNON(new CannonMoveStrategy()), - HORSE(new ChariotMoveStrategy()), - ELEPHANT(new ChariotMoveStrategy()), - SOLDIER(new ChariotMoveStrategy()); + GENERAL(camp -> new GeneralMoveStrategy()), + GUARD(camp -> new GeneralMoveStrategy()), + CHARIOT(camp -> new ChariotMoveStrategy()), + CANNON(camp -> new CannonMoveStrategy()), + HORSE(camp -> new ChariotMoveStrategy()), + ELEPHANT(camp -> new ChariotMoveStrategy()), + SOLDIER(camp -> new SoldierMoveStrategy(camp.getForwardDirection())); - private final MoveStrategy moveStrategy; + private final Function strategyFactory; - PieceType(MoveStrategy moveStrategy) { - this.moveStrategy = moveStrategy; + PieceType(Function strategyFactory) { + this.strategyFactory = strategyFactory; } - public MoveStrategy moveStrategy() { - return moveStrategy; + public MoveStrategy moveStrategy(Camp camp) { + return strategyFactory.apply(camp); } } diff --git a/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java index 9fbf86d78b..400bd3dc83 100644 --- a/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java @@ -29,7 +29,7 @@ public void validateBlockingPiece(List pathInfos, Position departure, .anyMatch(PathInfo::hasPiece); if (hasBlockingPiece) { - throw new IllegalArgumentException("이동 경로에 다른 기물을 뛰어넘을 수 없습니다."); + throw new IllegalArgumentException("이동 경로에 있는 다른 기물을 뛰어넘을 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java index 22ccadcff8..42a23061bc 100644 --- a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java @@ -33,7 +33,7 @@ public void validateBlockingPiece(List pathInfos, Position departure, .anyMatch(PathInfo::hasPiece); if (hasBlockingPiece) { - throw new IllegalArgumentException("이동 경로에 다른 기물을 뛰어넘을 수 없습니다."); + throw new IllegalArgumentException("이동 경로에 있는 다른 기물을 뛰어넘을 수 없습니다."); } } } diff --git a/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java b/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java new file mode 100644 index 0000000000..6773c595d2 --- /dev/null +++ b/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java @@ -0,0 +1,50 @@ +package domain.piece.strategy; + +import domain.board.Position; +import domain.path.PathGenerator; +import domain.path.PathInfo; +import domain.piece.Direction; + +import java.util.List; + +public class SoldierMoveStrategy implements MoveStrategy { + private final Direction forwardDirection; + + public SoldierMoveStrategy(Direction forwardDirection) { + this.forwardDirection = forwardDirection; + } + + @Override + public List getPath(Position departure, Position destination) { + int deltaX = departure.calculateDeltaX(destination); + int deltaY = departure.calculateDeltaY(destination); + + if (deltaX != 0 && deltaY != 0) { + throw new IllegalArgumentException("졸/병은 직선 방향으로만 이동할 수 있습니다."); + } + + if (deltaX > 1 || deltaY > 1) { + throw new IllegalArgumentException("졸/병은 직선 방향으로 한 칸만 이동 가능합니다."); + } + + Direction direction = Direction.decideDirection(deltaX, deltaY); + List allowedDirections = List.of(Direction.LEFT, Direction.RIGHT, forwardDirection); + + if (!allowedDirections.contains(direction)) { + throw new IllegalArgumentException("졸/병은 후퇴할 수 없습니다."); + } + + return PathGenerator.generateStraightPath(departure, destination, direction); + } + + @Override + public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + boolean hasBlockingPiece = pathInfos.stream() + .filter(path -> !path.position().equals(destination)) + .anyMatch(PathInfo::hasPiece); + + if (hasBlockingPiece) { + throw new IllegalArgumentException("이동 경로에 있는 다른 기물을 뛰어넘을 수 없습니다."); + } + } +} diff --git a/src/test/java/domain/piece/CannonMoveStrategyTest.java b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java similarity index 96% rename from src/test/java/domain/piece/CannonMoveStrategyTest.java rename to src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java index 83aff8b584..d4e021eecc 100644 --- a/src/test/java/domain/piece/CannonMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java @@ -1,9 +1,10 @@ -package domain.piece; +package domain.piece.strategy; import domain.board.Position; import domain.path.PathInfo; -import domain.piece.strategy.ChariotMoveStrategy; -import domain.piece.strategy.MoveStrategy; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/src/test/java/domain/piece/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java similarity index 94% rename from src/test/java/domain/piece/ChariotMoveStrategyTest.java rename to src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java index e130972ec3..b4e7856637 100644 --- a/src/test/java/domain/piece/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java @@ -1,9 +1,10 @@ -package domain.piece; +package domain.piece.strategy; import domain.board.Position; import domain.path.PathInfo; -import domain.piece.strategy.ChariotMoveStrategy; -import domain.piece.strategy.MoveStrategy; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/src/test/java/domain/piece/GeneralMoveStrategyTest.java b/src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java similarity index 93% rename from src/test/java/domain/piece/GeneralMoveStrategyTest.java rename to src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java index b27a6b938a..0a588a6cad 100644 --- a/src/test/java/domain/piece/GeneralMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java @@ -1,8 +1,6 @@ -package domain.piece; +package domain.piece.strategy; import domain.board.Position; -import domain.piece.strategy.GeneralMoveStrategy; -import domain.piece.strategy.MoveStrategy; import org.junit.jupiter.api.Test; import java.util.List; diff --git a/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java b/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java new file mode 100644 index 0000000000..b6da7686fb --- /dev/null +++ b/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java @@ -0,0 +1,59 @@ +package domain.piece.strategy; + +import domain.board.Position; +import domain.piece.Camp; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class SoldierMoveStrategyTest { + private final MoveStrategy soldierMoveStrategy = new SoldierMoveStrategy(Camp.CHO.getForwardDirection()); + + @Test + void 졸은_두_칸_이상_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 졸은_세로_직선_방향으로_한_칸_이동하는_경로를_가진다() { + Position from = new Position(8, 0); + Position to = new Position(8, 1); + + List path = soldierMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(8, 1)); + } + + @Test + void 졸은_가로_직선_방향으로_한_칸_이동하는_경로를_가진다() { + Position from = new Position(8, 0); + Position to = new Position(7, 0); + + List path = soldierMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly(new Position(7, 0)); + } + + @Test + void 졸은_대각선_방향으로_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(7, 1); + + assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 졸은_후퇴할_수_없다() { + Position from = new Position(7, 2); + Position to = new Position(7, 1); + + assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + } + +} From 780e13228456e866c694c28c9342a3ae146a2aa5 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 21:56:21 +0900 Subject: [PATCH 40/58] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=84=A0=EC=96=B8=20=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/board/Board.java | 2 +- src/main/java/domain/piece/Piece.java | 2 +- src/main/java/domain/piece/PieceType.java | 1 - src/main/java/domain/piece/strategy/CannonMoveStrategy.java | 2 +- .../java/domain/piece/strategy/ChariotMoveStrategy.java | 2 +- .../java/domain/piece/strategy/GeneralMoveStrategy.java | 2 +- src/main/java/domain/piece/strategy/MoveStrategy.java | 2 +- .../java/domain/piece/strategy/SoldierMoveStrategy.java | 2 +- .../java/domain/piece/strategy/CannonMoveStrategyTest.java | 6 +++--- .../java/domain/piece/strategy/ChariotMoveStrategyTest.java | 2 +- 10 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index c1e0970666..a2e2bd1e6f 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -8,7 +8,7 @@ import java.util.Map; public class Board { - Map pieces; + private final Map pieces; public Board(Map pieces) { this.pieces = pieces; diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index deb2cada62..d8798ee386 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -35,7 +35,7 @@ public List getPath(Position departure, Position destination) { } public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { - moveStrategy.validateBlockingPiece(pathInfos, departure, destination); + moveStrategy.validateBlockingPiece(pathInfos, destination); } @Override diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 6f46b396e2..69ac4194bc 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -2,7 +2,6 @@ import domain.piece.strategy.*; -import java.util.List; import java.util.function.Function; public enum PieceType { diff --git a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java index 0e8aa1efab..d6fff288cb 100644 --- a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java @@ -24,7 +24,7 @@ public List getPath(Position departure, Position destination) { } @Override - public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + public void validateBlockingPiece(List pathInfos, Position destination) { if (pathInfos.stream().anyMatch(path -> path.isSamePieceType(PieceType.CANNON))) { throw new IllegalArgumentException("포는 포를 넘거나 잡을 수 없습니다."); } diff --git a/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java index 400bd3dc83..4e43e0f78b 100644 --- a/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java @@ -23,7 +23,7 @@ public List getPath(Position departure, Position destination) { } @Override - public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + public void validateBlockingPiece(List pathInfos, Position destination) { boolean hasBlockingPiece = pathInfos.stream() .filter(path -> !path.position().equals(destination)) .anyMatch(PathInfo::hasPiece); diff --git a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java index 42a23061bc..ac56affe9a 100644 --- a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java @@ -27,7 +27,7 @@ public List getPath(Position departure, Position destination) { } @Override - public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + public void validateBlockingPiece(List pathInfos, Position destination) { boolean hasBlockingPiece = pathInfos.stream() .filter(path -> !path.position().equals(destination)) .anyMatch(PathInfo::hasPiece); diff --git a/src/main/java/domain/piece/strategy/MoveStrategy.java b/src/main/java/domain/piece/strategy/MoveStrategy.java index 1181d4b546..b2979491ce 100644 --- a/src/main/java/domain/piece/strategy/MoveStrategy.java +++ b/src/main/java/domain/piece/strategy/MoveStrategy.java @@ -7,5 +7,5 @@ public interface MoveStrategy { List getPath(Position departure, Position destination); - void validateBlockingPiece(List pathInfos, Position departure, Position destination); + void validateBlockingPiece(List pathInfos, Position destination); } diff --git a/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java b/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java index 6773c595d2..5ee2e37178 100644 --- a/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java @@ -38,7 +38,7 @@ public List getPath(Position departure, Position destination) { } @Override - public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + public void validateBlockingPiece(List pathInfos, Position destination) { boolean hasBlockingPiece = pathInfos.stream() .filter(path -> !path.position().equals(destination)) .anyMatch(PathInfo::hasPiece); diff --git a/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java index d4e021eecc..43eaf34033 100644 --- a/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java @@ -52,7 +52,7 @@ class CannonMoveStrategyTest { List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); } @Test @@ -63,7 +63,7 @@ class CannonMoveStrategyTest { List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CANNON))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); } @Test @@ -75,6 +75,6 @@ class CannonMoveStrategyTest { pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CANNON))); pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java index b4e7856637..b3fa27d271 100644 --- a/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java @@ -52,6 +52,6 @@ class ChariotMoveStrategyTest { List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); } } From 877247c174daae5bfc318cee353b369f4e5aa7bb Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 22:42:17 +0900 Subject: [PATCH 41/58] =?UTF-8?q?feat(MoveStrategy):=20=EB=A7=88=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=A0=84=EB=9E=B5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/{piece => path}/Direction.java | 2 +- src/main/java/domain/path/PathGenerator.java | 13 ++++- src/main/java/domain/piece/Camp.java | 2 + .../piece/strategy/CannonMoveStrategy.java | 3 +- .../piece/strategy/ChariotMoveStrategy.java | 3 +- .../piece/strategy/GeneralMoveStrategy.java | 5 +- .../piece/strategy/HorseMoveStrategy.java | 54 +++++++++++++++++++ .../piece/strategy/SoldierMoveStrategy.java | 4 +- src/test/java/domain/piece/DirectionTest.java | 1 + .../strategy/CannonMoveStrategyTest.java | 23 ++++---- .../strategy/ChariotMoveStrategyTest.java | 15 ++++-- .../strategy/GeneralMoveStrategyTest.java | 6 ++- .../piece/strategy/HorseMoveStrategyTest.java | 34 ++++++++++++ .../strategy/SoldierMoveStrategyTest.java | 9 ++-- 14 files changed, 144 insertions(+), 30 deletions(-) rename src/main/java/domain/{piece => path}/Direction.java (98%) create mode 100644 src/main/java/domain/piece/strategy/HorseMoveStrategy.java create mode 100644 src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java diff --git a/src/main/java/domain/piece/Direction.java b/src/main/java/domain/path/Direction.java similarity index 98% rename from src/main/java/domain/piece/Direction.java rename to src/main/java/domain/path/Direction.java index 1cdd32e51e..66db303969 100644 --- a/src/main/java/domain/piece/Direction.java +++ b/src/main/java/domain/path/Direction.java @@ -1,4 +1,4 @@ -package domain.piece; +package domain.path; public enum Direction { UP(0, 1), diff --git a/src/main/java/domain/path/PathGenerator.java b/src/main/java/domain/path/PathGenerator.java index f422f9255d..683c754186 100644 --- a/src/main/java/domain/path/PathGenerator.java +++ b/src/main/java/domain/path/PathGenerator.java @@ -1,7 +1,6 @@ package domain.path; import domain.board.Position; -import domain.piece.Direction; import java.util.ArrayList; import java.util.List; @@ -18,4 +17,16 @@ public static List generateStraightPath(Position departure, Position d return paths; } + + public static List generateComplexPath(Position departure, Position destination, List directions) { + List paths = new ArrayList<>(); + + Position current = departure; + for (Direction direction : directions) { + current = current.move(direction.getDeltaX(), direction.getDeltaY()); + paths.add(current); + } + + return paths; + } } diff --git a/src/main/java/domain/piece/Camp.java b/src/main/java/domain/piece/Camp.java index 0204e2b17a..9ab20a9671 100644 --- a/src/main/java/domain/piece/Camp.java +++ b/src/main/java/domain/piece/Camp.java @@ -1,5 +1,7 @@ package domain.piece; +import domain.path.Direction; + public enum Camp { CHO(Direction.UP), HAN(Direction.DOWN); diff --git a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java index d6fff288cb..b163626190 100644 --- a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java @@ -3,7 +3,7 @@ import domain.board.Position; import domain.path.PathGenerator; import domain.path.PathInfo; -import domain.piece.Direction; +import domain.path.Direction; import domain.piece.PieceType; import java.util.List; @@ -19,7 +19,6 @@ public List getPath(Position departure, Position destination) { } Direction direction = Direction.decideDirection(deltaX, deltaY); - return PathGenerator.generateStraightPath(departure, destination, direction); } diff --git a/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java index 4e43e0f78b..3edddb544a 100644 --- a/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/ChariotMoveStrategy.java @@ -3,7 +3,7 @@ import domain.path.PathGenerator; import domain.path.PathInfo; import domain.board.Position; -import domain.piece.Direction; +import domain.path.Direction; import java.util.List; @@ -18,7 +18,6 @@ public List getPath(Position departure, Position destination) { } Direction direction = Direction.decideDirection(deltaX, deltaY); - return PathGenerator.generateStraightPath(departure, destination, direction); } diff --git a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java index ac56affe9a..1f4b167cca 100644 --- a/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/GeneralMoveStrategy.java @@ -3,7 +3,7 @@ import domain.board.Position; import domain.path.PathGenerator; import domain.path.PathInfo; -import domain.piece.Direction; +import domain.path.Direction; import java.util.List; @@ -17,12 +17,11 @@ public List getPath(Position departure, Position destination) { throw new IllegalArgumentException("궁/사는 직선 방향으로만 이동할 수 있습니다."); } - if (deltaX > 1 || deltaY > 1) { + if (Math.abs(deltaX) + Math.abs(deltaY) != 1) { throw new IllegalArgumentException("궁/사는 직선 방향으로 한 칸만 이동 가능합니다."); } Direction direction = Direction.decideDirection(deltaX, deltaY); - return PathGenerator.generateStraightPath(departure, destination, direction); } diff --git a/src/main/java/domain/piece/strategy/HorseMoveStrategy.java b/src/main/java/domain/piece/strategy/HorseMoveStrategy.java new file mode 100644 index 0000000000..24f2d46fc5 --- /dev/null +++ b/src/main/java/domain/piece/strategy/HorseMoveStrategy.java @@ -0,0 +1,54 @@ +package domain.piece.strategy; + +import domain.board.Position; +import domain.path.Direction; +import domain.path.PathGenerator; +import domain.path.PathInfo; + +import java.util.List; + +public class HorseMoveStrategy implements MoveStrategy { + @Override + public List getPath(Position departure, Position destination) { + int deltaX = departure.calculateDeltaX(destination); + int deltaY = departure.calculateDeltaY(destination); + + if (!isHorseMove(deltaX, deltaY)) { + throw new IllegalArgumentException("마는 직진 후, 대각선 방향으로 한 칸 이동 가능합니다."); + } + + Direction firstDirection = decidefirstDirection(deltaX, deltaY); + Position node = departure.move(firstDirection.getDeltaX(), firstDirection.getDeltaY()); + Direction secondDirection = Direction.decideDirection( + node.calculateDeltaX(destination), + node.calculateDeltaY(destination) + ); + + return PathGenerator.generateComplexPath(departure, destination, List.of(firstDirection, secondDirection)); + } + + @Override + public void validateBlockingPiece(List pathInfos, Position destination) { + boolean hasBlockingPiece = pathInfos.stream() + .filter(path -> !path.position().equals(destination)) + .anyMatch(PathInfo::hasPiece); + + if (hasBlockingPiece) { + throw new IllegalArgumentException("이동 경로에 있는 다른 기물을 뛰어넘을 수 없습니다."); + } + } + + private boolean isHorseMove(int deltaX, int deltaY) { + int absoluteX = Math.abs(deltaX); + int absoluteY = Math.abs(deltaY); + + return (absoluteX == 1 && absoluteY == 2) || (absoluteX == 2 && absoluteY == 1); + } + + private Direction decidefirstDirection(int deltaX, int deltaY){ + if((Math.abs(deltaX) == 2)){ + return Direction.decideDirection(deltaX, 0); + } + return Direction.decideDirection(0, deltaY); + } +} diff --git a/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java b/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java index 5ee2e37178..b50558bb76 100644 --- a/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/SoldierMoveStrategy.java @@ -3,7 +3,7 @@ import domain.board.Position; import domain.path.PathGenerator; import domain.path.PathInfo; -import domain.piece.Direction; +import domain.path.Direction; import java.util.List; @@ -23,7 +23,7 @@ public List getPath(Position departure, Position destination) { throw new IllegalArgumentException("졸/병은 직선 방향으로만 이동할 수 있습니다."); } - if (deltaX > 1 || deltaY > 1) { + if (Math.abs(deltaX) + Math.abs(deltaY) != 1) { throw new IllegalArgumentException("졸/병은 직선 방향으로 한 칸만 이동 가능합니다."); } diff --git a/src/test/java/domain/piece/DirectionTest.java b/src/test/java/domain/piece/DirectionTest.java index 0c1fcb210a..58cfc7615d 100644 --- a/src/test/java/domain/piece/DirectionTest.java +++ b/src/test/java/domain/piece/DirectionTest.java @@ -1,6 +1,7 @@ package domain.piece; import domain.board.Position; +import domain.path.Direction; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java index 43eaf34033..c74a6411c4 100644 --- a/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java @@ -23,7 +23,9 @@ class CannonMoveStrategyTest { List path = chariotMoveStrategy.getPath(from, to); - assertThat(path).containsExactly(new Position(8, 1), new Position(8, 2)); + assertThat(path).containsExactly( + new Position(8, 1), + new Position(8, 2)); } @Test @@ -33,7 +35,9 @@ class CannonMoveStrategyTest { List path = chariotMoveStrategy.getPath(from, to); - assertThat(path).containsExactly(new Position(7, 0), new Position(6, 0)); + assertThat(path).containsExactly( + new Position(7, 0), + new Position(6, 0)); } @Test @@ -41,40 +45,41 @@ class CannonMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(7, 1); - assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } @Test void 포는_경로에_다른_기물이_없으면_이동할_수_없다() { Position from = new Position(8, 0); - Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + .isInstanceOf(IllegalArgumentException.class); } @Test void 포는_포를_잡을_수_없다() { Position from = new Position(8, 0); - Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CANNON))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + .isInstanceOf(IllegalArgumentException.class); } @Test void 포는_포를_넘을_수_없다() { Position from = new Position(8, 0); - Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CANNON))); pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java index b3fa27d271..f4ffda2ffb 100644 --- a/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java @@ -23,7 +23,9 @@ class ChariotMoveStrategyTest { List path = chariotMoveStrategy.getPath(from, to); - assertThat(path).containsExactly(new Position(8, 1), new Position(8, 2)); + assertThat(path).containsExactly( + new Position(8, 1), + new Position(8, 2)); } @Test @@ -33,7 +35,9 @@ class ChariotMoveStrategyTest { List path = chariotMoveStrategy.getPath(from, to); - assertThat(path).containsExactly(new Position(7, 0), new Position(6, 0)); + assertThat(path).containsExactly( + new Position(7, 0), + new Position(6, 0)); } @Test @@ -41,17 +45,18 @@ class ChariotMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(7, 1); - assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } @Test void 차는_경로에_다른_기물이_있으면_이동할_수_없다() { Position from = new Position(8, 0); - Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java b/src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java index 0a588a6cad..96c7c606bc 100644 --- a/src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/GeneralMoveStrategyTest.java @@ -16,7 +16,8 @@ class GeneralMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(8, 2); - assertThatThrownBy(() -> generalMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> generalMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -44,6 +45,7 @@ class GeneralMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(7, 1); - assertThatThrownBy(() -> generalMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> generalMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java new file mode 100644 index 0000000000..0d88a0792c --- /dev/null +++ b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java @@ -0,0 +1,34 @@ +package domain.piece.strategy; + +import domain.board.Position; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class HorseMoveStrategyTest { + private final MoveStrategy horseMoveStrategy = new HorseMoveStrategy(); + + @Test + void 마는_직선으로만_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + assertThatThrownBy(() -> horseMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 마가_정상적으로_이동하면_멱과_목적지_경로를_반환한다() { + Position from = new Position(8, 0); + Position to = new Position(7, 2); + + List path = horseMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly( + new Position(8, 1), + new Position(7, 2)); + } +} diff --git a/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java b/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java index b6da7686fb..9969b661d6 100644 --- a/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java @@ -17,7 +17,8 @@ class SoldierMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(8, 2); - assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -45,7 +46,8 @@ class SoldierMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(7, 1); - assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } @Test @@ -53,7 +55,8 @@ class SoldierMoveStrategyTest { Position from = new Position(7, 2); Position to = new Position(7, 1); - assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)).isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); } } From a311337776b76f84dcdce2b29131bda95b6b2d38 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 22:42:17 +0900 Subject: [PATCH 42/58] =?UTF-8?q?feat(MoveStrategy):=20=EB=A7=88=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=A0=84=EB=9E=B5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java index 0d88a0792c..2f8df39aaf 100644 --- a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java @@ -21,7 +21,7 @@ class HorseMoveStrategyTest { } @Test - void 마가_정상적으로_이동하면_멱과_목적지_경로를_반환한다() { + void 마는_직선으로_한_칸_이동_후_대각선으로_한_칸_이동하는_경로를_가진다() { Position from = new Position(8, 0); Position to = new Position(7, 2); From 99610dc6ea549a5d768c31190920e76b253df883 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 22:58:31 +0900 Subject: [PATCH 43/58] =?UTF-8?q?feat(MoveStrategy):=20=EC=83=81=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=A0=84=EB=9E=B5=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/piece/PieceType.java | 4 +- .../piece/strategy/ElephantMoveStrategy.java | 54 +++++++++++++++++++ .../strategy/ElephantMoveStrategyTest.java | 35 ++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/main/java/domain/piece/strategy/ElephantMoveStrategy.java create mode 100644 src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java diff --git a/src/main/java/domain/piece/PieceType.java b/src/main/java/domain/piece/PieceType.java index 69ac4194bc..e865e494f4 100644 --- a/src/main/java/domain/piece/PieceType.java +++ b/src/main/java/domain/piece/PieceType.java @@ -9,8 +9,8 @@ public enum PieceType { GUARD(camp -> new GeneralMoveStrategy()), CHARIOT(camp -> new ChariotMoveStrategy()), CANNON(camp -> new CannonMoveStrategy()), - HORSE(camp -> new ChariotMoveStrategy()), - ELEPHANT(camp -> new ChariotMoveStrategy()), + HORSE(camp -> new HorseMoveStrategy()), + ELEPHANT(camp -> new ElephantMoveStrategy()), SOLDIER(camp -> new SoldierMoveStrategy(camp.getForwardDirection())); private final Function strategyFactory; diff --git a/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java b/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java new file mode 100644 index 0000000000..c8235dc63e --- /dev/null +++ b/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java @@ -0,0 +1,54 @@ +package domain.piece.strategy; + +import domain.board.Position; +import domain.path.Direction; +import domain.path.PathGenerator; +import domain.path.PathInfo; + +import java.util.List; + +public class ElephantMoveStrategy implements MoveStrategy { + @Override + public List getPath(Position departure, Position destination) { + int deltaX = departure.calculateDeltaX(destination); + int deltaY = departure.calculateDeltaY(destination); + + if (!isElephantMove(deltaX, deltaY)) { + throw new IllegalArgumentException("상은 직진 후, 대각선 방향으로 두 칸 이동 가능합니다."); + } + + Direction firstDirection = decidefirstDirection(deltaX, deltaY); + Position firstNode = departure.move(firstDirection.getDeltaX(), firstDirection.getDeltaY()); + Direction secondDirection = Direction.decideDirection( + firstNode.calculateDeltaX(destination), + firstNode.calculateDeltaY(destination) + ); + + return PathGenerator.generateComplexPath(departure, destination, List.of(firstDirection, secondDirection, secondDirection)); + } + + @Override + public void validateBlockingPiece(List pathInfos, Position destination) { + boolean hasBlockingPiece = pathInfos.stream() + .filter(path -> !path.position().equals(destination)) + .anyMatch(PathInfo::hasPiece); + + if (hasBlockingPiece) { + throw new IllegalArgumentException("이동 경로에 있는 다른 기물을 뛰어넘을 수 없습니다."); + } + } + + private boolean isElephantMove(int deltaX, int deltaY) { + int absoluteX = Math.abs(deltaX); + int absoluteY = Math.abs(deltaY); + + return (absoluteX == 2 && absoluteY == 3) || (absoluteX == 3 && absoluteY == 2); + } + + private Direction decidefirstDirection(int deltaX, int deltaY) { + if ((Math.abs(deltaX) == 3)) { + return Direction.decideDirection(deltaX, 0); + } + return Direction.decideDirection(0, deltaY); + } +} diff --git a/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java new file mode 100644 index 0000000000..6d4fc8fecd --- /dev/null +++ b/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java @@ -0,0 +1,35 @@ +package domain.piece.strategy; + +import domain.board.Position; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class ElephantMoveStrategyTest { + private final MoveStrategy elephantMoveStrategy = new ElephantMoveStrategy(); + + @Test + void 상은_직선으로만_이동할_수_없다() { + Position from = new Position(8, 0); + Position to = new Position(8, 2); + + assertThatThrownBy(() -> elephantMoveStrategy.getPath(from, to)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 상은_직선으로_한_칸_이동_후_대각선으로_두_칸_이동하는_경로를_가진다() { + Position from = new Position(8, 0); + Position to = new Position(6, 3); + + List path = elephantMoveStrategy.getPath(from, to); + + assertThat(path).containsExactly( + new Position(8, 1), + new Position(7, 2), + new Position(6, 3)); + } +} From aae6b4471395be3e0b468a22004d7cc4eb749260 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 22:58:31 +0900 Subject: [PATCH 44/58] =?UTF-8?q?feat(MoveStrategy):=20=EC=83=81=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=A0=84=EB=9E=B5=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/piece/strategy/CannonMoveStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java index b163626190..ecdf120a5f 100644 --- a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java @@ -24,7 +24,7 @@ public List getPath(Position departure, Position destination) { @Override public void validateBlockingPiece(List pathInfos, Position destination) { - if (pathInfos.stream().anyMatch(path -> path.isSamePieceType(PieceType.CANNON))) { + if (pathInfos.stream().anyMatch(pathInfo -> pathInfo.isSamePieceType(PieceType.CANNON))) { throw new IllegalArgumentException("포는 포를 넘거나 잡을 수 없습니다."); } } From 561cda77be92480cead21d2461e8314d8f85ca4b Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 23:19:56 +0900 Subject: [PATCH 45/58] =?UTF-8?q?test(PathInfo):=20PathInfo=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/path/PathInfo.java | 4 +-- .../piece/strategy/CannonMoveStrategy.java | 2 +- src/test/java/domain/path/PathInfoTest.java | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 src/test/java/domain/path/PathInfoTest.java diff --git a/src/main/java/domain/path/PathInfo.java b/src/main/java/domain/path/PathInfo.java index 526993bf84..8576449fed 100644 --- a/src/main/java/domain/path/PathInfo.java +++ b/src/main/java/domain/path/PathInfo.java @@ -9,7 +9,7 @@ public boolean hasPiece(){ return piece != null; } - public boolean isSamePieceType(PieceType pieceType){ - return piece.isSameType(pieceType); + public boolean isPieceType(PieceType type) { + return hasPiece() && piece.isSameType(type); } } diff --git a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java index ecdf120a5f..17da6ba689 100644 --- a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java @@ -24,7 +24,7 @@ public List getPath(Position departure, Position destination) { @Override public void validateBlockingPiece(List pathInfos, Position destination) { - if (pathInfos.stream().anyMatch(pathInfo -> pathInfo.isSamePieceType(PieceType.CANNON))) { + if (pathInfos.stream().anyMatch(pathInfo -> pathInfo.isPieceType(PieceType.CANNON))) { throw new IllegalArgumentException("포는 포를 넘거나 잡을 수 없습니다."); } } diff --git a/src/test/java/domain/path/PathInfoTest.java b/src/test/java/domain/path/PathInfoTest.java new file mode 100644 index 0000000000..7401fcfbcb --- /dev/null +++ b/src/test/java/domain/path/PathInfoTest.java @@ -0,0 +1,35 @@ +package domain.path; + +import domain.board.Position; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +class PathInfoTest { + + @Test + void 해당_위치에_기물이_있는지_반환한다() { + Piece chariot = Piece.of(Camp.CHO, PieceType.CHARIOT); + PathInfo withPiece = new PathInfo(new Position(0, 0), chariot); + assertThat(withPiece.hasPiece()).isTrue(); + + PathInfo empty = new PathInfo(new Position(0, 0), null); + assertThat(empty.hasPiece()).isFalse(); + } + + @Test + void 해당_위치에_존재하는_기물이_같은_종류의_기물인지_반환한다() { + Piece cannon = Piece.of(Camp.CHO, PieceType.CANNON); + PathInfo pathInfo = new PathInfo(new Position(0, 0), cannon); + + assertThat(pathInfo.isPieceType(PieceType.CANNON)).isTrue(); + assertThat(pathInfo.isPieceType(PieceType.CHARIOT)).isFalse(); + + PathInfo empty = new PathInfo(new Position(0, 0), null); + assertThat(empty.isPieceType(PieceType.CANNON)).isFalse(); + } +} From 3549d35db4664f9209928579f29c68a8a19e433d Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 23:22:15 +0900 Subject: [PATCH 46/58] =?UTF-8?q?test(Position):=20Position=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/board/PositionTest.java | 5 +++++ src/test/java/domain/path/PathInfoTest.java | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/domain/board/PositionTest.java b/src/test/java/domain/board/PositionTest.java index be19407837..2dd2171cb6 100644 --- a/src/test/java/domain/board/PositionTest.java +++ b/src/test/java/domain/board/PositionTest.java @@ -8,6 +8,11 @@ class PositionTest { + @Test + void 좌표를_이동시킨다() { + Position position = new Position(0, 0); + assertThat(position.move(1, 2)).isEqualTo(new Position(1, 2)); + } @Nested class 좌표_범위_검증_테스트 { diff --git a/src/test/java/domain/path/PathInfoTest.java b/src/test/java/domain/path/PathInfoTest.java index 7401fcfbcb..c144a3ab49 100644 --- a/src/test/java/domain/path/PathInfoTest.java +++ b/src/test/java/domain/path/PathInfoTest.java @@ -7,7 +7,6 @@ import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; class PathInfoTest { From 74fc93ade431036e20714fda4b93760788431f93 Mon Sep 17 00:00:00 2001 From: frombunny Date: Thu, 2 Apr 2026 23:32:39 +0900 Subject: [PATCH 47/58] =?UTF-8?q?test(Piece):=20Piece=20=EB=88=84=EB=9D=BD?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/piece/PieceTest.java | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/test/java/domain/piece/PieceTest.java diff --git a/src/test/java/domain/piece/PieceTest.java b/src/test/java/domain/piece/PieceTest.java new file mode 100644 index 0000000000..2361b2702b --- /dev/null +++ b/src/test/java/domain/piece/PieceTest.java @@ -0,0 +1,46 @@ +package domain.piece; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class PieceTest { + Piece piece; + + @BeforeEach + void setUp() { + piece = Piece.of(Camp.CHO, PieceType.CHARIOT); + } + + @Test + void 같은_진영인지_반환한다() { + assertThat(piece.isSameCamp(Piece.of(Camp.CHO, PieceType.ELEPHANT))).isTrue(); + assertThat(piece.isSameCamp(Piece.of(Camp.HAN, PieceType.SOLDIER))).isFalse(); + } + + @Nested + class 동등성_비교_테스트 { + @Test + void 같은_진영이고_같은_기물_타입이면_동등한_기물로_판단한다() { + assertThat(piece.equals(Piece.of(Camp.CHO, PieceType.CHARIOT))).isTrue(); + } + + @Test + void 진영이_다르면_다른_기물로_판단한다() { + assertThat(piece.equals(Piece.of(Camp.HAN, PieceType.CHARIOT))).isFalse(); + } + + @Test + void 기물_종류가_다르면_다른_기물로_판단한다() { + assertThat(piece.equals(Piece.of(Camp.CHO, PieceType.HORSE))).isFalse(); + } + + @Test + void 동등한_두_객체의_hashcode는_같다() { + assertThat(piece.equals(Piece.of(Camp.CHO, PieceType.CHARIOT))).isTrue(); + assertThat(piece.hashCode()).isEqualTo(Piece.of(Camp.CHO, PieceType.CHARIOT).hashCode()); + } + } +} From 43e9627abcb23a19f3fecea9e5d23fd61c3742bf Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 00:07:48 +0900 Subject: [PATCH 48/58] =?UTF-8?q?test(Board):=20Board=20=EB=88=84=EB=9D=BD?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/domain/board/BoardTest.java | 13 +++++++++++++ .../java/domain/{piece => path}/DirectionTest.java | 3 +-- 2 files changed, 14 insertions(+), 2 deletions(-) rename src/test/java/domain/{piece => path}/DirectionTest.java (98%) diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index 8aeec220d8..688b13a818 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -38,6 +38,19 @@ void setUp() { .isInstanceOf(IllegalArgumentException.class); } + @Test + void 출발지에서_도착지로_기물을_이동시킨다(){ + Position from = new Position(0, 0); + Position to = new Position(0, 3); + Piece movingPiece = board.pieceAt(from); + + board.move(from, to); + + assertThat(board.isExistPieceAt(from)).isFalse(); + assertThat(board.pieceAt(to)).isEqualTo(movingPiece); + + } + @Test void 도착지에_위치한_기물이_같은_진영의_기물일_경우_예외를_던진다() { assertThatThrownBy(() -> board.move(new Position(8, 0), new Position(7, 0))) diff --git a/src/test/java/domain/piece/DirectionTest.java b/src/test/java/domain/path/DirectionTest.java similarity index 98% rename from src/test/java/domain/piece/DirectionTest.java rename to src/test/java/domain/path/DirectionTest.java index 58cfc7615d..34d3ae3fd7 100644 --- a/src/test/java/domain/piece/DirectionTest.java +++ b/src/test/java/domain/path/DirectionTest.java @@ -1,7 +1,6 @@ -package domain.piece; +package domain.path; import domain.board.Position; -import domain.path.Direction; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 906399c52264431bbde88da0ee1800e03c5bb8db Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 00:10:45 +0900 Subject: [PATCH 49/58] =?UTF-8?q?test(PathGenerator):=20PathGenerator=20?= =?UTF-8?q?=EB=88=84=EB=9D=BD=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/domain/path/PathGeneratorTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/java/domain/path/PathGeneratorTest.java diff --git a/src/test/java/domain/path/PathGeneratorTest.java b/src/test/java/domain/path/PathGeneratorTest.java new file mode 100644 index 0000000000..9a20c7367a --- /dev/null +++ b/src/test/java/domain/path/PathGeneratorTest.java @@ -0,0 +1,38 @@ +package domain.path; + +import domain.board.Position; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class PathGeneratorTest { + @Test + void 직선_경로를_정상적으로_생성한다() { + Position departure = new Position(0, 0); + Position destination = new Position(0, 2); + Direction direction = Direction.UP; + + List path = PathGenerator.generateStraightPath(departure, destination, direction); + + assertThat(path).containsExactly( + new Position(0, 1), + new Position(0, 2) + ); + } + + @Test + void 복합_경로를_정상적으로_생성한다() { + Position departure = new Position(8, 0); + Position destination = new Position(7, 2); + List directions = List.of(Direction.UP, Direction.NORTHWEST); + + List path = PathGenerator.generateComplexPath(departure, destination, directions); + + assertThat(path).containsExactly( + new Position(8, 1), + new Position(7, 2) + ); + } +} From a17bc6baf4c76d3d8e0340b6b0b64bbbfc39e771 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 00:35:37 +0900 Subject: [PATCH 50/58] =?UTF-8?q?fix(Board):=20=EC=9E=A5=EA=B8=B0=ED=8C=90?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/domain/board/Board.java | 2 +- src/test/java/domain/board/BoardTest.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index a2e2bd1e6f..e63af34f52 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -31,7 +31,7 @@ public void move(Position departure, Position destination) { List path = new ArrayList<>(); for (Position position : departurePiece.getPath(departure, destination)) { - path.add(new PathInfo(position, pieceAt(position))); + path.add(new PathInfo(position, pieces.get(position))); } departurePiece.validateBlockingPiece(path, departure, destination); diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index 688b13a818..ad872826b6 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -39,16 +39,21 @@ void setUp() { } @Test - void 출발지에서_도착지로_기물을_이동시킨다(){ - Position from = new Position(0, 0); - Position to = new Position(0, 3); + void 출발지에서_도착지로_기물을_이동시킨다() { + Position from = new Position(8, 3); Piece movingPiece = board.pieceAt(from); - board.move(from, to); + Position first = new Position(8, 4); + board.move(from, first); + + Position second = new Position(8, 5); + board.move(first, second); + + Position to = new Position(8, 6); + board.move(second, to); assertThat(board.isExistPieceAt(from)).isFalse(); assertThat(board.pieceAt(to)).isEqualTo(movingPiece); - } @Test From 2a4b1e5f122d4d70df0e156471144e6930fc692d Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 01:16:00 +0900 Subject: [PATCH 51/58] =?UTF-8?q?feat(view):=20=EC=9E=85=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=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/Board.java | 5 ++- src/main/java/domain/piece/Piece.java | 10 ++++- src/main/java/view/InputView.java | 17 ++++++++ src/main/java/view/OutputView.java | 57 +++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 src/main/java/view/InputView.java create mode 100644 src/main/java/view/OutputView.java diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index e63af34f52..a54caa6856 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -27,6 +27,9 @@ public Piece pieceAt(Position position) { } public void move(Position departure, Position destination) { + if (departure.equals(destination)){ + throw new IllegalArgumentException("출발 위치와 도착 위치가 같습니다."); + } Piece departurePiece = pieceAt(departure); List path = new ArrayList<>(); @@ -34,7 +37,7 @@ public void move(Position departure, Position destination) { path.add(new PathInfo(position, pieces.get(position))); } - departurePiece.validateBlockingPiece(path, departure, destination); + departurePiece.validateBlockingPiece(path, destination); if (isExistPieceAt(destination)) { validateCapture(departurePiece, pieceAt(destination)); diff --git a/src/main/java/domain/piece/Piece.java b/src/main/java/domain/piece/Piece.java index d8798ee386..f26b4bff23 100644 --- a/src/main/java/domain/piece/Piece.java +++ b/src/main/java/domain/piece/Piece.java @@ -30,11 +30,19 @@ public boolean isSameType(PieceType otherPieceType) { return pieceType.equals(otherPieceType); } + public Camp getCamp() { + return camp; + } + + public PieceType getPieceType() { + return pieceType; + } + public List getPath(Position departure, Position destination) { return moveStrategy.getPath(departure, destination); } - public void validateBlockingPiece(List pathInfos, Position departure, Position destination) { + public void validateBlockingPiece(List pathInfos, Position destination) { moveStrategy.validateBlockingPiece(pathInfos, destination); } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java new file mode 100644 index 0000000000..a1f056abdf --- /dev/null +++ b/src/main/java/view/InputView.java @@ -0,0 +1,17 @@ +package view; + +import java.util.Scanner; + +public class InputView { + private static final Scanner scanner = new Scanner(System.in); + + public static String readDeparturePosition() { + System.out.println("이동시킬 기물이 위치한 좌표를 입력해주세요. (ex) 0,0"); + return scanner.nextLine(); + } + + public static String readDestinationPosition() { + System.out.println("이동할 좌표를 입력해주세요. (ex) 0,0"); + return scanner.nextLine(); + } +} diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java new file mode 100644 index 0000000000..c0cdda425e --- /dev/null +++ b/src/main/java/view/OutputView.java @@ -0,0 +1,57 @@ +package view; + +import domain.board.Board; +import domain.board.Position; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; + +public class OutputView { + private static final int MAX_ROW = 9; + private static final int MAX_COLUMN = 8; + private static final String ANSI_RESET = "\u001B[0m"; + private static final String ANSI_CHO = "\u001B[34m"; + private static final String ANSI_HAN = "\u001B[31m"; + private static final String ANSI_GUIDE = "\u001B[90m"; + + public static void printBoard(Board board) { + System.out.println(ANSI_GUIDE + " 0 1 2 3 4 5 6 7 8" + ANSI_RESET); + + for (int row = MAX_ROW; row >= 0; row--) { + System.out.print(ANSI_GUIDE + row + " |" + ANSI_RESET); + for (int col = 0; col <= MAX_COLUMN; col++) { + if (!board.isExistPieceAt(new Position(col, row))) { + System.out.print(ANSI_GUIDE + "+" + ANSI_RESET); + } else { + Piece piece = board.pieceAt(new Position(col, row)); + System.out.print(colorize(piece.getCamp(), symbolOf(piece.getPieceType(), piece.getCamp()))); + } + if (col < MAX_COLUMN) System.out.print(" "); + } + System.out.println(ANSI_GUIDE + "|" + ANSI_RESET); + } + } + + public static void printError(String message){ + System.out.println(message); + } + + private static String symbolOf(PieceType pieceType, Camp camp) { + return switch (pieceType) { + case GENERAL -> "궁"; + case GUARD -> "사"; + case CHARIOT -> "차"; + case CANNON -> "포"; + case HORSE -> "마"; + case ELEPHANT -> "상"; + case SOLDIER -> (camp == Camp.CHO) ? "졸" : "병"; + }; + } + + private static String colorize(Camp camp, String symbol) { + if (camp == Camp.CHO) { + return ANSI_CHO + symbol + ANSI_RESET; + } + return ANSI_HAN + symbol + ANSI_RESET; + } +} From 8a3671fce0e40f93389299b9b7c87537eedfb515 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 01:17:03 +0900 Subject: [PATCH 52/58] =?UTF-8?q?feat(Controller):=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=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/Application.java | 16 ++++++++ src/main/java/controller/GameController.java | 41 ++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/main/java/Application.java create mode 100644 src/main/java/controller/GameController.java diff --git a/src/main/java/Application.java b/src/main/java/Application.java new file mode 100644 index 0000000000..121afb6df5 --- /dev/null +++ b/src/main/java/Application.java @@ -0,0 +1,16 @@ +import controller.GameController; +import domain.board.Board; +import domain.board.BoardInitializer; +import domain.board.BoardSetting; + +public class Application { + public static void main(String[] args) { + Board board = new Board(BoardInitializer.init(BoardSetting.LEFT_ELEPHANT_SET_UP)); + GameController gameController = new GameController(); + + while (true) { + gameController.printBoard(board); + gameController.move(board); + } + } +} diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java new file mode 100644 index 0000000000..e6b40c7073 --- /dev/null +++ b/src/main/java/controller/GameController.java @@ -0,0 +1,41 @@ + +package controller; + +import domain.board.Board; +import domain.board.Position; +import view.InputView; +import view.OutputView; + +public class GameController { + public void move(Board board) { + while (true) { + try { + Position departure = parsePosition(InputView.readDeparturePosition()); + Position destination = parsePosition(InputView.readDestinationPosition()); + board.move(departure, destination); + return; + } catch (IllegalArgumentException exception) { + OutputView.printError(exception.getMessage()); + } + } + } + + public void printBoard(Board board) { + OutputView.printBoard(board); + } + + private Position parsePosition(String value) { + String[] tokens = value.split(","); + if (tokens.length != 2) { + throw new IllegalArgumentException("좌표는 x,y 형식으로 입력해야 합니다."); + } + + try { + int column = Integer.parseInt(tokens[0].trim()); + int row = Integer.parseInt(tokens[1].trim()); + return new Position(column, row); + } catch (NumberFormatException exception) { + throw new IllegalArgumentException("좌표는 숫자로 입력해야 합니다."); + } + } +} From 700e8ea4b0dccf943767051adf1ef0f8dff21278 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 01:38:27 +0900 Subject: [PATCH 53/58] =?UTF-8?q?feat(Game):=20=EC=8A=B9=ED=8C=A8=20?= =?UTF-8?q?=ED=8C=90=EC=A0=95=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/Application.java | 5 +- src/main/java/controller/GameController.java | 4 ++ src/main/java/domain/board/Board.java | 70 ++++++++++++++++---- src/main/java/view/OutputView.java | 5 ++ src/test/java/domain/board/BoardTest.java | 48 ++++++++++---- 5 files changed, 106 insertions(+), 26 deletions(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 121afb6df5..29d3276eab 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -8,9 +8,12 @@ public static void main(String[] args) { Board board = new Board(BoardInitializer.init(BoardSetting.LEFT_ELEPHANT_SET_UP)); GameController gameController = new GameController(); - while (true) { + while (!board.isGameOver()) { gameController.printBoard(board); gameController.move(board); } + + gameController.printBoard(board); + gameController.printWinner(board); } } diff --git a/src/main/java/controller/GameController.java b/src/main/java/controller/GameController.java index e6b40c7073..6adf0613b6 100644 --- a/src/main/java/controller/GameController.java +++ b/src/main/java/controller/GameController.java @@ -24,6 +24,10 @@ public void printBoard(Board board) { OutputView.printBoard(board); } + public void printWinner(Board board) { + OutputView.printWinner(board.winner()); + } + private Position parsePosition(String value) { String[] tokens = value.split(","); if (tokens.length != 2) { diff --git a/src/main/java/domain/board/Board.java b/src/main/java/domain/board/Board.java index a54caa6856..cbe367145f 100644 --- a/src/main/java/domain/board/Board.java +++ b/src/main/java/domain/board/Board.java @@ -1,14 +1,17 @@ package domain.board; import domain.path.PathInfo; +import domain.piece.Camp; import domain.piece.Piece; +import domain.piece.PieceType; -import java.util.ArrayList; import java.util.List; import java.util.Map; public class Board { private final Map pieces; + private boolean gameOver; + private Camp winner; public Board(Map pieces) { this.pieces = pieces; @@ -26,25 +29,50 @@ public Piece pieceAt(Position position) { return pieces.get(position); } - public void move(Position departure, Position destination) { - if (departure.equals(destination)){ - throw new IllegalArgumentException("출발 위치와 도착 위치가 같습니다."); - } - Piece departurePiece = pieceAt(departure); + public boolean isGameOver() { + return gameOver; + } - List path = new ArrayList<>(); - for (Position position : departurePiece.getPath(departure, destination)) { - path.add(new PathInfo(position, pieces.get(position))); + public Camp winner() { + if (!gameOver) { + throw new IllegalStateException("아직 게임이 종료되지 않았습니다."); } + return winner; + } + + public void move(Position departure, Position destination) { + validateGameStatus(); + validateDepartureAndDestinationPosition(departure, destination); + + Piece departurePiece = pieceAt(departure); + List path = getPath(departure, destination, departurePiece); + departurePiece.validateBlockingPiece(path, destination); if (isExistPieceAt(destination)) { - validateCapture(departurePiece, pieceAt(destination)); + handleCapture(pieceAt(departure), destination); } - pieces.remove(departure); - pieces.put(destination, departurePiece); + executeMove(departure, destination, departurePiece); + } + + private void validateGameStatus() { + if (gameOver) { + throw new IllegalStateException("이미 종료된 게임입니다."); + } + } + + private void handleCapture(Piece departurePiece, Position destination) { + Piece destinationPiece = pieceAt(destination); + validateCapture(departurePiece, destinationPiece); + updateGameOver(departurePiece, destinationPiece); + } + + private void validateDepartureAndDestinationPosition(Position departure, Position destination) { + if (departure.equals(destination)) { + throw new IllegalArgumentException("출발 위치와 도착 위치가 같습니다."); + } } private void validateCapture(Piece departurePiece, Piece destinationPiece) { @@ -52,4 +80,22 @@ private void validateCapture(Piece departurePiece, Piece destinationPiece) { throw new IllegalArgumentException("같은 진영의 기물은 잡을 수 없습니다."); } } + + private List getPath(Position departure, Position destination, Piece piece) { + return piece.getPath(departure, destination).stream() + .map(pos -> new PathInfo(pos, pieces.get(pos))) + .toList(); + } + + private void updateGameOver(Piece departurePiece, Piece destinationPiece) { + if (destinationPiece.isSameType(PieceType.GENERAL)) { + gameOver = true; + winner = departurePiece.getCamp(); + } + } + + private void executeMove(Position from, Position to, Piece piece) { + pieces.remove(from); + pieces.put(to, piece); + } } diff --git a/src/main/java/view/OutputView.java b/src/main/java/view/OutputView.java index c0cdda425e..f4fa2dbfbe 100644 --- a/src/main/java/view/OutputView.java +++ b/src/main/java/view/OutputView.java @@ -36,6 +36,11 @@ public static void printError(String message){ System.out.println(message); } + public static void printWinner(Camp winner) { + String winnerName = (winner == Camp.CHO) ? "초" : "한"; + System.out.println(winnerName + "의 승리입니다."); + } + private static String symbolOf(PieceType pieceType, Camp camp) { return switch (pieceType) { case GENERAL -> "궁"; diff --git a/src/test/java/domain/board/BoardTest.java b/src/test/java/domain/board/BoardTest.java index ad872826b6..986234412c 100644 --- a/src/test/java/domain/board/BoardTest.java +++ b/src/test/java/domain/board/BoardTest.java @@ -6,6 +6,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.HashMap; +import java.util.Map; + import static org.assertj.core.api.Assertions.*; class BoardTest { @@ -39,26 +42,45 @@ void setUp() { } @Test - void 출발지에서_도착지로_기물을_이동시킨다() { - Position from = new Position(8, 3); - Piece movingPiece = board.pieceAt(from); + void 도착지에_위치한_기물이_같은_진영의_기물일_경우_예외를_던진다() { + assertThatThrownBy(() -> board.move(new Position(8, 0), new Position(7, 0))) + .isInstanceOf(IllegalArgumentException.class); + } - Position first = new Position(8, 4); - board.move(from, first); + @Test + void 왕이_잡히면_게임이_종료되고_승자를_반환한다() { + Map pieces = new HashMap<>(); + pieces.put(new Position(4, 8), Piece.of(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(4, 9), Piece.of(Camp.HAN, PieceType.GENERAL)); + Board emptyBoard = new Board(pieces); - Position second = new Position(8, 5); - board.move(first, second); + emptyBoard.move(new Position(4, 8), new Position(4, 9)); - Position to = new Position(8, 6); - board.move(second, to); + assertThat(emptyBoard.isGameOver()).isTrue(); + assertThat(emptyBoard.winner()).isEqualTo(Camp.CHO); + } - assertThat(board.isExistPieceAt(from)).isFalse(); - assertThat(board.pieceAt(to)).isEqualTo(movingPiece); + @Test + void 게임이_종료되면_더_이상_기물을_이동할_수_없다() { + Map pieces = new HashMap<>(); + pieces.put(new Position(4, 8), Piece.of(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(4, 9), Piece.of(Camp.HAN, PieceType.GENERAL)); + Board emptyBoard = new Board(pieces); + + emptyBoard.move(new Position(4, 8), new Position(4, 9)); + + assertThatThrownBy(() -> emptyBoard.move(new Position(4, 9), new Position(4, 8))) + .isInstanceOf(IllegalStateException.class); } @Test - void 도착지에_위치한_기물이_같은_진영의_기물일_경우_예외를_던진다() { - assertThatThrownBy(() -> board.move(new Position(8, 0), new Position(7, 0))) + void 같은_진영의_기물은_잡을_수_없다() { + Map pieces = new HashMap<>(); + pieces.put(new Position(4, 0), Piece.of(Camp.CHO, PieceType.CHARIOT)); + pieces.put(new Position(4, 1), Piece.of(Camp.CHO, PieceType.SOLDIER)); + Board board = new Board(pieces); + + assertThatThrownBy(() -> board.move(new Position(4, 0), new Position(4, 1))) .isInstanceOf(IllegalArgumentException.class); } } From 4a6f08fbe018f423b2f7d94427a35db156d32400 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 01:40:57 +0900 Subject: [PATCH 54/58] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=84=A0=EC=96=B8=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- src/main/java/domain/path/PathGenerator.java | 2 +- src/main/java/domain/piece/strategy/ElephantMoveStrategy.java | 2 +- src/main/java/domain/piece/strategy/HorseMoveStrategy.java | 2 +- src/test/java/domain/path/PathGeneratorTest.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b73fab2c24..1c943873bf 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ - [x] `포`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 가능하지만, 반드시 기물을 한 개 뛰어넘어야만 그 방향으로 이동이 가능하다. - [x] 단, 포끼리는 서로 뛰어넘을 수 없다. - [x] 단, 포끼리는 서로 잡을 수 없다. -- [ ] `마`는 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 한 칸 더 이동한다. +- [x] `마`는 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 한 칸 더 이동한다. - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. -- [ ] `상`은 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 두 칸 더 이동한다. +- [x] `상`은 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 두 칸 더 이동한다. - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. - [x] `졸, 병`은 왼쪽, 오른쪽, 앞쪽으로 1칸씩 움직일 수 있으나, 후퇴할 수 없다. diff --git a/src/main/java/domain/path/PathGenerator.java b/src/main/java/domain/path/PathGenerator.java index 683c754186..1dbdaa35ec 100644 --- a/src/main/java/domain/path/PathGenerator.java +++ b/src/main/java/domain/path/PathGenerator.java @@ -18,7 +18,7 @@ public static List generateStraightPath(Position departure, Position d return paths; } - public static List generateComplexPath(Position departure, Position destination, List directions) { + public static List generateComplexPath(Position departure, List directions) { List paths = new ArrayList<>(); Position current = departure; diff --git a/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java b/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java index c8235dc63e..c03c72a3f6 100644 --- a/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/ElephantMoveStrategy.java @@ -24,7 +24,7 @@ public List getPath(Position departure, Position destination) { firstNode.calculateDeltaY(destination) ); - return PathGenerator.generateComplexPath(departure, destination, List.of(firstDirection, secondDirection, secondDirection)); + return PathGenerator.generateComplexPath(departure, List.of(firstDirection, secondDirection, secondDirection)); } @Override diff --git a/src/main/java/domain/piece/strategy/HorseMoveStrategy.java b/src/main/java/domain/piece/strategy/HorseMoveStrategy.java index 24f2d46fc5..5ec94fb78e 100644 --- a/src/main/java/domain/piece/strategy/HorseMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/HorseMoveStrategy.java @@ -24,7 +24,7 @@ public List getPath(Position departure, Position destination) { node.calculateDeltaY(destination) ); - return PathGenerator.generateComplexPath(departure, destination, List.of(firstDirection, secondDirection)); + return PathGenerator.generateComplexPath(departure, List.of(firstDirection, secondDirection)); } @Override diff --git a/src/test/java/domain/path/PathGeneratorTest.java b/src/test/java/domain/path/PathGeneratorTest.java index 9a20c7367a..0278b833a3 100644 --- a/src/test/java/domain/path/PathGeneratorTest.java +++ b/src/test/java/domain/path/PathGeneratorTest.java @@ -28,7 +28,7 @@ class PathGeneratorTest { Position destination = new Position(7, 2); List directions = List.of(Direction.UP, Direction.NORTHWEST); - List path = PathGenerator.generateComplexPath(departure, destination, directions); + List path = PathGenerator.generateComplexPath(departure, directions); assertThat(path).containsExactly( new Position(8, 1), From 809c2ae46564f9f35f65d23a4b8608c34582dd9a Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 01:45:27 +0900 Subject: [PATCH 55/58] =?UTF-8?q?view:=20=EC=83=81=EC=B0=A8=EB=A6=BC=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=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/Application.java | 4 ++-- src/main/java/domain/board/BoardSetting.java | 10 ++++++++++ src/main/java/view/InputView.java | 8 ++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/Application.java b/src/main/java/Application.java index 29d3276eab..58bd0ba21e 100644 --- a/src/main/java/Application.java +++ b/src/main/java/Application.java @@ -1,11 +1,11 @@ import controller.GameController; import domain.board.Board; import domain.board.BoardInitializer; -import domain.board.BoardSetting; +import view.InputView; public class Application { public static void main(String[] args) { - Board board = new Board(BoardInitializer.init(BoardSetting.LEFT_ELEPHANT_SET_UP)); + Board board = new Board(BoardInitializer.init(InputView.readBoardSetting())); GameController gameController = new GameController(); while (!board.isGameOver()) { diff --git a/src/main/java/domain/board/BoardSetting.java b/src/main/java/domain/board/BoardSetting.java index 27e8fb40e3..4e86793556 100644 --- a/src/main/java/domain/board/BoardSetting.java +++ b/src/main/java/domain/board/BoardSetting.java @@ -22,4 +22,14 @@ public enum BoardSetting { public List piecesArrangement() { return piecesArrangement; } + + public static BoardSetting from(String value) { + return switch (value.trim()) { + case "1", "왼상차림" -> LEFT_ELEPHANT_SET_UP; + case "2", "오른상차림" -> RIGHT_ELEPHANT_SET_UP; + case "3", "바깥상차림" -> OUTER_ELEPHANT_SET_UP; + case "4", "안상차림" -> INNER_ELEPHANT_SET_UP; + default -> throw new IllegalArgumentException("상차림은 1~4 또는 이름으로 입력해야 합니다."); + }; + } } diff --git a/src/main/java/view/InputView.java b/src/main/java/view/InputView.java index a1f056abdf..dade14db10 100644 --- a/src/main/java/view/InputView.java +++ b/src/main/java/view/InputView.java @@ -1,10 +1,18 @@ package view; +import domain.board.BoardSetting; + import java.util.Scanner; public class InputView { private static final Scanner scanner = new Scanner(System.in); + public static BoardSetting readBoardSetting() { + System.out.println("장기판 상차림을 선택해주세요."); + System.out.println("1. 왼상차림 2. 오른상차림 3. 바깥상차림 4. 안상차림"); + return BoardSetting.from(scanner.nextLine()); + } + public static String readDeparturePosition() { System.out.println("이동시킬 기물이 위치한 좌표를 입력해주세요. (ex) 0,0"); return scanner.nextLine(); From 033710a90c6e130d47ef0c41057694b54bf86690 Mon Sep 17 00:00:00 2001 From: frombunny Date: Fri, 3 Apr 2026 16:18:26 +0900 Subject: [PATCH 56/58] =?UTF-8?q?test(MoveStrategy):=20=EB=A7=88,=EC=83=81?= =?UTF-8?q?=20=EA=B8=B0=EB=AC=BC=20=EC=9D=B4=EB=8F=99=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- .../piece/strategy/ElephantMoveStrategyTest.java | 16 ++++++++++++++++ .../piece/strategy/HorseMoveStrategyTest.java | 16 ++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c943873bf..1bc9624d53 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ - [x] 단, 포끼리는 서로 뛰어넘을 수 없다. - [x] 단, 포끼리는 서로 잡을 수 없다. - [x] `마`는 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 한 칸 더 이동한다. - - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. + - [x] 경로에 다른 기물이 있을 경우, 이동할 수 없다. - [x] `상`은 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 두 칸 더 이동한다. - - [ ] 경로에 다른 기물이 있을 경우, 이동할 수 없다. + - [x] 경로에 다른 기물이 있을 경우, 이동할 수 없다. - [x] `졸, 병`은 왼쪽, 오른쪽, 앞쪽으로 1칸씩 움직일 수 있으나, 후퇴할 수 없다. diff --git a/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java index 6d4fc8fecd..d46ef98075 100644 --- a/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java @@ -1,8 +1,13 @@ package domain.piece.strategy; import domain.board.Position; +import domain.path.PathInfo; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -32,4 +37,15 @@ class ElephantMoveStrategyTest { new Position(7, 2), new Position(6, 3)); } + + @Test + void 상은_경로에_다른_기물이_있으면_이동할_수_없다() { + Position from = new Position(8, 0); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); + + assertThatThrownBy(() -> elephantMoveStrategy.validateBlockingPiece(pathInfos, from)) + .isInstanceOf(IllegalArgumentException.class); + } } diff --git a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java index 2f8df39aaf..344abbc761 100644 --- a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java @@ -1,8 +1,13 @@ package domain.piece.strategy; import domain.board.Position; +import domain.path.PathInfo; +import domain.piece.Camp; +import domain.piece.Piece; +import domain.piece.PieceType; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -31,4 +36,15 @@ class HorseMoveStrategyTest { new Position(8, 1), new Position(7, 2)); } + + @Test + void 마는_경로에_다른_기물이_있으면_이동할_수_없다() { + Position from = new Position(8, 0); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); + + assertThatThrownBy(() -> horseMoveStrategy.validateBlockingPiece(pathInfos, from)) + .isInstanceOf(IllegalArgumentException.class); + } } From 9701db2870d9ef850d8e489f4b1f01ddca7817cf Mon Sep 17 00:00:00 2001 From: frombunny Date: Sat, 4 Apr 2026 01:33:04 +0900 Subject: [PATCH 57/58] =?UTF-8?q?fix(MoveStrategy):=20=ED=8F=AC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=8B=9C=20=EA=B2=BD=EB=A1=9C=EC=97=90=20?= =?UTF-8?q?=EA=B8=B0=EB=AC=BC=EC=9D=B4=20=EC=97=AC=EB=9F=AC=EA=B0=9C=20?= =?UTF-8?q?=EC=9E=88=EC=9C=BC=EB=A9=B4=20=EC=9D=B4=EB=8F=99=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=97=86=EB=8F=84=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/piece/strategy/CannonMoveStrategy.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java index 17da6ba689..67fa53181f 100644 --- a/src/main/java/domain/piece/strategy/CannonMoveStrategy.java +++ b/src/main/java/domain/piece/strategy/CannonMoveStrategy.java @@ -24,6 +24,9 @@ public List getPath(Position departure, Position destination) { @Override public void validateBlockingPiece(List pathInfos, Position destination) { + if (pathInfos.size() != 2) { + throw new IllegalArgumentException("포는 반드시 하나의 기물만을 이동할 수 있습니다."); + } if (pathInfos.stream().anyMatch(pathInfo -> pathInfo.isPieceType(PieceType.CANNON))) { throw new IllegalArgumentException("포는 포를 넘거나 잡을 수 없습니다."); } From 4e68aac7bbf4bee49b4d33d76ed43491b1083791 Mon Sep 17 00:00:00 2001 From: frombunny Date: Sat, 4 Apr 2026 01:34:19 +0900 Subject: [PATCH 58/58] =?UTF-8?q?test(MoveStrategy):=20=ED=8F=AC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EA=B2=BD=EB=A1=9C=EC=97=90=20=EA=B8=B0?= =?UTF-8?q?=EB=AC=BC=EC=9D=B4=20=EC=97=AC=EB=9F=AC=EA=B0=9C=20=EC=9E=88?= =?UTF-8?q?=EC=9D=84=20=EA=B2=BD=EC=9A=B0=EC=9D=98=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + .../strategy/CannonMoveStrategyTest.java | 39 ++++++++++++------- .../strategy/ChariotMoveStrategyTest.java | 5 ++- .../strategy/ElephantMoveStrategyTest.java | 7 ++-- .../piece/strategy/HorseMoveStrategyTest.java | 7 ++-- .../strategy/SoldierMoveStrategyTest.java | 1 - 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 1bc9624d53..073cb8b127 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ - [x] 단, 다른 기물을 뛰어넘을 수는 없다. - [x] 가로막는 기물이 있는 지점의 바로 앞까지, 혹은 가로막는 기물이 적의 것일 경우 잡아내고 그 기물이 있던 곳까지 이동할 수 있다. - [x] `포`는 장기판 위의 곧은 선을 따라 한 방향으로 원하는 만큼 이동 가능하지만, 반드시 기물을 한 개 뛰어넘어야만 그 방향으로 이동이 가능하다. + - [x] 단, 경로에 두 개 이상의 기물이 존재하면 이동할 수 없다. - [x] 단, 포끼리는 서로 뛰어넘을 수 없다. - [x] 단, 포끼리는 서로 잡을 수 없다. - [x] `마`는 수직 또는 수평 방향으로 한 칸 갔다가 45도를 꺾어서 대각선으로 한 칸 더 이동한다. diff --git a/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java index c74a6411c4..cd0cfecfac 100644 --- a/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/CannonMoveStrategyTest.java @@ -14,14 +14,14 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; class CannonMoveStrategyTest { - private final MoveStrategy chariotMoveStrategy = new ChariotMoveStrategy(); + private final MoveStrategy cannonMoveStrategy = new CannonMoveStrategy(); @Test void 포는_세로_직선_방향의_이동_경로를_가진다() { Position from = new Position(8, 0); Position to = new Position(8, 2); - List path = chariotMoveStrategy.getPath(from, to); + List path = cannonMoveStrategy.getPath(from, to); assertThat(path).containsExactly( new Position(8, 1), @@ -33,7 +33,7 @@ class CannonMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(6, 0); - List path = chariotMoveStrategy.getPath(from, to); + List path = cannonMoveStrategy.getPath(from, to); assertThat(path).containsExactly( new Position(7, 0), @@ -45,41 +45,54 @@ class CannonMoveStrategyTest { Position from = new Position(8, 0); Position to = new Position(7, 1); - assertThatThrownBy(() -> chariotMoveStrategy.getPath(from, to)) + assertThatThrownBy(() -> cannonMoveStrategy.getPath(from, to)) .isInstanceOf(IllegalArgumentException.class); } @Test void 포는_경로에_다른_기물이_없으면_이동할_수_없다() { - Position from = new Position(8, 0); + Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); - pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(to, Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + assertThatThrownBy(() -> cannonMoveStrategy.validateBlockingPiece(pathInfos, to)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 포는_경로에_여러_개의_기물이_존재하면_이동할_수_없다() { + Position to = new Position(8, 4); + + List pathInfos = new ArrayList<>(); + pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.SOLDIER))); + pathInfos.add(new PathInfo(new Position(8, 3), Piece.of(Camp.CHO, PieceType.HORSE))); + pathInfos.add(new PathInfo(to, Piece.of(Camp.CHO, PieceType.CHARIOT))); + + assertThatThrownBy(() -> cannonMoveStrategy.validateBlockingPiece(pathInfos, to)) .isInstanceOf(IllegalArgumentException.class); } @Test void 포는_포를_잡을_수_없다() { - Position from = new Position(8, 0); + Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); - pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CANNON))); + pathInfos.add(new PathInfo(to, Piece.of(Camp.CHO, PieceType.CANNON))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + assertThatThrownBy(() -> cannonMoveStrategy.validateBlockingPiece(pathInfos, to)) .isInstanceOf(IllegalArgumentException.class); } @Test void 포는_포를_넘을_수_없다() { - Position from = new Position(8, 0); + Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CANNON))); - pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(to, Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + assertThatThrownBy(() -> cannonMoveStrategy.validateBlockingPiece(pathInfos, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java index f4ffda2ffb..58e9f10dd9 100644 --- a/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/ChariotMoveStrategyTest.java @@ -51,12 +51,13 @@ class ChariotMoveStrategyTest { @Test void 차는_경로에_다른_기물이_있으면_이동할_수_없다() { - Position from = new Position(8, 0); + Position to = new Position(8, 2); List pathInfos = new ArrayList<>(); pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(new Position(8, 2), Piece.of(Camp.CHO, PieceType.HORSE))); - assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, from)) + assertThatThrownBy(() -> chariotMoveStrategy.validateBlockingPiece(pathInfos, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java b/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java index d46ef98075..455e48adde 100644 --- a/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/ElephantMoveStrategyTest.java @@ -40,12 +40,13 @@ class ElephantMoveStrategyTest { @Test void 상은_경로에_다른_기물이_있으면_이동할_수_없다() { - Position from = new Position(8, 0); + Position to = new Position(8, 1); List pathInfos = new ArrayList<>(); - pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(new Position(8, 0), Piece.of(Camp.CHO, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(to, Piece.of(Camp.HAN, PieceType.CHARIOT))); - assertThatThrownBy(() -> elephantMoveStrategy.validateBlockingPiece(pathInfos, from)) + assertThatThrownBy(() -> elephantMoveStrategy.validateBlockingPiece(pathInfos, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java index 344abbc761..451f6e0cdc 100644 --- a/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/HorseMoveStrategyTest.java @@ -39,12 +39,13 @@ class HorseMoveStrategyTest { @Test void 마는_경로에_다른_기물이_있으면_이동할_수_없다() { - Position from = new Position(8, 0); + Position to = new Position(8, 1); List pathInfos = new ArrayList<>(); - pathInfos.add(new PathInfo(new Position(8, 1), Piece.of(Camp.CHO, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(new Position(8, 0), Piece.of(Camp.HAN, PieceType.CHARIOT))); + pathInfos.add(new PathInfo(to, Piece.of(Camp.CHO, PieceType.CHARIOT))); - assertThatThrownBy(() -> horseMoveStrategy.validateBlockingPiece(pathInfos, from)) + assertThatThrownBy(() -> horseMoveStrategy.validateBlockingPiece(pathInfos, to)) .isInstanceOf(IllegalArgumentException.class); } } diff --git a/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java b/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java index 9969b661d6..5f955b9d23 100644 --- a/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java +++ b/src/test/java/domain/piece/strategy/SoldierMoveStrategyTest.java @@ -58,5 +58,4 @@ class SoldierMoveStrategyTest { assertThatThrownBy(() -> soldierMoveStrategy.getPath(from, to)) .isInstanceOf(IllegalArgumentException.class); } - }